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