ca82f2431c7da90e864dc3ef2cb329017dbfc2af
[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 static PyMethodDef taglist_functions[] =
289 {{"foldAll", taglist_foldAll, METH_VARARGS, "fold all sprites (movieclips) in the list"},
290  {"unfoldAll", taglist_unfoldAll, METH_VARARGS, "unfold (expand) all sprites (movieclips) in the list"},
291  {"optimizeOrder", taglist_optimizeOrder, METH_VARARGS, "Reorder the Tag structure"},
292  {NULL, NULL, 0, NULL}
293 };
294
295 //----------------------------------------------------------------------------
296 static void swf_dealloc(PyObject* self)
297 {
298     SWFObject*swfo;
299     SWF*swf;
300     swfo = (SWFObject*)self;
301     swf = &swfo->swf;
302     mylog("swf_dealloc %08x(%d)\n", (int)self, self->ob_refcnt);
303     if(swfo->filename) {
304         free(swfo->filename);
305         swfo->filename = 0;
306     }
307     Py_DECREF(swfo->taglist);
308     swfo->taglist = 0;
309     PyObject_Del(self);
310 }
311 //----------------------------------------------------------------------------
312 static void taglist_dealloc(PyObject* self)
313 {
314     TagListObject*taglist = (TagListObject*)self;
315     SWF swf;
316     mylog("taglist_dealloc %08x(%d)\n", (int)self, self->ob_refcnt);
317     swf.firstTag = taglist->firstTag;
318     swf_FreeTags(&swf);
319     taglist->firstTag = 0;
320     taglist->lastTag = 0;
321     taglist->searchTag = 0;
322     PyObject_Del(self);
323 }
324 //----------------------------------------------------------------------------
325 static int swf_print(PyObject * self, FILE *fi, int flags) //flags&Py_PRINT_RAW
326 {
327     SWFObject*swf = (SWFObject*)self;
328     swf_DumpHeader(fi, &swf->swf);
329     //void swf_DumpSWF(FILE * f,SWF*swf);
330     mylog("print %08x(%d)\n", (int)self, self->ob_refcnt);
331     return 0;
332 }
333 //----------------------------------------------------------------------------
334 static PyObject* swf_getattr(PyObject * self, char* a)
335 {
336     SWFObject*swf = (SWFObject*)self;
337     PyObject* ret;
338
339     if(!strcmp(a, "fps")) {
340         double fps = swf->swf.frameRate/256.0;
341         mylog("swf_getattr %08x(%d) %s = %f\n", (int)self, self->ob_refcnt, a, fps);
342         return Py_BuildValue("d", fps);
343     } else if(!strcmp(a, "version")) {
344         int version = swf->swf.fileVersion;;
345         mylog("swf_getattr %08x(%d) %s = %d\n", (int)self, self->ob_refcnt, a, version);
346         return Py_BuildValue("i", version);
347     } else if(!strcmp(a, "name")) {
348         char*filename = swf->filename;
349         mylog("swf_getattr %08x(%d) %s = %s\n", (int)self, self->ob_refcnt, a, filename);
350         return Py_BuildValue("s", filename);
351     } else if(!strcmp(a, "bbox")) {
352         int xmin,ymin,xmax,ymax;
353         xmin = swf->swf.movieSize.xmin;
354         ymin = swf->swf.movieSize.ymin;
355         xmax = swf->swf.movieSize.xmax;
356         ymax = swf->swf.movieSize.ymax;
357         mylog("swf_getattr %08x(%d) %s = (%d,%d,%d,%d)\n", (int)self, self->ob_refcnt, a, xmin,ymin,xmax,ymax);
358         return Py_BuildValue("(iiii)", xmin, ymin, xmax, ymax); 
359     } else if(!strcmp(a, "tags")) {
360         PyObject*ret =  (PyObject*)(swf->taglist);
361         Py_INCREF(ret);
362         mylog("swf_getattr %08x(%d) %s = %08x(%d)\n", (int)self, self->ob_refcnt, a, ret, ret->ob_refcnt);
363         return ret;
364     }
365
366     ret = Py_FindMethod(swf_functions, self, a);
367     mylog("swf_getattr %08x(%d) %s: %08x\n", (int)self, self->ob_refcnt, a, ret);
368     return ret;
369 }
370 //----------------------------------------------------------------------------
371 static int swf_setattr(PyObject * self, char* a, PyObject * o)
372 {
373     SWFObject*swf = (SWFObject*)self;
374     if(!strcmp(a, "fps")) {
375         double fps;
376         if (!PyArg_Parse(o, "d", &fps)) 
377             goto err;
378         swf->swf.frameRate = (int)(fps*0x100);
379         mylog("swf_setattr %08x(%d) %s = %f\n", (int)self, self->ob_refcnt, a, fps);
380         return 0;
381     } else if(!strcmp(a, "version")) {
382         int version;
383         if (!PyArg_Parse(o, "i", &version)) 
384             goto err;
385         swf->swf.fileVersion = version;
386         mylog("swf_setattr %08x(%d) %s = %d\n", (int)self, self->ob_refcnt, a, version);
387         return 0;
388     } else if(!strcmp(a, "name")) {
389         char*filename;
390         if (!PyArg_Parse(o, "s", &filename)) 
391             goto err;
392         if(swf->filename) {
393             free(swf->filename);swf->filename=0;
394         }
395         swf->filename = strdup(filename);
396         mylog("swf_setattr %08x(%d) %s = %s\n", (int)self, self->ob_refcnt, a, filename);
397         return 0;
398     } else if(!strcmp(a, "bbox")) {
399         int xmin=0,ymin=0,xmax=0,ymax=0;
400         if (!PyArg_Parse(o, "(iiii)", &xmin, &ymin, &xmax, &ymax)) 
401             goto err;
402
403         swf->swf.movieSize.xmin = xmin;
404         swf->swf.movieSize.ymin = ymin;
405         swf->swf.movieSize.xmax = xmax;
406         swf->swf.movieSize.ymax = ymax;
407         mylog("swf_setattr %08x(%d) %s = (%d,%d,%d,%d)\n", (int)self, self->ob_refcnt, a, xmin,ymin,xmax,ymax);
408         return 0;
409     } else if(!strcmp(a, "tags")) {
410         TagListObject* taglist;
411         /*if (!PyArg_Parse(o, "O!", &TagListClass, &taglist));
412             goto err;*/
413         taglist = (TagListObject*)o;
414         Py_DECREF(swf->taglist);
415         swf->taglist = taglist;
416         Py_INCREF(swf->taglist);
417         mylog("swf_setattr %08x(%d) %s = %08x\n", (int)self, self->ob_refcnt, a, swf->taglist);
418         return 0;
419     }
420 err:
421     mylog("swf_setattr %08x(%d) %s = ? (%08x)\n", (int)self, self->ob_refcnt, a, o);
422     return 1;
423 }
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, i);
500
501     if(i<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     }
510     if(!tag || i != index) {
511         PyErr_SetString(PyExc_Exception, setError("No Tag at position %d", index));
512         return NULL;
513     }
514
515     tagobject = TagObject_New();
516     tagobject->tag = tag;
517
518     return (PyObject*)tagobject;
519 }
520 //----------------------------------------------------------------------------
521 static void tag_dealloc(PyObject * self)
522 {
523     TagObject*tag = (TagObject*)self;
524     mylog("tag_dealoc %08x(%d)\n", (int)self, self->ob_refcnt);
525     if(tag->placeobject) {
526         swf_PlaceObjectFree(tag->placeobject);
527         tag->placeobject = 0;
528     }
529     if(tag->font) {
530         swf_FontFree(tag->font);
531         tag->font = 0;
532     }
533     if(tag->character) {
534         Py_DECREF(tag->character);
535         tag->character = 0;
536     }
537     PyObject_Del(self);
538 }
539 //----------------------------------------------------------------------------
540 static PyObject* tag_setU8(PyObject * self, PyObject*other)
541 {
542     return NULL;
543 }
544 //----------------------------------------------------------------------------
545 static PyObject* tag_setbackgroundcolor_getrgb(PyObject * self, PyObject*other)
546 {
547     TagObject*tag = (TagObject*)self;
548     int r,g,b;
549     r = tag->tag->data[0];
550     g = tag->tag->data[1];
551     b = tag->tag->data[2];
552     return Py_BuildValue("(iii)", r,g,b);
553 }
554 //----------------------------------------------------------------------------
555
556 static struct tagfunctions {
557     int id;
558     PyMethodDef f[8];
559 } tagfunctions[] =
560 {
561  { 
562    ST_SETBACKGROUNDCOLOR, 
563    {{"getRGB", tag_setbackgroundcolor_getrgb, METH_VARARGS, "get's the color set by this tag"},
564     {NULL, NULL, 0, NULL}
565    }
566  }
567 };
568 static PyMethodDef common_tagfunctions[] =
569 {{"setU8", tag_setU8, METH_VARARGS, "sets a byte to the tag data"},
570  {NULL, NULL, 0, NULL}
571 };
572
573 static PyObject* tag_getattr(PyObject * self, char* a)
574 {
575     TagObject*tag = (TagObject*)self;
576     PyObject* ret = NULL;
577     int id =  tag->tag->id;
578     int t;
579    
580     /* search for a tag specific function */
581     for(t=0;t<sizeof(tagfunctions)/sizeof(tagfunctions[0]);t++)
582     {
583         if(id==tagfunctions[t].id) {
584             mylog("taglist_getattr: id %d found\n", id);
585             ret = Py_FindMethod(tagfunctions[t].f, self, a);
586             break;
587         }
588     }
589
590     /* search in the functions common to all tags */
591     FindMethodMore(ret, common_tagfunctions, self, a);
592
593     mylog("taglist_getattr %08x(%d) %s: %08x\n", (int)self, self->ob_refcnt, a, ret);
594     return ret;
595 }
596 //----------------------------------------------------------------------------
597 //                     Tag Contructors
598 //----------------------------------------------------------------------------
599 static TagObject* TagObject_New()
600 {
601     TagObject*tag = PyObject_New(TagObject, &TagClass);
602     tag->font = 0;
603     tag->character = 0;
604     tag->placeobject = 0;
605     tag->tag = 0;
606     return tag;
607 }
608
609 static PyObject* f_SetBackgroundColor(PyObject* self, PyObject* args, PyObject* kwargs)
610 {
611     static char *kwlist[] = {"color", NULL};
612     int r=0,g=0,b=0;
613     TagObject*tag;
614     ColorObject*color;
615
616     /* 1st try- copy constructor */
617     if(!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &ColorClass, &color)) {
618         /* 2nd try- color's contructor */
619         color = (ColorObject*)f_Color(NULL, args, kwargs);
620     }
621     if(!color)
622         return NULL;
623
624     tag = TagObject_New();
625     tag->tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
626     swf_SetU8(tag->tag, color->rgba.r);
627     swf_SetU8(tag->tag, color->rgba.g);
628     swf_SetU8(tag->tag, color->rgba.b);
629     mylog("SetBackgroundColor(%02x,%02x,%02x) %08x -> %08x\n", color->rgba.r, color->rgba.g, color->rgba.b, (int)self, tag);
630     return (PyObject*)tag;
631 }
632 //----------------------------------------------------------------------------
633 static PyObject* f_DefineFont(PyObject* self, PyObject* args, PyObject* kwargs)
634 {
635     static char *kwlist[] = {"filename", NULL};
636     char*filename = 0;
637     TagObject*tag;
638     SWFFONT* font;
639
640     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", kwlist, &filename))
641         return NULL;
642
643     font = swf_ReadFont(filename);
644     mylog("font=%08x",font);
645     if(!font) {
646         PyErr_SetString(PyExc_Exception, setError("Could not load %s", filename));
647         return NULL;
648     }
649
650     tag = TagObject_New();
651     tag->font = font;
652     tag->tag = swf_InsertTag(0, ST_DEFINEFONT2);
653     tag->font->id = 0xabcd; // swf_SetU16(id);
654     swf_FontSetDefine2(tag->tag, tag->font); // TODO: should this be done later, in taglist?
655     mylog("DefineFont %08x -> %08x\n", (int)self, (int)tag);
656     return (PyObject*)tag;
657 }
658 //----------------------------------------------------------------------------
659 static PyObject* f_DefineText(PyObject* self, PyObject* args, PyObject* kwargs)
660 {
661     static char *kwlist[] = {"font", "text", "size", "color", NULL};
662     TagObject*tag;
663     char*text = 0;
664     int textlen = 0;
665     PyObject*unicode16;
666     PyObject*unicode8;
667     int size = 0;
668     RGBA rgba = {0,0,0,255};
669     ColorObject*color = 0;
670     TagObject*font = 0;
671     SRECT r;
672     
673     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!u#i|O!", kwlist, &TagClass, &font, &text, &textlen, &size, &ColorClass, &color))
674         return NULL;
675     
676     unicode16 = PyUnicode_DecodeUTF16(text, textlen*2, NULL, NULL);
677     unicode8 = PyUnicode_AsUTF8String(unicode16);
678     text = PyString_AS_STRING(unicode8);
679
680     if(color)
681         rgba = color->rgba;
682
683     mylog("DefineText: text = %s", text);
684     
685     tag = TagObject_New();
686     tag ->tag= swf_InsertTag(0, ST_DEFINETEXT2);
687     swf_SetU16(tag->tag, /*ID*/0);
688     r = swf_SetDefineText(tag->tag, font->font, &rgba, text, size);
689     mylog("DefineText %08x -> %08x\n", (int)self, (int)tag);
690     return (PyObject*)tag;
691 }
692 //----------------------------------------------------------------------------
693 static PyObject* f_PlaceObject(PyObject* self, PyObject* args, PyObject* kwargs)
694 {
695     static char *kwlist[] = {"character", "depth", "matrix", "colortransform", "ratio", "name", "clipdepth", "action"};
696     TagObject*tag;
697     
698     TagObject*character = 0;
699     int depth;
700     int clipdepth = 0;
701     MatrixObject*matrix = 0;
702     CXFormObject*cxform = 0;
703     int ratio = 0;
704     ActionObject*action = 0;
705     char* name = 0;
706     SWFPLACEOBJECT* po;
707     po = malloc(sizeof(SWFPLACEOBJECT));
708     memset(po, 0, sizeof(SWFPLACEOBJECT));
709
710     swf_GetPlaceObject(0, po);
711
712     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!i|O!O!isiO!", kwlist, 
713                 &TagClass, &character, 
714                 &depth, 
715                 &MatrixClass, &matrix, 
716                 &CXFormClass, &cxform,
717                 &ratio,
718                 &name,
719                 &clipdepth,
720                 &action
721                 ))
722         return NULL;
723     po->depth = depth;
724     po->id = /*ID*/ 0;
725     po->clipdepth = clipdepth;
726     po->ratio = ratio;
727     po->name = name;
728     if(clipdepth) po->matrix = matrix->matrix;
729     if(cxform) po->cxform = cxform->cxform;
730     if(action) po->actions = action->action;
731
732     tag = TagObject_New();
733     tag->placeobject = po;
734     Py_INCREF(character);
735     tag->character = (PyObject*)character;
736     tag->tag= swf_InsertTag(0, ST_PLACEOBJECT2);
737     swf_SetPlaceObject(tag->tag, po);
738     mylog("PlaceObject %08x -> %08x\n", (int)self, (int)tag);
739     return (PyObject*)tag;
740 }
741 //----------------------------------------------------------------------------
742 static PyTypeObject SWFClass = 
743 {
744     PyObject_HEAD_INIT(NULL)
745     0,
746     tp_name: "SWF",
747     tp_basicsize: sizeof(SWFObject),
748     tp_itemsize: 0,
749     tp_dealloc: swf_dealloc,
750     tp_print: swf_print,
751     tp_getattr: swf_getattr,
752     tp_setattr: swf_setattr,
753 };
754 static PySequenceMethods taglist_as_sequence =
755 {
756     sq_length: taglist_length, // len(obj)
757     sq_concat: taglist_concat, // obj += [...], obj1+obj2
758     sq_repeat: 0,            // x*n, intargfunc
759     sq_item: taglist_item,  // obj[3]
760     sq_slice: 0,             // x[i:j] intintargfunc
761     sq_ass_item: 0,          // x[i] = y intobjargproc
762     sq_ass_slice: 0,         // x[i:j] = v intintobjargproc
763     sq_contains: 0,          //???
764 };
765 static PyTypeObject TagListClass = 
766 {
767     PyObject_HEAD_INIT(NULL)
768     0,
769     tp_name: "TagList",
770     tp_basicsize: sizeof(TagListObject),
771     tp_itemsize: 0,
772     tp_dealloc: taglist_dealloc,
773     tp_print: 0,                 // print x
774     tp_getattr: taglist_getattr, // x.attr
775     tp_setattr: 0,               // x.attr = v
776     tp_compare: 0,               // x>y
777     tp_repr: 0,                  // `x`, print x
778     tp_as_number: 0,
779     tp_as_sequence: &taglist_as_sequence,
780 };
781 static PyTypeObject TagClass = 
782 {
783     PyObject_HEAD_INIT(NULL)
784     0,
785     tp_name: "Tag",
786     tp_basicsize: sizeof(TagObject),
787     tp_itemsize: 0,
788     tp_dealloc: tag_dealloc,
789     tp_print: 0,
790     tp_getattr: tag_getattr,
791 };
792 //----------------------------------------------------------------------------
793
794 static PyMethodDef SWFMethods[] = 
795 {
796     /* SWF creation*/
797     {"load", f_load, METH_VARARGS, "Load a SWF from disc."},
798     {"create", (PyCFunction)f_create, METH_KEYWORDS, "Create a new SWF from scratch."},
799     
800     /* Primitives */
801     {"Color", (PyCFunction)f_Color, METH_KEYWORDS, "Create a new color object."},
802     {"Gradient", (PyCFunction)f_Gradient, METH_KEYWORDS, "Create a new gradient object."},
803     {"ColorTransform", (PyCFunction)f_ColorTransform, METH_KEYWORDS, "Create a new colortransform object."},
804     {"Matrix", (PyCFunction)f_Matrix, METH_KEYWORDS, "Create a new matrix object."},
805     {"BBox", (PyCFunction)f_BBox, METH_KEYWORDS, "Create a new bounding box object."},
806
807     /* TAGS */
808     {"SetBackgroundColor", (PyCFunction)f_SetBackgroundColor, METH_KEYWORDS, "Create a SetBackGroundColor Tag."},
809     {"DefineFont", (PyCFunction)f_DefineFont, METH_KEYWORDS, "Create a DefineFont Tag."},
810     {"DefineText", (PyCFunction)f_DefineText, METH_KEYWORDS, "Create a DefineText Tag."},
811     {"PlaceObject", (PyCFunction)f_PlaceObject, METH_KEYWORDS, "Create a PlaceObject Tag."},
812     {NULL, NULL, 0, NULL}
813 };
814
815 void initSWF(void)
816 {
817     SWFClass.ob_type = &PyType_Type;
818
819     initLog("test.log",8,0,0,0,0);
820
821     (void)Py_InitModule("SWF", SWFMethods);
822 }