d11925fbc9dc0ce6b684c82a971c39f8090a2b89
[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 "primitives.h"
29 #include "action.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 staticforward PyTypeObject TagListClass;
46 staticforward PyTypeObject TagClass;
47
48 /* Tags, Objects */
49
50 typedef struct {
51     PyObject_HEAD
52     TAG*tag;
53     /* ST_DEFINEFONT*/
54     SWFFONT* font;
55     /* ST_PLACEOBJECT, ST_PLACEOBJECT2*/
56     SWFPLACEOBJECT* placeobject;
57     PyObject* character;
58 } TagObject;
59
60 typedef struct {
61     PyObject_HEAD
62     TAG*firstTag;
63     TAG*searchTag;
64     TAG*lastTag;
65     PyDictObject* char2id;
66     PyDictObject* id2char;
67     U16 currentID;
68 } TagListObject;
69
70 typedef struct {
71     PyObject_HEAD
72     SWF swf; //swf.firstTag ist not used
73     TagListObject*taglist;
74     char*filename;
75 } SWFObject;
76
77 //----------------------------------------------------------------------------
78 static PyObject* f_create(PyObject* self, PyObject* args, PyObject* kwargs)
79 {
80     static char *kwlist[] = {"version", "fps", "bbox", "name", NULL};
81     SWFObject* swf;
82     int version = 6;
83     double framerate = 25;
84     PyObject * obbox = 0;
85     SRECT bbox = {0,0,0,0};
86     char* filename = 0;
87
88     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|idOs", 
89                 kwlist, &version, &framerate, 
90                 &obbox, filename))
91         return NULL;
92
93     if (!PyArg_Parse(obbox, "(iiii)", &bbox.xmin, &bbox.ymin, &bbox.xmax, &bbox.ymax))
94         return NULL;
95
96     swf = PyObject_New(SWFObject, &SWFClass);
97     memset(&swf->swf, 0, sizeof(SWF));
98     if(filename)
99         swf->filename = strdup(filename);
100     else
101         swf->filename = 0;
102
103     swf->swf.fileVersion = version;
104     swf->swf.frameRate = (int)(framerate*0x100);
105     swf->swf.movieSize = bbox;
106     swf->taglist = PyObject_New(TagListObject, &TagListClass);
107     swf->taglist->firstTag = 0;
108     swf->taglist->searchTag = 0;
109     swf->taglist->lastTag = 0;
110     swf->taglist->currentID = 1;
111     swf->taglist->char2id = (PyDictObject*)PyDict_New();
112     swf->taglist->id2char = (PyDictObject*)PyDict_New();
113
114     if(swf->swf.fileVersion>=6)
115         swf->swf.compressed = 1;
116
117     mylog("create %08x -> %08x\n", (int)self, (int)swf);
118     return (PyObject*)swf;
119 }
120 //----------------------------------------------------------------------------
121 static PyObject* f_load(PyObject* self, PyObject* args)
122 {
123     char* filename;
124     SWFObject* swf;
125     int fi;
126
127     if (!PyArg_ParseTuple(args,"s:load", &filename)) 
128         return NULL;
129
130     swf = PyObject_New(SWFObject, &SWFClass);
131     memset(&swf->swf, 0, sizeof(SWF));
132     swf->filename = strdup(filename);
133     swf->taglist = PyObject_New(TagListObject, &TagListClass);
134
135     if(!filename) {
136         PyErr_SetString(PyExc_Exception, setError("Couldn't open file %s", filename));
137         return 0;
138     }
139     fi = open(filename,O_RDONLY|O_BINARY);
140     if (fi<0) { 
141         PyErr_SetString(PyExc_Exception, setError("Couldn't open file %s", filename));
142         return 0;
143     }
144     if(swf_ReadSWF(fi,&swf->swf)<0) { 
145         close(fi);
146         PyErr_SetString(PyExc_Exception, setError("%s is not a valid SWF file or contains errors",filename));
147         return 0;
148     }
149     close(fi);
150     
151     swf->taglist->firstTag = swf->swf.firstTag;
152     swf->taglist->searchTag = swf->swf.firstTag;
153     swf->taglist->lastTag = swf->swf.firstTag;
154     swf->taglist->currentID = 1;
155     swf->taglist->char2id = (PyDictObject*)PyDict_New();
156     swf->taglist->id2char = (PyDictObject*)PyDict_New();
157     swf->swf.firstTag = 0;
158
159     mylog("load %08x -> %08x\n", (int)self, (int)swf);
160     return (PyObject*)swf;
161 }
162 //----------------------------------------------------------------------------
163 static PyObject * swf_save(PyObject* self, PyObject* args, PyObject* kwargs)
164 {
165     static char *kwlist[] = {"name", "compress", NULL};
166     SWFObject*swfo;
167     SWF*swf;
168     int fi;
169     char*filename = 0;
170     int compress = 0;
171
172     if(!self)
173         return NULL;
174
175     swfo = (SWFObject*)self;
176     swf = &swfo->swf;
177     
178     filename = swfo->filename;
179
180     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|si", kwlist, &filename, &compress))
181         return NULL;
182
183     // keyword arg compress (=1) forces compression
184     if(compress)
185         swf->compressed = 1;
186     
187     swf->firstTag = swfo->taglist->firstTag;
188
189     // fix the file, in case it is empty or not terminated properly
190     {
191         TAG*tag = swf->firstTag;
192         if(!tag)
193             tag = swf->firstTag = swf_InsertTag(0,ST_END);
194         while(tag && tag->next)
195             tag = tag->next;
196         if(tag->id != ST_END) {
197             tag = swf_InsertTag(tag,ST_END);
198         }
199     }
200
201     fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
202     if(fi<0) {
203         PyErr_SetString(PyExc_Exception, setError("couldn't create output file %s", filename));
204         return 0;
205     }
206     if(swf->compressed) {
207             if(swf_WriteSWC(fi, swf)<0) {
208                 close(fi);
209                 PyErr_SetString(PyExc_Exception, setError("WriteSWC() failed."));
210                 return 0;
211             }
212     } else {
213             if(swf_WriteSWF(fi, swf)<0) {
214                 close(fi);
215                 PyErr_SetString(PyExc_Exception, setError("WriteSWC() failed."));
216                 return 0;
217             }
218     }
219     close(fi);
220     
221     swf->firstTag = 0;
222     
223     return PY_NONE;
224 }
225 //----------------------------------------------------------------------------
226 static PyObject * swf_writeCGI(PyObject* self, PyObject* args)
227 {
228     SWFObject*swf = (SWFObject*)self;
229     if(!self || !PyArg_ParseTuple(args,"")) 
230         return NULL;
231     swf->swf.firstTag = swf->taglist->firstTag;
232     swf_WriteCGI(&swf->swf);
233     swf->swf.firstTag = 0;
234     return PY_NONE;
235 }
236 //----------------------------------------------------------------------------
237 static PyObject * taglist_foldAll(PyObject* self, PyObject* args)
238 {
239     SWF swf;
240     TagListObject*taglist = (TagListObject*)self;
241     if(!self || !PyArg_ParseTuple(args,"")) 
242         return NULL;
243     swf.firstTag = taglist->firstTag;
244     swf_FoldAll(&swf);
245     taglist->firstTag = swf.firstTag;
246     taglist->lastTag = 0; // FIXME
247     taglist->searchTag = 0;
248     return PY_NONE;
249 }
250 //----------------------------------------------------------------------------
251 static PyObject * taglist_unfoldAll(PyObject* self, PyObject* args)
252 {
253     SWF swf;
254     TagListObject*taglist = (TagListObject*)self;
255     if(!self || !PyArg_ParseTuple(args,"")) 
256         return NULL;
257     swf.firstTag = taglist->firstTag;
258     swf_UnFoldAll(&swf);
259     taglist->firstTag = swf.firstTag;
260     taglist->lastTag = 0; // FIXME
261     taglist->searchTag = 0;
262     return PY_NONE;
263 }
264 //----------------------------------------------------------------------------
265 static PyObject * taglist_optimizeOrder(PyObject* self, PyObject* args)
266 {
267     SWF swf;
268     TagListObject*taglist = (TagListObject*)self;
269     if(!self || !PyArg_ParseTuple(args,"")) 
270         return NULL;
271     swf.firstTag = taglist->firstTag;
272     swf_UnFoldAll(&swf);
273     taglist->firstTag = swf.firstTag;
274     taglist->lastTag = 0; // FIXME
275     taglist->searchTag = 0;
276     return PY_NONE;
277 }
278 //----------------------------------------------------------------------------
279
280 //TODO: void swf_Relocate(SWF*swf, char*bitmap); // bitmap is 65536 bytes, bitmap[a]==0 means id a is free
281
282 static PyMethodDef swf_functions[] =
283 {{"save", (PyCFunction)swf_save, METH_KEYWORDS, "Save SWF to disk"},
284  {"writeCGI", (PyCFunction)swf_writeCGI, METH_VARARGS, "print SWF as CGI to stdout"},
285  {NULL, NULL, 0, NULL}
286 };
287  
288 //----------------------------------------------------------------------------
289 static void swf_dealloc(PyObject* self)
290 {
291     SWFObject*swfo;
292     SWF*swf;
293     swfo = (SWFObject*)self;
294     swf = &swfo->swf;
295     mylog("swf_dealloc %08x(%d)\n", (int)self, self->ob_refcnt);
296     if(swfo->filename) {
297         free(swfo->filename);
298         swfo->filename = 0;
299     }
300     Py_DECREF(swfo->taglist);
301     swfo->taglist = 0;
302     PyObject_Del(self);
303 }
304 //----------------------------------------------------------------------------
305 static void taglist_dealloc(PyObject* self)
306 {
307     TagListObject*taglist = (TagListObject*)self;
308     SWF swf;
309     mylog("taglist_dealloc %08x(%d)\n", (int)self, self->ob_refcnt);
310     swf.firstTag = taglist->firstTag;
311     swf_FreeTags(&swf);
312     taglist->firstTag = 0;
313     taglist->lastTag = 0;
314     taglist->searchTag = 0;
315     PyObject_Del(self);
316 }
317 //----------------------------------------------------------------------------
318 static int swf_print(PyObject * self, FILE *fi, int flags) //flags&Py_PRINT_RAW
319 {
320     SWFObject*swf = (SWFObject*)self;
321     swf_DumpHeader(fi, &swf->swf);
322     //void swf_DumpSWF(FILE * f,SWF*swf);
323     mylog("print %08x(%d)\n", (int)self, self->ob_refcnt);
324     return 0;
325 }
326 //----------------------------------------------------------------------------
327 static PyObject* swf_getattr(PyObject * self, char* a)
328 {
329     SWFObject*swf = (SWFObject*)self;
330     PyObject* ret;
331
332     if(!strcmp(a, "fps")) {
333         double fps = swf->swf.frameRate/256.0;
334         mylog("swf_getattr %08x(%d) %s = %f\n", (int)self, self->ob_refcnt, a, fps);
335         return Py_BuildValue("d", fps);
336     } else if(!strcmp(a, "version")) {
337         int version = swf->swf.fileVersion;;
338         mylog("swf_getattr %08x(%d) %s = %d\n", (int)self, self->ob_refcnt, a, version);
339         return Py_BuildValue("i", version);
340     } else if(!strcmp(a, "name")) {
341         char*filename = swf->filename;
342         mylog("swf_getattr %08x(%d) %s = %s\n", (int)self, self->ob_refcnt, a, filename);
343         return Py_BuildValue("s", filename);
344     } else if(!strcmp(a, "bbox")) {
345         int xmin,ymin,xmax,ymax;
346         xmin = swf->swf.movieSize.xmin;
347         ymin = swf->swf.movieSize.ymin;
348         xmax = swf->swf.movieSize.xmax;
349         ymax = swf->swf.movieSize.ymax;
350         mylog("swf_getattr %08x(%d) %s = (%d,%d,%d,%d)\n", (int)self, self->ob_refcnt, a, xmin,ymin,xmax,ymax);
351         return Py_BuildValue("(iiii)", xmin, ymin, xmax, ymax); 
352     } else if(!strcmp(a, "tags")) {
353         PyObject*ret =  (PyObject*)(swf->taglist);
354         Py_INCREF(ret);
355         mylog("swf_getattr %08x(%d) %s = %08x(%d)\n", (int)self, self->ob_refcnt, a, ret, ret->ob_refcnt);
356         return ret;
357     }
358
359     ret = Py_FindMethod(swf_functions, self, a);
360     mylog("swf_getattr %08x(%d) %s: %08x\n", (int)self, self->ob_refcnt, a, ret);
361     return ret;
362 }
363 //----------------------------------------------------------------------------
364 static int swf_setattr(PyObject * self, char* a, PyObject * o)
365 {
366     SWFObject*swf = (SWFObject*)self;
367     if(!strcmp(a, "fps")) {
368         double fps;
369         if (!PyArg_Parse(o, "d", &fps)) 
370             goto err;
371         swf->swf.frameRate = (int)(fps*0x100);
372         mylog("swf_setattr %08x(%d) %s = %f\n", (int)self, self->ob_refcnt, a, fps);
373         return 0;
374     } else if(!strcmp(a, "version")) {
375         int version;
376         if (!PyArg_Parse(o, "i", &version)) 
377             goto err;
378         swf->swf.fileVersion = version;
379         mylog("swf_setattr %08x(%d) %s = %d\n", (int)self, self->ob_refcnt, a, version);
380         return 0;
381     } else if(!strcmp(a, "name")) {
382         char*filename;
383         if (!PyArg_Parse(o, "s", &filename)) 
384             goto err;
385         if(swf->filename) {
386             free(swf->filename);swf->filename=0;
387         }
388         swf->filename = strdup(filename);
389         mylog("swf_setattr %08x(%d) %s = %s\n", (int)self, self->ob_refcnt, a, filename);
390         return 0;
391     } else if(!strcmp(a, "bbox")) {
392         int xmin=0,ymin=0,xmax=0,ymax=0;
393         if (!PyArg_Parse(o, "(iiii)", &xmin, &ymin, &xmax, &ymax)) 
394             goto err;
395
396         swf->swf.movieSize.xmin = xmin;
397         swf->swf.movieSize.ymin = ymin;
398         swf->swf.movieSize.xmax = xmax;
399         swf->swf.movieSize.ymax = ymax;
400         mylog("swf_setattr %08x(%d) %s = (%d,%d,%d,%d)\n", (int)self, self->ob_refcnt, a, xmin,ymin,xmax,ymax);
401         return 0;
402     } else if(!strcmp(a, "tags")) {
403         TagListObject* taglist;
404         /*if (!PyArg_Parse(o, "O!", &TagListClass, &taglist));
405             goto err;*/
406         taglist = (TagListObject*)o;
407         Py_DECREF(swf->taglist);
408         swf->taglist = taglist;
409         Py_INCREF(swf->taglist);
410         mylog("swf_setattr %08x(%d) %s = %08x\n", (int)self, self->ob_refcnt, a, swf->taglist);
411         return 0;
412     }
413 err:
414     mylog("swf_setattr %08x(%d) %s = ? (%08x)\n", (int)self, self->ob_refcnt, a, o);
415     return 1;
416 }
417
418 //----------------------------------------------------------------------------
419 static PyMethodDef taglist_functions[] =
420 {{"foldAll", taglist_foldAll, METH_VARARGS, "fold all sprites (movieclips) in the list"},
421  {"unfoldAll", taglist_unfoldAll, METH_VARARGS, "unfold (expand) all sprites (movieclips) in the list"},
422  {"optimizeOrder", taglist_optimizeOrder, METH_VARARGS, "Reorder the Tag structure"},
423  {NULL, NULL, 0, NULL}
424 };
425
426 static PyObject* taglist_getattr(PyObject * self, char* a)
427 {
428     PyObject* ret = Py_FindMethod(taglist_functions, self, a);
429     mylog("taglist_getattr %08x(%d) %s: %08x\n", (int)self, self->ob_refcnt, a, ret);
430     return ret;
431 }
432 //----------------------------------------------------------------------------
433 static int taglist_length(PyObject * self)
434 {
435     TagListObject*tags = (TagListObject*)self;
436     TAG*tag;
437     int l = 0;
438     mylog("taglist_length %08x(%d)", (int)self, self->ob_refcnt);
439     tag = tags->firstTag;
440     while(tag) {
441         l++;
442         tag = tag->next;
443     }
444     return l;
445 }
446 //----------------------------------------------------------------------------
447 static PyObject * taglist_concat(PyObject * self, PyObject* list)
448 {
449     TagObject*tag;
450     TagListObject*taglist = (TagListObject*)self;
451     mylog("taglist_concat %08x(%d) %08x", (int)self, self->ob_refcnt, list);
452         
453     if (PyArg_Parse(list, "O!", &TagClass, &tag)) {
454         /* copy tag, so we don't have to do INCREF(tag) (and don't
455            get problems if the tag is appended to more than one
456            taglist) */
457         /* TODO: handle IDs */
458         mylog("taglist_concat: Tag", (int)self, self->ob_refcnt);
459         taglist->lastTag = swf_InsertTag(taglist->lastTag, tag->tag->id);
460         swf_SetBlock(taglist->lastTag, tag->tag->data, tag->tag->len);
461         if(!taglist->firstTag) {
462             taglist->firstTag = taglist->searchTag = taglist->lastTag;
463         }
464         if(swf_isDefiningTag(tag->tag)) {
465             PyObject*id = PyLong_FromLong(taglist->currentID);
466             PyDict_SetItem((PyObject*)(taglist->char2id), list, id);
467             Py_INCREF(id);
468             PyDict_SetItem((PyObject*)(taglist->id2char), id, list);
469             Py_INCREF(id);
470         }
471         Py_INCREF(self);
472         return self;
473     }
474     PyErr_Clear();
475     if (PyList_Check(list)) {
476         int l = PyList_Size(list);
477         int t;
478         mylog("taglist_concat: PythonList", (int)self, self->ob_refcnt);
479         for(t=0;t<l;t++) {
480             PyObject*item = PyList_GetItem(list, t);
481             self = taglist_concat(self, item);
482             if(!self)
483                 return 0;
484         }
485         Py_INCREF(self);
486         return self;
487     }
488     PyErr_SetString(PyExc_Exception, setError("taglist concatenation only works with tags and lists (%08x).", list));
489     return 0;
490 }
491 //----------------------------------------------------------------------------
492 staticforward TagObject* TagObject_New();
493 static PyObject * taglist_item(PyObject * self, int index)
494 {
495     TagListObject*taglist = (TagListObject*)self;
496     TAG*tag;
497     TagObject*tagobject;
498     int i = 0;
499     mylog("taglist_item %08x(%d) [%d]", (int)self, self->ob_refcnt, index);
500
501     if(index<0) {
502         PyErr_SetString(PyExc_Exception, setError("Negative Indices not supported."));
503         return NULL;
504     }
505
506     tag = taglist->firstTag;
507     while(tag && i<index) {
508         tag = tag->next;
509         i++;
510     }
511     if(!tag || i != index) {
512         if(index> i+10) {
513             PyErr_SetString(PyExc_Exception, setError("No Tag at position %d", index));
514             return NULL;
515         }
516
517         mylog("taglist_item %08x(%d)->IndexError (%d)", (int)self, self->ob_refcnt, index);
518
519         Py_INCREF(PyExc_IndexError);
520         PyErr_SetObject(PyExc_IndexError, Py_None);
521         return NULL;
522     }
523
524     tagobject = TagObject_New();
525     tagobject->tag = tag;
526
527     return (PyObject*)tagobject;
528 }
529 //----------------------------------------------------------------------------
530 static void tag_dealloc(PyObject * self)
531 {
532     TagObject*tag = (TagObject*)self;
533     mylog("tag_dealoc %08x(%d)\n", (int)self, self->ob_refcnt);
534     if(tag->placeobject) {
535         swf_PlaceObjectFree(tag->placeobject);
536         tag->placeobject = 0;
537     }
538     if(tag->font) {
539         swf_FontFree(tag->font);
540         tag->font = 0;
541     }
542     if(tag->character) {
543         Py_DECREF(tag->character);
544         tag->character = 0;
545     }
546     PyObject_Del(self);
547 }
548 //----------------------------------------------------------------------------
549 static PyObject* tag_setU8(PyObject * self, PyObject*other)
550 {
551     return NULL;
552 }
553 //----------------------------------------------------------------------------
554 static PyObject* tag_setbackgroundcolor_getrgb(PyObject * self, PyObject*other)
555 {
556     TagObject*tag = (TagObject*)self;
557     int r,g,b;
558     r = tag->tag->data[0];
559     g = tag->tag->data[1];
560     b = tag->tag->data[2];
561     return Py_BuildValue("(iii)", r,g,b);
562 }
563 //----------------------------------------------------------------------------
564
565 static struct tagfunctions {
566     int id;
567     PyMethodDef f[8];
568 } tagfunctions[] =
569 {
570  { 
571    ST_SETBACKGROUNDCOLOR, 
572    {{"getRGB", tag_setbackgroundcolor_getrgb, METH_VARARGS, "get's the color set by this tag"},
573     {NULL, NULL, 0, NULL}
574    }
575  }
576 };
577 static PyMethodDef common_tagfunctions[] =
578 {{"setU8", tag_setU8, METH_VARARGS, "sets a byte to the tag data"},
579  {NULL, NULL, 0, NULL}
580 };
581
582 static PyObject* tag_getattr(PyObject * self, char* a)
583 {
584     TagObject*tag = (TagObject*)self;
585     PyObject* ret = NULL;
586     int id =  tag->tag->id;
587     int t;
588    
589     /* search for a tag specific function */
590     for(t=0;t<sizeof(tagfunctions)/sizeof(tagfunctions[0]);t++)
591     {
592         if(id==tagfunctions[t].id) {
593             mylog("tag_getattr: id %d found\n", id);
594             ret = Py_FindMethod(tagfunctions[t].f, self, a);
595             break;
596         }
597     }
598
599     /* search in the functions common to all tags */
600     FindMethodMore(ret, common_tagfunctions, self, a);
601
602     mylog("tag_getattr %08x(%d) %s: %08x\n", (int)self, self->ob_refcnt, a, ret);
603     return ret;
604 }
605 //----------------------------------------------------------------------------
606 //                     Tag Contructors
607 //----------------------------------------------------------------------------
608 static TagObject* TagObject_New()
609 {
610     TagObject*tag = PyObject_New(TagObject, &TagClass);
611     tag->font = 0;
612     tag->character = 0;
613     tag->placeobject = 0;
614     tag->tag = 0;
615     return tag;
616 }
617
618 static PyObject* f_SetBackgroundColor(PyObject* self, PyObject* args, PyObject* kwargs)
619 {
620     static char *kwlist[] = {"color", NULL};
621     int r=0,g=0,b=0;
622     TagObject*tag;
623     ColorObject*color;
624
625     /* 1st try- copy constructor */
626     if(!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &ColorClass, &color)) {
627         /* 2nd try- color's contructor */
628         color = (ColorObject*)f_Color(NULL, args, kwargs);
629     }
630     if(!color)
631         return NULL;
632
633     tag = TagObject_New();
634     tag->tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
635     swf_SetU8(tag->tag, color->rgba.r);
636     swf_SetU8(tag->tag, color->rgba.g);
637     swf_SetU8(tag->tag, color->rgba.b);
638     mylog("SetBackgroundColor(%02x,%02x,%02x) %08x -> %08x\n", color->rgba.r, color->rgba.g, color->rgba.b, (int)self, tag);
639     return (PyObject*)tag;
640 }
641 //----------------------------------------------------------------------------
642 static PyObject* f_DefineFont(PyObject* self, PyObject* args, PyObject* kwargs)
643 {
644     static char *kwlist[] = {"filename", NULL};
645     char*filename = 0;
646     TagObject*tag;
647     SWFFONT* font;
648
649     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", kwlist, &filename))
650         return NULL;
651
652     font = swf_ReadFont(filename);
653     mylog("font=%08x",font);
654     if(!font) {
655         PyErr_SetString(PyExc_Exception, setError("Could not load %s", filename));
656         return NULL;
657     }
658
659     tag = TagObject_New();
660     tag->font = font;
661     tag->tag = swf_InsertTag(0, ST_DEFINEFONT2);
662     tag->font->id = 0xabcd; // swf_SetU16(id);
663     swf_FontSetDefine2(tag->tag, tag->font); // TODO: should this be done later, in taglist?
664     mylog("DefineFont %08x -> %08x\n", (int)self, (int)tag);
665     return (PyObject*)tag;
666 }
667 //----------------------------------------------------------------------------
668 static PyObject* f_Protect(PyObject* self, PyObject* args, PyObject* kwargs)
669 {
670     static char *kwlist[] = {"password", NULL};
671     char*password = 0;
672     TagObject*tag;
673
674     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", kwlist, &password))
675         return NULL;
676
677     tag = TagObject_New();
678     tag->tag = swf_InsertTag(0, ST_PROTECT);
679     if(password) {
680         swf_SetPassword(tag->tag, password);
681     }
682     mylog("f_Protect %08x -> %08x\n", (int)self, (int)tag);
683     return (PyObject*)tag;
684 }
685 //----------------------------------------------------------------------------
686 static PyObject* f_DefineText(PyObject* self, PyObject* args, PyObject* kwargs)
687 {
688     static char *kwlist[] = {"font", "text", "size", "color", NULL};
689     TagObject*tag;
690     char*text = 0;
691     int textlen = 0;
692     PyObject*unicode16;
693     PyObject*unicode8;
694     int size = 0;
695     RGBA rgba = {0,0,0,255};
696     ColorObject*color = 0;
697     TagObject*font = 0;
698     SRECT r;
699     
700     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!u#i|O!", kwlist, &TagClass, &font, &text, &textlen, &size, &ColorClass, &color))
701         return NULL;
702     
703     unicode16 = PyUnicode_DecodeUTF16(text, textlen*2, NULL, NULL);
704     unicode8 = PyUnicode_AsUTF8String(unicode16);
705     text = PyString_AS_STRING(unicode8);
706
707     if(color)
708         rgba = color->rgba;
709
710     mylog("DefineText: text = %s", text);
711     
712     tag = TagObject_New();
713     tag ->tag= swf_InsertTag(0, ST_DEFINETEXT2);
714     swf_SetU16(tag->tag, /*ID*/0);
715     r = swf_SetDefineText(tag->tag, font->font, &rgba, text, size);
716     mylog("DefineText %08x -> %08x\n", (int)self, (int)tag);
717     return (PyObject*)tag;
718 }
719 //----------------------------------------------------------------------------
720 static PyObject* f_PlaceObject(PyObject* self, PyObject* args, PyObject* kwargs)
721 {
722     static char *kwlist[] = {"character", "depth", "matrix", "colortransform", "ratio", "name", "clipdepth", "action", NULL};
723     TagObject*tag;
724     
725     TagObject*character = 0;
726     int depth;
727     int clipdepth = 0;
728     MatrixObject*matrix = 0;
729     CXFormObject*cxform = 0;
730     int ratio = 0;
731     ActionObject*action = 0;
732     char* name = 0;
733     SWFPLACEOBJECT* po;
734     po = malloc(sizeof(SWFPLACEOBJECT));
735     memset(po, 0, sizeof(SWFPLACEOBJECT));
736
737     swf_GetPlaceObject(0, po);
738
739     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!i|O!O!isiO!", kwlist, 
740                 &TagClass, &character, 
741                 &depth, 
742                 &MatrixClass, &matrix, 
743                 &CXFormClass, &cxform,
744                 &ratio,
745                 &name,
746                 &clipdepth,
747                 &action
748                 ))
749         return NULL;
750     po->depth = depth;
751     po->id = /*ID*/ 0;
752     po->clipdepth = clipdepth;
753     po->ratio = ratio;
754     po->name = name;
755     if(clipdepth) po->matrix = matrix->matrix;
756     if(cxform) po->cxform = cxform->cxform;
757     if(action) po->actions = action->action;
758
759     tag = TagObject_New();
760     tag->placeobject = po;
761     Py_INCREF(character);
762     tag->character = (PyObject*)character;
763     tag->tag= swf_InsertTag(0, ST_PLACEOBJECT2);
764     swf_SetPlaceObject(tag->tag, po);
765     mylog("PlaceObject %08x -> %08x\n", (int)self, (int)tag);
766     return (PyObject*)tag;
767 }
768 //----------------------------------------------------------------------------
769 static PyTypeObject SWFClass = 
770 {
771     PyObject_HEAD_INIT(NULL)
772     0,
773     tp_name: "SWF",
774     tp_basicsize: sizeof(SWFObject),
775     tp_itemsize: 0,
776     tp_dealloc: swf_dealloc,
777     tp_print: swf_print,
778     tp_getattr: swf_getattr,
779     tp_setattr: swf_setattr,
780 };
781 static PySequenceMethods taglist_as_sequence =
782 {
783     sq_length: taglist_length, // len(obj)
784     sq_concat: taglist_concat, // obj += [...], obj1+obj2
785     sq_repeat: 0,            // x*n, intargfunc
786     sq_item: taglist_item,  // obj[3]
787     sq_slice: 0,             // x[i:j] intintargfunc
788     sq_ass_item: 0,          // x[i] = y intobjargproc
789     sq_ass_slice: 0,         // x[i:j] = v intintobjargproc
790     sq_contains: 0,          //???
791 };
792 static PyTypeObject TagListClass = 
793 {
794     PyObject_HEAD_INIT(NULL)
795     0,
796     tp_name: "TagList",
797     tp_basicsize: sizeof(TagListObject),
798     tp_itemsize: 0,
799     tp_dealloc: taglist_dealloc,
800     tp_print: 0,                 // print x
801     tp_getattr: taglist_getattr, // x.attr
802     tp_setattr: 0,               // x.attr = v
803     tp_compare: 0,               // x>y
804     tp_repr: 0,                  // `x`, print x
805     tp_as_number: 0,
806     tp_as_sequence: &taglist_as_sequence,
807 };
808 static PyTypeObject TagClass = 
809 {
810     PyObject_HEAD_INIT(NULL)
811     0,
812     tp_name: "Tag",
813     tp_basicsize: sizeof(TagObject),
814     tp_itemsize: 0,
815     tp_dealloc: tag_dealloc,
816     tp_print: 0,
817     tp_getattr: tag_getattr,
818 };
819 //----------------------------------------------------------------------------
820
821 static PyMethodDef SWFMethods[] = 
822 {
823     /* SWF creation*/
824     {"load", f_load, METH_VARARGS, "Load a SWF from disc."},
825     {"create", (PyCFunction)f_create, METH_KEYWORDS, "Create a new SWF from scratch."},
826     
827     /* Primitives */
828     {"Color", (PyCFunction)f_Color, METH_KEYWORDS, "Create a new color object."},
829     {"Gradient", (PyCFunction)f_Gradient, METH_KEYWORDS, "Create a new gradient object."},
830     {"ColorTransform", (PyCFunction)f_ColorTransform, METH_KEYWORDS, "Create a new colortransform object."},
831     {"Matrix", (PyCFunction)f_Matrix, METH_KEYWORDS, "Create a new matrix object."},
832     {"BBox", (PyCFunction)f_BBox, METH_KEYWORDS, "Create a new bounding box object."},
833
834     /* TAGS */
835     {"SetBackgroundColor", (PyCFunction)f_SetBackgroundColor, METH_KEYWORDS, "Create a SetBackGroundColor Tag."},
836     {"Protect", (PyCFunction)f_Protect, METH_KEYWORDS, "Create a Protect Tag."},
837     {"DefineFont", (PyCFunction)f_DefineFont, METH_KEYWORDS, "Create a DefineFont Tag."},
838     {"DefineText", (PyCFunction)f_DefineText, METH_KEYWORDS, "Create a DefineText Tag."},
839     {"PlaceObject", (PyCFunction)f_PlaceObject, METH_KEYWORDS, "Create a PlaceObject Tag."},
840     {NULL, NULL, 0, NULL}
841 };
842
843 void initSWF(void)
844 {
845     SWFClass.ob_type = &PyType_Type;
846
847     initLog("test.log",8,0,0,0,0);
848
849     (void)Py_InitModule("SWF", SWFMethods);
850 }