splitted SWF.c into various modules
[swftools.git] / lib / python / SWF.c
1 /* SWF.c
2
3    Python wrapper for librfxswf- module core.
4
5    Part of the swftools package.
6
7    Copyright (c) 2003 Matthias Kramm <kramm@quiss.org>
8  
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
22
23 #include <Python.h>
24 #undef HAVE_STAT
25 #include "../rfxswf.h"
26 #include "../log.h"
27 #include "./pyutils.h"
28 #include "./tag.h"
29 #include "./taglist.h"
30
31 /*
32 TODO:
33     1) taglist is rfxswflib's linked list. It should maybe implemented as Python
34        list, which would, however, mean that we would have to convert the list
35        back and forth for the following functions:
36         load, save, writeCGI, unfoldAll, foldAll, optimizeOrder
37     2) taglist should have an ID handler. Every time a tag is inserted, it's ID
38        is stored in a lookup list.
39     3) 
40 */
41
42 //-------------------------- Types -------------------------------------------
43
44 staticforward PyTypeObject SWFClass;
45
46 /* Tags, Objects */
47
48 typedef struct {
49     PyObject_HEAD
50     SWF swf; //swf.firstTag ist not used
51     PyObject*taglist;
52     char*filename;
53 } SWFObject;
54
55
56 //----------------------------------------------------------------------------
57 static PyObject* f_create(PyObject* self, PyObject* args, PyObject* kwargs)
58 {
59     static char *kwlist[] = {"version", "fps", "bbox", "name", NULL};
60     SWFObject* swf;
61     int version = 6;
62     double framerate = 25;
63     PyObject * obbox = 0;
64     SRECT bbox = {0,0,0,0};
65     char* filename = 0;
66
67     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|idOs", 
68                 kwlist, &version, &framerate, 
69                 &obbox, filename))
70         return NULL;
71
72     if (!PyArg_Parse(obbox, "(iiii)", &bbox.xmin, &bbox.ymin, &bbox.xmax, &bbox.ymax))
73         return NULL;
74
75     swf = PyObject_New(SWFObject, &SWFClass);
76     memset(&swf->swf, 0, sizeof(SWF));
77     if(filename)
78         swf->filename = strdup(filename);
79     else
80         swf->filename = 0;
81
82     swf->swf.fileVersion = version;
83     swf->swf.frameRate = (int)(framerate*0x100);
84     swf->swf.movieSize = bbox;
85     swf->taglist = taglist_new();
86
87     if(swf->swf.fileVersion>=6)
88         swf->swf.compressed = 1;
89
90     mylog("create %08x -> %08x\n", (int)self, (int)swf);
91     return (PyObject*)swf;
92 }
93 //----------------------------------------------------------------------------
94 static PyObject* f_load(PyObject* self, PyObject* args)
95 {
96     char* filename;
97     SWFObject* swf;
98     int fi;
99
100     if (!PyArg_ParseTuple(args,"s:load", &filename)) 
101         return NULL;
102
103     swf = PyObject_New(SWFObject, &SWFClass);
104     memset(&swf->swf, 0, sizeof(SWF));
105     swf->filename = strdup(filename);
106
107     if(!filename) {
108         PyErr_SetString(PyExc_Exception, setError("Couldn't open file %s", filename));
109         return 0;
110     }
111     fi = open(filename,O_RDONLY|O_BINARY);
112     if (fi<0) { 
113         PyErr_SetString(PyExc_Exception, setError("Couldn't open file %s", filename));
114         return 0;
115     }
116     if(swf_ReadSWF(fi,&swf->swf)<0) { 
117         close(fi);
118         PyErr_SetString(PyExc_Exception, setError("%s is not a valid SWF file or contains errors",filename));
119         return 0;
120     }
121     close(fi);
122     swf->swf.firstTag = 0;
123
124     swf->taglist = taglist_new2(swf->swf.firstTag);
125     
126     mylog("load %08x -> %08x\n", (int)self, (int)swf);
127     return (PyObject*)swf;
128 }
129 //----------------------------------------------------------------------------
130 static PyObject * swf_save(PyObject* self, PyObject* args, PyObject* kwargs)
131 {
132     static char *kwlist[] = {"name", "compress", NULL};
133     SWFObject*swfo;
134     SWF*swf;
135     int fi;
136     char*filename = 0;
137     int compress = 0;
138
139     if(!self)
140         return NULL;
141
142     swfo = (SWFObject*)self;
143     swf = &swfo->swf;
144     
145     filename = swfo->filename;
146
147     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|si", kwlist, &filename, &compress))
148         return NULL;
149
150     // keyword arg compress (=1) forces compression
151     if(compress)
152         swf->compressed = 1;
153     
154     swf->firstTag = taglist_getTAGs(swfo->taglist);
155
156     // fix the file, in case it is empty or not terminated properly
157     {
158         TAG*tag = swf->firstTag;
159         if(!tag)
160             tag = swf->firstTag = swf_InsertTag(0,ST_END);
161         while(tag && tag->next)
162             tag = tag->next;
163         if(tag->id != ST_END) {
164             tag = swf_InsertTag(tag,ST_END);
165         }
166     }
167
168     fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
169     if(fi<0) {
170         PyErr_SetString(PyExc_Exception, setError("couldn't create output file %s", filename));
171         return 0;
172     }
173     if(swf->compressed) {
174             if(swf_WriteSWC(fi, swf)<0) {
175                 close(fi);
176                 PyErr_SetString(PyExc_Exception, setError("WriteSWC() failed."));
177                 return 0;
178             }
179     } else {
180             if(swf_WriteSWF(fi, swf)<0) {
181                 close(fi);
182                 PyErr_SetString(PyExc_Exception, setError("WriteSWC() failed."));
183                 return 0;
184             }
185     }
186     close(fi);
187     
188     swf->firstTag = 0;
189     
190     return PY_NONE;
191 }
192 //----------------------------------------------------------------------------
193 static PyObject * swf_writeCGI(PyObject* self, PyObject* args)
194 {
195     SWFObject*swf = (SWFObject*)self;
196     if(!self || !PyArg_ParseTuple(args,"")) 
197         return NULL;
198     swf->swf.firstTag = taglist_getTAGs(swf->taglist);
199     swf_WriteCGI(&swf->swf);
200     swf->swf.firstTag = 0;
201     return PY_NONE;
202 }
203 //----------------------------------------------------------------------------
204
205 //TODO: void swf_Relocate(SWF*swf, char*bitmap); // bitmap is 65536 bytes, bitmap[a]==0 means id a is free
206
207 static PyMethodDef swf_functions[] =
208 {{"save", (PyCFunction)swf_save, METH_KEYWORDS, "Save SWF to disk"},
209  {"writeCGI", (PyCFunction)swf_writeCGI, METH_VARARGS, "print SWF as CGI to stdout"},
210  {NULL, NULL, 0, NULL}
211 };
212  
213 //----------------------------------------------------------------------------
214 static void swf_dealloc(PyObject* self)
215 {
216     SWFObject*swfo;
217     SWF*swf;
218     swfo = (SWFObject*)self;
219     swf = &swfo->swf;
220     mylog("swf_dealloc %08x(%d)\n", (int)self, self->ob_refcnt);
221     if(swfo->filename) {
222         free(swfo->filename);
223         swfo->filename = 0;
224     }
225     Py_DECREF(swfo->taglist);
226     swfo->taglist = 0;
227     PyObject_Del(self);
228 }
229 //----------------------------------------------------------------------------
230 static int swf_print(PyObject * self, FILE *fi, int flags) //flags&Py_PRINT_RAW
231 {
232     SWFObject*swf = (SWFObject*)self;
233     swf_DumpHeader(fi, &swf->swf);
234     //void swf_DumpSWF(FILE * f,SWF*swf);
235     mylog("print %08x(%d)\n", (int)self, self->ob_refcnt);
236     return 0;
237 }
238 //----------------------------------------------------------------------------
239 static PyObject* swf_getattr(PyObject * self, char* a)
240 {
241     SWFObject*swf = (SWFObject*)self;
242     PyObject* ret;
243
244     if(!strcmp(a, "fps")) {
245         double fps = swf->swf.frameRate/256.0;
246         mylog("swf_getattr %08x(%d) %s = %f\n", (int)self, self->ob_refcnt, a, fps);
247         return Py_BuildValue("d", fps);
248     } else if(!strcmp(a, "version")) {
249         int version = swf->swf.fileVersion;;
250         mylog("swf_getattr %08x(%d) %s = %d\n", (int)self, self->ob_refcnt, a, version);
251         return Py_BuildValue("i", version);
252     } else if(!strcmp(a, "name")) {
253         char*filename = swf->filename;
254         mylog("swf_getattr %08x(%d) %s = %s\n", (int)self, self->ob_refcnt, a, filename);
255         return Py_BuildValue("s", filename);
256     } else if(!strcmp(a, "bbox")) {
257         int xmin,ymin,xmax,ymax;
258         xmin = swf->swf.movieSize.xmin;
259         ymin = swf->swf.movieSize.ymin;
260         xmax = swf->swf.movieSize.xmax;
261         ymax = swf->swf.movieSize.ymax;
262         mylog("swf_getattr %08x(%d) %s = (%d,%d,%d,%d)\n", (int)self, self->ob_refcnt, a, xmin,ymin,xmax,ymax);
263         return Py_BuildValue("(iiii)", xmin, ymin, xmax, ymax); 
264     } else if(!strcmp(a, "tags")) {
265         PyObject*ret =  (PyObject*)(swf->taglist);
266         Py_INCREF(ret);
267         mylog("swf_getattr %08x(%d) %s = %08x(%d)\n", (int)self, self->ob_refcnt, a, ret, ret->ob_refcnt);
268         return ret;
269     }
270
271     ret = Py_FindMethod(swf_functions, self, a);
272     mylog("swf_getattr %08x(%d) %s: %08x\n", (int)self, self->ob_refcnt, a, ret);
273     return ret;
274 }
275 //----------------------------------------------------------------------------
276 static int swf_setattr(PyObject * self, char* a, PyObject * o)
277 {
278     SWFObject*swf = (SWFObject*)self;
279     if(!strcmp(a, "fps")) {
280         double fps;
281         if (!PyArg_Parse(o, "d", &fps)) 
282             goto err;
283         swf->swf.frameRate = (int)(fps*0x100);
284         mylog("swf_setattr %08x(%d) %s = %f\n", (int)self, self->ob_refcnt, a, fps);
285         return 0;
286     } else if(!strcmp(a, "version")) {
287         int version;
288         if (!PyArg_Parse(o, "i", &version)) 
289             goto err;
290         swf->swf.fileVersion = version;
291         mylog("swf_setattr %08x(%d) %s = %d\n", (int)self, self->ob_refcnt, a, version);
292         return 0;
293     } else if(!strcmp(a, "name")) {
294         char*filename;
295         if (!PyArg_Parse(o, "s", &filename)) 
296             goto err;
297         if(swf->filename) {
298             free(swf->filename);swf->filename=0;
299         }
300         swf->filename = strdup(filename);
301         mylog("swf_setattr %08x(%d) %s = %s\n", (int)self, self->ob_refcnt, a, filename);
302         return 0;
303     } else if(!strcmp(a, "bbox")) {
304         int xmin=0,ymin=0,xmax=0,ymax=0;
305         if (!PyArg_Parse(o, "(iiii)", &xmin, &ymin, &xmax, &ymax)) 
306             goto err;
307
308         swf->swf.movieSize.xmin = xmin;
309         swf->swf.movieSize.ymin = ymin;
310         swf->swf.movieSize.xmax = xmax;
311         swf->swf.movieSize.ymax = ymax;
312         mylog("swf_setattr %08x(%d) %s = (%d,%d,%d,%d)\n", (int)self, self->ob_refcnt, a, xmin,ymin,xmax,ymax);
313         return 0;
314     } else if(!strcmp(a, "tags")) {
315         PyObject* taglist;
316         /*if (!PyArg_Parse(o, "O!", &TagListClass, &taglist));
317             goto err;*/
318         // TODO: check if it's really a taglist
319         taglist = o;
320         Py_DECREF(swf->taglist);
321         swf->taglist = taglist;
322         Py_INCREF(swf->taglist);
323         mylog("swf_setattr %08x(%d) %s = %08x\n", (int)self, self->ob_refcnt, a, swf->taglist);
324         return 0;
325     }
326 err:
327     mylog("swf_setattr %08x(%d) %s = ? (%08x)\n", (int)self, self->ob_refcnt, a, o);
328     return 1;
329 }
330
331 //----------------------------------------------------------------------------
332 static PyTypeObject SWFClass = 
333 {
334     PyObject_HEAD_INIT(NULL)
335     0,
336     tp_name: "SWF",
337     tp_basicsize: sizeof(SWFObject),
338     tp_itemsize: 0,
339     tp_dealloc: swf_dealloc,
340     tp_print: swf_print,
341     tp_getattr: swf_getattr,
342     tp_setattr: swf_setattr,
343 };
344 //----------------------------------------------------------------------------
345
346 static PyMethodDef SWFMethods[] = 
347 {
348     /* SWF creation*/
349     {"load", f_load, METH_VARARGS, "Load a SWF from disc."},
350     {"create", (PyCFunction)f_create, METH_KEYWORDS, "Create a new SWF from scratch."},
351     {0,0,0,0}
352     // save is a member function
353 };
354 PyMethodDef* swf_getMethods()
355 {
356     SWFClass.ob_type = &PyType_Type;
357     return SWFMethods;
358 }
359
360 // =============================================================================
361
362 #include "primitives.h"
363 #include "action.h"
364 #include "tag.h"
365 #include "taglist.h"
366
367 static PyObject* module_verbose(PyObject* self, PyObject* args)
368 {
369     if (!PyArg_ParseTuple(args,"i", &verbose)) 
370         return NULL;
371     return Py_BuildValue("s", 0);
372 }
373
374 static PyMethodDef LoggingMethods[] = 
375 {
376     /* Module functions */
377     {"verbose", module_verbose, METH_VARARGS, "Set the module verbosity"},
378     {0,0,0,0}
379 };
380     
381 void initSWF(void)
382 {
383     PyMethodDef* primitive_methods = primitive_getMethods();
384     PyMethodDef* tag_methods = tag_getMethods();
385     PyMethodDef* action_methods = action_getMethods();
386     PyMethodDef* swf_methods = swf_getMethods();
387
388     initLog("test.log",8,0,0,0,0);
389
390     PyMethodDef* all_methods = 0;
391     all_methods = addMethods(all_methods, primitive_methods);
392     all_methods = addMethods(all_methods, tag_methods);
393     all_methods = addMethods(all_methods, action_methods);
394     all_methods = addMethods(all_methods, swf_methods);
395
396     all_methods = addMethods(all_methods, LoggingMethods);
397
398     (void)Py_InitModule("SWF", all_methods);
399 }