memory management and logging fixes
[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
110     if(!filename) {
111         PyErr_SetString(PyExc_Exception, setError("Couldn't open file %s", filename));
112         return 0;
113     }
114     swf->filename = strdup(filename);
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     //swf_FreeTags(swf);
202     /*{ TAG * t = swf->firstTag;
203       while (t)
204       { 
205         mylog("tag: %08x\n",t);
206         mylog("  id: %d (%s)\n", t->id, swf_TagGetName(t));
207         mylog("  data: %08x (%d bytes)\n", t->data, t->len);
208         mylog("  next: %08x\n", t->next);
209         TAG * tnew = t->next;
210         mylog("->free data\n");
211         if (t->data) free(t->data);
212         mylog("->free tag\n");
213         free(t);
214         t = tnew;
215       }
216     }*/
217     swf->firstTag = 0;
218     
219     return PY_NONE;
220 }
221 //----------------------------------------------------------------------------
222 static PyObject * swf_writeCGI(PyObject* self, PyObject* args)
223 {
224     SWFObject*swf = (SWFObject*)self;
225     if(!self || !PyArg_ParseTuple(args,"")) 
226         return NULL;
227     swf->swf.firstTag = taglist_getTAGs(swf->taglist);
228     if(!swf->swf.firstTag)
229         return NULL;
230     swf_WriteCGI(&swf->swf);
231     swf_FreeTags(&swf->swf);
232     swf->swf.firstTag = 0;
233     return PY_NONE;
234 }
235 //----------------------------------------------------------------------------
236
237 //TODO: void swf_Relocate(SWF*swf, char*bitmap); // bitmap is 65536 bytes, bitmap[a]==0 means id a is free
238
239 static PyMethodDef swf_functions[] =
240 {{"save", (PyCFunction)swf_save, METH_KEYWORDS, "Save SWF to disk"},
241  {"writeCGI", (PyCFunction)swf_writeCGI, METH_VARARGS, "print SWF as CGI to stdout"},
242  {NULL, NULL, 0, NULL}
243 };
244  
245 //----------------------------------------------------------------------------
246 static void swf_dealloc(PyObject* self)
247 {
248     mylog("-%08x(%d) swf_dealloc\n", (int)self, self->ob_refcnt);
249     SWFObject*swfo;
250     SWF*swf;
251     swfo = (SWFObject*)self;
252     swf = &swfo->swf;
253     if(swfo->filename) {
254         free(swfo->filename);
255         swfo->filename = 0;
256     }
257     Py_DECREF(swfo->taglist);
258     swfo->taglist = 0;
259     PyObject_Del(self);
260 }
261 //----------------------------------------------------------------------------
262 static int swf_print(PyObject * self, FILE *fi, int flags) //flags&Py_PRINT_RAW
263 {
264     mylog(" %08x(%d) print \n", (int)self, self->ob_refcnt);
265     SWFObject*swf = (SWFObject*)self;
266     swf_DumpHeader(fi, &swf->swf);
267     //void swf_DumpSWF(FILE * f,SWF*swf);
268     return 0;
269 }
270 //----------------------------------------------------------------------------
271 static PyObject* swf_getattr(PyObject * self, char* a)
272 {
273     SWFObject*swf = (SWFObject*)self;
274     PyObject* ret;
275
276     if(!strcmp(a, "fps")) {
277         double fps = swf->swf.frameRate/256.0;
278         mylog(" %08x(%d) swf_getattr %s = %f\n", (int)self, self->ob_refcnt, a, fps);
279         return Py_BuildValue("d", fps);
280     } else if(!strcmp(a, "version")) {
281         int version = swf->swf.fileVersion;;
282         mylog(" %08x(%d) swf_getattr %s = %d\n", (int)self, self->ob_refcnt, a, version);
283         return Py_BuildValue("i", version);
284     } else if(!strcmp(a, "name")) {
285         char*filename = swf->filename;
286         mylog(" %08x(%d) swf_getattr %s = %s\n", (int)self, self->ob_refcnt, a, filename);
287         return Py_BuildValue("s", filename);
288     } else if(!strcmp(a, "bbox")) {
289         int xmin,ymin,xmax,ymax;
290         xmin = swf->swf.movieSize.xmin;
291         ymin = swf->swf.movieSize.ymin;
292         xmax = swf->swf.movieSize.xmax;
293         ymax = swf->swf.movieSize.ymax;
294         mylog(" %08x(%d) swf_getattr %s = (%d,%d,%d,%d)\n", (int)self, self->ob_refcnt, a, xmin,ymin,xmax,ymax);
295         return Py_BuildValue("(iiii)", xmin, ymin, xmax, ymax); 
296     } else if(!strcmp(a, "tags")) {
297         PyObject*ret =  (PyObject*)(swf->taglist);
298         Py_INCREF(ret);
299         mylog(" %08x(%d) swf_getattr %s = %08x(%d)\n", (int)self, self->ob_refcnt, a, ret, ret->ob_refcnt);
300         return ret;
301     }
302
303     ret = Py_FindMethod(swf_functions, self, a);
304     mylog(" %08x(%d) swf_getattr %s: %08x\n", (int)self, self->ob_refcnt, a, ret);
305     return ret;
306 }
307 //----------------------------------------------------------------------------
308 static int swf_setattr(PyObject * self, char* a, PyObject * o)
309 {
310     SWFObject*swf = (SWFObject*)self;
311     if(!strcmp(a, "fps")) {
312         double fps;
313         if (!PyArg_Parse(o, "d", &fps)) 
314             goto err;
315         swf->swf.frameRate = (int)(fps*0x100);
316         mylog(" %08x(%d) swf_setattr %s = %f\n", (int)self, self->ob_refcnt, a, fps);
317         return 0;
318     } else if(!strcmp(a, "version")) {
319         int version;
320         if (!PyArg_Parse(o, "i", &version)) 
321             goto err;
322         swf->swf.fileVersion = version;
323         mylog(" %08x(%d) swf_setattr %s = %d\n", (int)self, self->ob_refcnt, a, version);
324         return 0;
325     } else if(!strcmp(a, "name")) {
326         char*filename;
327         if (!PyArg_Parse(o, "s", &filename)) 
328             goto err;
329         if(swf->filename) {
330             free(swf->filename);swf->filename=0;
331         }
332         swf->filename = strdup(filename);
333         mylog(" %08x(%d) swf_setattr %s = %s\n", (int)self, self->ob_refcnt, a, filename);
334         return 0;
335     } else if(!strcmp(a, "bbox")) {
336         int xmin=0,ymin=0,xmax=0,ymax=0;
337         if (!PyArg_Parse(o, "(iiii)", &xmin, &ymin, &xmax, &ymax)) 
338             goto err;
339
340         swf->swf.movieSize.xmin = xmin;
341         swf->swf.movieSize.ymin = ymin;
342         swf->swf.movieSize.xmax = xmax;
343         swf->swf.movieSize.ymax = ymax;
344         mylog(" %08x(%d) swf_setattr %s = (%d,%d,%d,%d)\n", (int)self, self->ob_refcnt, a, xmin,ymin,xmax,ymax);
345         return 0;
346     } else if(!strcmp(a, "tags")) {
347         PyObject* taglist;
348         taglist = o;
349         PY_ASSERT_TYPE(taglist,&TagListClass);
350         Py_DECREF(swf->taglist);
351         swf->taglist = taglist;
352         Py_INCREF(swf->taglist);
353         mylog(" %08x(%d) swf_setattr %s = %08x\n", (int)self, self->ob_refcnt, a, swf->taglist);
354         return 0;
355     }
356 err:
357     mylog(" %08x(%d) swf_setattr %s = ? (%08x)\n", (int)self, self->ob_refcnt, a, o);
358     return 1;
359 }
360
361 //----------------------------------------------------------------------------
362 static PyTypeObject SWFClass = 
363 {
364     PyObject_HEAD_INIT(NULL)
365     0,
366     tp_name: "SWF",
367     tp_basicsize: sizeof(SWFObject),
368     tp_itemsize: 0,
369     tp_dealloc: swf_dealloc,
370     tp_print: swf_print,
371     tp_getattr: swf_getattr,
372     tp_setattr: swf_setattr,
373 };
374 //----------------------------------------------------------------------------
375
376 static PyMethodDef SWFMethods[] = 
377 {
378     /* SWF creation*/
379     {"load", f_load, METH_VARARGS, "Load a SWF from disc."},
380     {"create", (PyCFunction)f_create, METH_KEYWORDS, "Create a new SWF from scratch."},
381     {0,0,0,0}
382     // save is a member function
383 };
384 PyMethodDef* swf_getMethods()
385 {
386     SWFClass.ob_type = &PyType_Type;
387     return SWFMethods;
388 }
389
390 // =============================================================================
391
392 #include "primitives.h"
393 #include "action.h"
394 #include "tag.h"
395 #include "taglist.h"
396
397 static PyObject* module_verbose(PyObject* self, PyObject* args, PyObject* kwargs)
398 {
399     int _verbose = 0;
400     static char *kwlist[] = {"verbosity", NULL};
401     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &verbose))
402         return NULL;
403     setVerbosity(_verbose);
404
405     return Py_BuildValue("s", 0);
406 }
407
408 static PyMethodDef LoggingMethods[] = 
409 {
410     /* Module functions */
411     {"verbose", (PyCFunction)module_verbose, METH_KEYWORDS, "Set the module verbosity"},
412     {0,0,0,0}
413 };
414
415 void initSWF(void)
416 {
417     PyObject*module;
418     PyMethodDef* primitive_methods = primitive_getMethods();
419     PyMethodDef* tag_methods = tag_getMethods();
420     PyMethodDef* action_methods = action_getMethods();
421     PyMethodDef* swf_methods = swf_getMethods();
422
423     PyMethodDef* all_methods = 0;
424     all_methods = addMethods(all_methods, primitive_methods);
425     all_methods = addMethods(all_methods, tag_methods);
426     all_methods = addMethods(all_methods, action_methods);
427     all_methods = addMethods(all_methods, swf_methods);
428
429     all_methods = addMethods(all_methods, LoggingMethods);
430
431     module = Py_InitModule("SWF", all_methods);
432
433     /* Python doesn't copy the PyMethodDef struct, so we need
434        to keep it around */
435     // free(all_methods) 
436 }
437