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