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