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