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