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