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