added bbox attribute to text tag.
[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         int xmin,ymin,xmax,ymax;
298         xmin = swf->swf.movieSize.xmin;
299         ymin = swf->swf.movieSize.ymin;
300         xmax = swf->swf.movieSize.xmax;
301         ymax = swf->swf.movieSize.ymax;
302         mylog(" %08x(%d) swf_getattr %s = (%d,%d,%d,%d)\n", (int)self, self->ob_refcnt, a, xmin,ymin,xmax,ymax);
303         return Py_BuildValue("(iiii)", xmin, ymin, xmax, ymax); 
304     } else if(!strcmp(a, "tags")) {
305         PyObject*ret =  (PyObject*)(swf->taglist);
306         Py_INCREF(ret);
307         mylog(" %08x(%d) swf_getattr %s = %08x(%d)\n", (int)self, self->ob_refcnt, a, ret, ret->ob_refcnt);
308         return ret;
309     }
310
311     ret = Py_FindMethod(swf_functions, self, a);
312     mylog(" %08x(%d) swf_getattr %s: %08x\n", (int)self, self->ob_refcnt, a, ret);
313     return ret;
314 }
315 //----------------------------------------------------------------------------
316 static int swf_setattr(PyObject * self, char* a, PyObject * o)
317 {
318     SWFObject*swf = (SWFObject*)self;
319     if(!strcmp(a, "fps")) {
320         double fps;
321         if (!PyArg_Parse(o, "d", &fps)) 
322             goto err;
323         swf->swf.frameRate = (int)(fps*0x100);
324         mylog(" %08x(%d) swf_setattr %s = %f\n", (int)self, self->ob_refcnt, a, fps);
325         return 0;
326     } else if(!strcmp(a, "version")) {
327         int version;
328         if (!PyArg_Parse(o, "i", &version)) 
329             goto err;
330         swf->swf.fileVersion = version;
331         mylog(" %08x(%d) swf_setattr %s = %d\n", (int)self, self->ob_refcnt, a, version);
332         return 0;
333     } else if(!strcmp(a, "name")) {
334         char*filename;
335         if (!PyArg_Parse(o, "s", &filename)) 
336             goto err;
337         if(swf->filename) {
338             free(swf->filename);swf->filename=0;
339         }
340         swf->filename = strdup(filename);
341         mylog(" %08x(%d) swf_setattr %s = %s\n", (int)self, self->ob_refcnt, a, filename);
342         return 0;
343     } else if(!strcmp(a, "bbox")) {
344         int xmin=0,ymin=0,xmax=0,ymax=0;
345         if (!PyArg_Parse(o, "(iiii)", &xmin, &ymin, &xmax, &ymax)) 
346             goto err;
347
348         swf->swf.movieSize.xmin = xmin;
349         swf->swf.movieSize.ymin = ymin;
350         swf->swf.movieSize.xmax = xmax;
351         swf->swf.movieSize.ymax = ymax;
352         mylog(" %08x(%d) swf_setattr %s = (%d,%d,%d,%d)\n", (int)self, self->ob_refcnt, a, xmin,ymin,xmax,ymax);
353         return 0;
354     } else if(!strcmp(a, "tags")) {
355         PyObject* taglist;
356         taglist = o;
357         PY_ASSERT_TYPE(taglist,&TagListClass);
358         Py_DECREF(swf->taglist);
359         swf->taglist = taglist;
360         Py_INCREF(swf->taglist);
361         mylog(" %08x(%d) swf_setattr %s = %08x\n", (int)self, self->ob_refcnt, a, swf->taglist);
362         return 0;
363     }
364 err:
365     mylog(" %08x(%d) swf_setattr %s = ? (%08x)\n", (int)self, self->ob_refcnt, a, o);
366     return 1;
367 }
368
369 //----------------------------------------------------------------------------
370 static PyTypeObject SWFClass = 
371 {
372     PyObject_HEAD_INIT(NULL)
373     0,
374     tp_name: "SWF",
375     tp_basicsize: sizeof(SWFObject),
376     tp_itemsize: 0,
377     tp_dealloc: swf_dealloc,
378     tp_print: swf_print,
379     tp_getattr: swf_getattr,
380     tp_setattr: swf_setattr,
381 };
382 //----------------------------------------------------------------------------
383
384 static PyMethodDef SWFMethods[] = 
385 {
386     /* SWF creation*/
387     {"load", f_load, METH_VARARGS, "Load a SWF from disc."},
388     {"create", (PyCFunction)f_create, METH_KEYWORDS, "Create a new SWF from scratch."},
389     {0,0,0,0}
390     // save is a member function
391 };
392 PyMethodDef* swf_getMethods()
393 {
394     SWFClass.ob_type = &PyType_Type;
395     return SWFMethods;
396 }
397
398 // =============================================================================
399
400 #include "primitives.h"
401 #include "action.h"
402 #include "tag.h"
403 #include "taglist.h"
404
405 static PyObject* module_verbose(PyObject* self, PyObject* args, PyObject* kwargs)
406 {
407     int _verbose = 0;
408     static char *kwlist[] = {"verbosity", NULL};
409     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &verbose))
410         return NULL;
411     setVerbosity(_verbose);
412
413     return Py_BuildValue("s", 0);
414 }
415
416 static PyMethodDef LoggingMethods[] = 
417 {
418     /* Module functions */
419     {"verbose", (PyCFunction)module_verbose, METH_KEYWORDS, "Set the module verbosity"},
420     {0,0,0,0}
421 };
422
423 void initSWF(void)
424 {
425     PyObject*module;
426     PyMethodDef* primitive_methods = primitive_getMethods();
427     PyMethodDef* tag_methods = tags_getMethods();
428     PyMethodDef* action_methods = action_getMethods();
429     PyMethodDef* swf_methods = swf_getMethods();
430
431     PyMethodDef* all_methods = 0;
432     all_methods = addMethods(all_methods, primitive_methods);
433     all_methods = addMethods(all_methods, tag_methods);
434     all_methods = addMethods(all_methods, action_methods);
435     all_methods = addMethods(all_methods, swf_methods);
436
437     all_methods = addMethods(all_methods, LoggingMethods);
438
439     module = Py_InitModule("SWF", all_methods);
440
441     /* Python doesn't copy the PyMethodDef struct, so we need
442        to keep it around */
443     // free(all_methods) 
444 }
445