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