reworked tag memory allocation
[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     swf = PyObject_New(SWFObject, &SWFClass);
68     mylog("+%08x(%d) create\n", (int)swf, swf->ob_refcnt);
69
70     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|idOs", 
71                 kwlist, &version, &framerate, 
72                 &obbox, filename))
73         return NULL;
74
75     if (!PyArg_Parse(obbox, "(iiii)", &bbox.xmin, &bbox.ymin, &bbox.xmax, &bbox.ymax))
76         return NULL;
77
78     memset(&swf->swf, 0, sizeof(SWF));
79     if(filename)
80         swf->filename = strdup(filename);
81     else
82         swf->filename = 0;
83
84     swf->swf.fileVersion = version;
85     swf->swf.frameRate = (int)(framerate*0x100);
86     swf->swf.movieSize = bbox;
87     swf->taglist = taglist_new();
88
89     if(swf->swf.fileVersion>=6)
90         swf->swf.compressed = 1;
91
92     mylog(" %08x(%d) create: done\n", (int)swf, swf->ob_refcnt);
93     return (PyObject*)swf;
94 }
95 //----------------------------------------------------------------------------
96 static PyObject* f_load(PyObject* self, PyObject* args)
97 {
98     char* filename;
99     SWFObject* swf;
100     int fi;
101
102     if (!PyArg_ParseTuple(args,"s:load", &filename)) 
103         return NULL;
104
105     swf = PyObject_New(SWFObject, &SWFClass);
106     mylog("+%08x(%d) f_load\n", (int)swf, swf->ob_refcnt);
107
108     memset(&swf->swf, 0, sizeof(SWF));
109     swf->filename = strdup(filename);
110
111     if(!filename) {
112         PyErr_SetString(PyExc_Exception, setError("Couldn't open file %s", filename));
113         return 0;
114     }
115     fi = open(filename,O_RDONLY|O_BINARY);
116     if (fi<0) { 
117         PyErr_SetString(PyExc_Exception, setError("Couldn't open file %s", filename));
118         return 0;
119     }
120     if(swf_ReadSWF(fi,&swf->swf)<0) { 
121         close(fi);
122         PyErr_SetString(PyExc_Exception, setError("%s is not a valid SWF file or contains errors",filename));
123         return 0;
124     }
125     close(fi);
126
127     swf->taglist = taglist_new2(swf->swf.firstTag);
128     if(swf->taglist == NULL) {
129         return NULL;
130     }
131     
132     swf_FreeTags(&swf->swf);
133     swf->swf.firstTag = 0;
134     
135     return (PyObject*)swf;
136 }
137 //----------------------------------------------------------------------------
138 static PyObject * swf_save(PyObject* self, PyObject* args, PyObject* kwargs)
139 {
140     static char *kwlist[] = {"name", "compress", NULL};
141     SWFObject*swfo;
142     SWF*swf;
143     int fi;
144     char*filename = 0;
145     int compress = 0;
146
147     if(!self)
148         return NULL;
149
150     swfo = (SWFObject*)self;
151     swf = &swfo->swf;
152     
153     filename = swfo->filename;
154
155     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|si", kwlist, &filename, &compress))
156         return NULL;
157     
158     mylog(" %08x(%d) f_save filename=%s compress=%d\n", (int)self, self->ob_refcnt, filename, compress);
159
160     // keyword arg compress (=1) forces compression
161     if(compress)
162         swf->compressed = 1;
163     
164     swf->firstTag = taglist_getTAGs(swfo->taglist);
165     if(!swf->firstTag)
166         return NULL;
167
168     // fix the file, in case it is empty or not terminated properly
169     {
170         TAG*tag = swf->firstTag;
171         if(!tag)
172             tag = swf->firstTag = swf_InsertTag(0,ST_END);
173         while(tag && tag->next) {
174             tag = tag->next;
175         }
176         if(tag->id != ST_END) {
177             tag = swf_InsertTag(tag,ST_END);
178         }
179     }
180
181     fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
182     if(fi<0) {
183         PyErr_SetString(PyExc_Exception, setError("couldn't create output file %s", filename));
184         return 0;
185     }
186     if(swf->compressed) {
187             if(swf_WriteSWC(fi, swf)<0) {
188                 close(fi);
189                 PyErr_SetString(PyExc_Exception, setError("WriteSWC() failed."));
190                 return 0;
191             }
192     } else {
193             if(swf_WriteSWF(fi, swf)<0) {
194                 close(fi);
195                 PyErr_SetString(PyExc_Exception, setError("WriteSWC() failed."));
196                 return 0;
197             }
198     }
199     close(fi);
200
201     /* TODO: why is this segfaulting?? */
202    /* swf_FreeTags(swf);
203     swf->firstTag = 0;*/
204     
205     return PY_NONE;
206 }
207 //----------------------------------------------------------------------------
208 static PyObject * swf_writeCGI(PyObject* self, PyObject* args)
209 {
210     SWFObject*swf = (SWFObject*)self;
211     if(!self || !PyArg_ParseTuple(args,"")) 
212         return NULL;
213     swf->swf.firstTag = taglist_getTAGs(swf->taglist);
214     if(!swf->swf.firstTag)
215         return NULL;
216     swf_WriteCGI(&swf->swf);
217     swf->swf.firstTag = 0;
218     return PY_NONE;
219 }
220 //----------------------------------------------------------------------------
221
222 //TODO: void swf_Relocate(SWF*swf, char*bitmap); // bitmap is 65536 bytes, bitmap[a]==0 means id a is free
223
224 static PyMethodDef swf_functions[] =
225 {{"save", (PyCFunction)swf_save, METH_KEYWORDS, "Save SWF to disk"},
226  {"writeCGI", (PyCFunction)swf_writeCGI, METH_VARARGS, "print SWF as CGI to stdout"},
227  {NULL, NULL, 0, NULL}
228 };
229  
230 //----------------------------------------------------------------------------
231 static void swf_dealloc(PyObject* self)
232 {
233     mylog("-%08x(%d) swf_dealloc\n", (int)self, self->ob_refcnt);
234     SWFObject*swfo;
235     SWF*swf;
236     swfo = (SWFObject*)self;
237     swf = &swfo->swf;
238     if(swfo->filename) {
239         free(swfo->filename);
240         swfo->filename = 0;
241     }
242     Py_DECREF(swfo->taglist);
243     swfo->taglist = 0;
244     PyObject_Del(self);
245 }
246 //----------------------------------------------------------------------------
247 static int swf_print(PyObject * self, FILE *fi, int flags) //flags&Py_PRINT_RAW
248 {
249     mylog(" %08x(%d) print \n", (int)self, self->ob_refcnt);
250     SWFObject*swf = (SWFObject*)self;
251     swf_DumpHeader(fi, &swf->swf);
252     //void swf_DumpSWF(FILE * f,SWF*swf);
253     return 0;
254 }
255 //----------------------------------------------------------------------------
256 static PyObject* swf_getattr(PyObject * self, char* a)
257 {
258     SWFObject*swf = (SWFObject*)self;
259     PyObject* ret;
260
261     if(!strcmp(a, "fps")) {
262         double fps = swf->swf.frameRate/256.0;
263         mylog(" %08x(%d) swf_getattr %s = %f\n", (int)self, self->ob_refcnt, a, fps);
264         return Py_BuildValue("d", fps);
265     } else if(!strcmp(a, "version")) {
266         int version = swf->swf.fileVersion;;
267         mylog(" %08x(%d) swf_getattr %s = %d\n", (int)self, self->ob_refcnt, a, version);
268         return Py_BuildValue("i", version);
269     } else if(!strcmp(a, "name")) {
270         char*filename = swf->filename;
271         mylog(" %08x(%d) swf_getattr %s = %s\n", (int)self, self->ob_refcnt, a, filename);
272         return Py_BuildValue("s", filename);
273     } else if(!strcmp(a, "bbox")) {
274         int xmin,ymin,xmax,ymax;
275         xmin = swf->swf.movieSize.xmin;
276         ymin = swf->swf.movieSize.ymin;
277         xmax = swf->swf.movieSize.xmax;
278         ymax = swf->swf.movieSize.ymax;
279         mylog(" %08x(%d) swf_getattr %s = (%d,%d,%d,%d)\n", (int)self, self->ob_refcnt, a, xmin,ymin,xmax,ymax);
280         return Py_BuildValue("(iiii)", xmin, ymin, xmax, ymax); 
281     } else if(!strcmp(a, "tags")) {
282         PyObject*ret =  (PyObject*)(swf->taglist);
283         Py_INCREF(ret);
284         mylog(" %08x(%d) swf_getattr %s = %08x(%d)\n", (int)self, self->ob_refcnt, a, ret, ret->ob_refcnt);
285         return ret;
286     }
287
288     ret = Py_FindMethod(swf_functions, self, a);
289     mylog(" %08x(%d) swf_getattr %s: %08x\n", (int)self, self->ob_refcnt, a, ret);
290     return ret;
291 }
292 //----------------------------------------------------------------------------
293 static int swf_setattr(PyObject * self, char* a, PyObject * o)
294 {
295     SWFObject*swf = (SWFObject*)self;
296     if(!strcmp(a, "fps")) {
297         double fps;
298         if (!PyArg_Parse(o, "d", &fps)) 
299             goto err;
300         swf->swf.frameRate = (int)(fps*0x100);
301         mylog(" %08x(%d) swf_setattr %s = %f\n", (int)self, self->ob_refcnt, a, fps);
302         return 0;
303     } else if(!strcmp(a, "version")) {
304         int version;
305         if (!PyArg_Parse(o, "i", &version)) 
306             goto err;
307         swf->swf.fileVersion = version;
308         mylog(" %08x(%d) swf_setattr %s = %d\n", (int)self, self->ob_refcnt, a, version);
309         return 0;
310     } else if(!strcmp(a, "name")) {
311         char*filename;
312         if (!PyArg_Parse(o, "s", &filename)) 
313             goto err;
314         if(swf->filename) {
315             free(swf->filename);swf->filename=0;
316         }
317         swf->filename = strdup(filename);
318         mylog(" %08x(%d) swf_setattr %s = %s\n", (int)self, self->ob_refcnt, a, filename);
319         return 0;
320     } else if(!strcmp(a, "bbox")) {
321         int xmin=0,ymin=0,xmax=0,ymax=0;
322         if (!PyArg_Parse(o, "(iiii)", &xmin, &ymin, &xmax, &ymax)) 
323             goto err;
324
325         swf->swf.movieSize.xmin = xmin;
326         swf->swf.movieSize.ymin = ymin;
327         swf->swf.movieSize.xmax = xmax;
328         swf->swf.movieSize.ymax = ymax;
329         mylog(" %08x(%d) swf_setattr %s = (%d,%d,%d,%d)\n", (int)self, self->ob_refcnt, a, xmin,ymin,xmax,ymax);
330         return 0;
331     } else if(!strcmp(a, "tags")) {
332         PyObject* taglist;
333         /*if (!PyArg_Parse(o, "O!", &TagListClass, &taglist));
334             goto err;*/
335         // TODO: check if it's really a taglist
336         taglist = o;
337         Py_DECREF(swf->taglist);
338         swf->taglist = taglist;
339         Py_INCREF(swf->taglist);
340         mylog(" %08x(%d) swf_setattr %s = %08x\n", (int)self, self->ob_refcnt, a, swf->taglist);
341         return 0;
342     }
343 err:
344     mylog(" %08x(%d) swf_setattr %s = ? (%08x)\n", (int)self, self->ob_refcnt, a, o);
345     return 1;
346 }
347
348 //----------------------------------------------------------------------------
349 static PyTypeObject SWFClass = 
350 {
351     PyObject_HEAD_INIT(NULL)
352     0,
353     tp_name: "SWF",
354     tp_basicsize: sizeof(SWFObject),
355     tp_itemsize: 0,
356     tp_dealloc: swf_dealloc,
357     tp_print: swf_print,
358     tp_getattr: swf_getattr,
359     tp_setattr: swf_setattr,
360 };
361 //----------------------------------------------------------------------------
362
363 static PyMethodDef SWFMethods[] = 
364 {
365     /* SWF creation*/
366     {"load", f_load, METH_VARARGS, "Load a SWF from disc."},
367     {"create", (PyCFunction)f_create, METH_KEYWORDS, "Create a new SWF from scratch."},
368     {0,0,0,0}
369     // save is a member function
370 };
371 PyMethodDef* swf_getMethods()
372 {
373     SWFClass.ob_type = &PyType_Type;
374     return SWFMethods;
375 }
376
377 // =============================================================================
378
379 #include "primitives.h"
380 #include "action.h"
381 #include "tag.h"
382 #include "taglist.h"
383
384 static PyObject* module_verbose(PyObject* self, PyObject* args, PyObject* kwargs)
385 {
386     int _verbose = 0;
387     static char *kwlist[] = {"verbosity", NULL};
388     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &verbose))
389         return NULL;
390     setVerbosity(_verbose);
391
392     return Py_BuildValue("s", 0);
393 }
394
395 static PyMethodDef LoggingMethods[] = 
396 {
397     /* Module functions */
398     {"verbose", (PyCFunction)module_verbose, METH_KEYWORDS, "Set the module verbosity"},
399     {0,0,0,0}
400 };
401     
402 void initSWF(void)
403 {
404     PyObject*module;
405     PyMethodDef* primitive_methods = primitive_getMethods();
406     PyMethodDef* tag_methods = tag_getMethods();
407     PyMethodDef* action_methods = action_getMethods();
408     PyMethodDef* swf_methods = swf_getMethods();
409
410     PyMethodDef* all_methods = 0;
411     all_methods = addMethods(all_methods, primitive_methods);
412     all_methods = addMethods(all_methods, tag_methods);
413     all_methods = addMethods(all_methods, action_methods);
414     all_methods = addMethods(all_methods, swf_methods);
415
416     all_methods = addMethods(all_methods, LoggingMethods);
417
418     module = Py_InitModule("SWF", all_methods);
419 }