memory management and logging fixes
[swftools.git] / lib / python / tag.c
1 #include <Python.h>
2 #undef HAVE_STAT
3 #include "../rfxswf.h"
4 #include "../log.h"
5 #include "./pyutils.h"
6 #include "primitives.h"
7 #include "action.h"
8 #include "tag.h"
9 #include "tagmap.h"
10
11 //----------------------------------------------------------------------------
12 typedef struct {
13     PyObject_HEAD
14     PyObject* tagmap;
15     TAG*tag;
16     /* ST_DEFINEFONT*/
17     SWFFONT* font;
18     /* ST_PLACEOBJECT, ST_PLACEOBJECT2*/
19     SWFPLACEOBJECT* placeobject;
20     PyObject* character;
21 } TagObject;
22
23 //----------------------------------------------------------------------------
24 static void tag_dealloc(PyObject * self)
25 {
26     TagObject*tag = (TagObject*)self;
27     if(tag->tag)
28         mylog("-%08x(%d) tag_dealoc [%s]\n", (int)self, self->ob_refcnt, swf_TagGetName(tag->tag));
29     else
30         mylog("-%08x(%d) tag_dealoc [?]\n", (int)self, self->ob_refcnt);
31     if(tag->placeobject) {
32         swf_PlaceObjectFree(tag->placeobject);
33         tag->placeobject = 0;
34     }
35     if(tag->font) {
36         swf_FontFree(tag->font);
37         tag->font = 0;
38     }
39     if(tag->character) {
40         Py_DECREF(tag->character);
41         tag->character = 0;
42     }
43     if(tag->tag) {
44         swf_DeleteTag(tag->tag);
45         tag->tag = 0;
46     }
47     Py_DECREF(tag->tagmap);
48     tag->tagmap = 0;
49     PyObject_Del(self);
50 }
51 //----------------------------------------------------------------------------
52 static PyObject* tag_setU8(PyObject * self, PyObject*other)
53 {
54     return NULL;
55 }
56 //----------------------------------------------------------------------------
57 static PyObject* tag_setbackgroundcolor_getrgb(PyObject * self, PyObject*other)
58 {
59     TagObject*tag = (TagObject*)self;
60     int r,g,b;
61     r = tag->tag->data[0];
62     g = tag->tag->data[1];
63     b = tag->tag->data[2];
64     return Py_BuildValue("(iii)", r,g,b);
65 }
66 //----------------------------------------------------------------------------
67
68 static struct tagfunctions {
69     int id;
70     PyMethodDef f[8];
71 } tagfunctions[] =
72 {
73  { 
74    ST_SETBACKGROUNDCOLOR, 
75    {{"getRGB", tag_setbackgroundcolor_getrgb, METH_VARARGS, "get's the color set by this tag"},
76     {NULL, NULL, 0, NULL}
77    }
78  }
79 };
80 static PyMethodDef common_tagfunctions[] =
81 {{"setU8", tag_setU8, METH_VARARGS, "sets a byte to the tag data"},
82  {NULL, NULL, 0, NULL}
83 };
84
85 static PyObject* tag_getattr(PyObject * self, char* a)
86 {
87     TagObject*tag = (TagObject*)self;
88     PyObject* ret = NULL;
89     int id =  tag->tag->id;
90     int t;
91
92     /* -- fields -- */
93     if(!strcmp(a, "id")) {
94         return Py_BuildValue("i", id);
95     }
96     if(!strcmp(a, "name")) {
97         char* name = swf_TagGetName(tag->tag);
98         return Py_BuildValue("s", name);
99     }
100 /*    if(!strcmp(a, "swf")) {
101         if(tag->swf == 0)
102             return Py_BuildValue("s", 0);
103         else {
104             Py_INCREF(tag->swf);
105             return tag->swf;
106         }
107     }*/
108     /* ------------ */
109    
110     /* search for a tag specific function */
111     for(t=0;t<sizeof(tagfunctions)/sizeof(tagfunctions[0]);t++)
112     {
113         if(id==tagfunctions[t].id) {
114             mylog(" %08x(%d) tag_getattr: id %d found\n", (int)self, self->ob_refcnt, id);
115             ret = Py_FindMethod(tagfunctions[t].f, self, a);
116             if(!ret) return ret;
117             ret = FindMethodMore(ret, common_tagfunctions, self, a);
118             mylog(" %08x(%d) tag_getattr %s: %08x\n", (int)self, self->ob_refcnt, a, ret);
119             return ret;
120         }
121     }
122    
123     ret = Py_FindMethod(common_tagfunctions, self, a);
124
125     mylog(" %08x(%d) tag_getattr %s: %08x\n", (int)self, self->ob_refcnt, a, ret);
126     return ret;
127 }
128 //----------------------------------------------------------------------------
129 //                     Tag Contructors
130 //----------------------------------------------------------------------------
131 PyObject* tag_new()
132 {
133     TagObject*tag = PyObject_New(TagObject, &TagClass);
134     mylog("+%08x(%d) tag_new\n", (int)tag, tag->ob_refcnt);
135     tag->font = 0;
136     tag->character = 0;
137     tag->placeobject = 0;
138     tag->tag = 0;
139     tag->tagmap = tagmap_new();
140     return (PyObject*)tag;
141 }
142 PyObject* tag_new2(TAG*t, PyObject* tagmap)
143 {
144     TagObject*tag = PyObject_New(TagObject, &TagClass);
145     mylog("+%08x(%d) tag_new tag=%08x\n", (int)tag, tag->ob_refcnt, t);
146     tag->font = 0;
147     tag->character = 0;
148     tag->placeobject = 0;
149     tag->tagmap = tagmap_new();
150     // copy tag
151     tag->tag = swf_InsertTag(0, t->id);
152     swf_SetBlock(tag->tag, t->data, t->len);
153     t = tag->tag;
154     
155     int num = swf_GetNumUsedIDs(t);
156     int * positions = malloc(num*sizeof(int));
157     swf_GetUsedIDs(t, positions);
158     int i;
159     for(i=0;i<num;i++) {
160         int id = GET16(&t->data[positions[i]]);
161         PyObject*obj = tagmap_id2obj(tagmap, id);
162         if(obj==NULL) {
163             PyErr_SetString(PyExc_Exception, setError("TagID %d not defined", id));
164             return NULL;
165         }
166         tagmap_addMapping(tag->tagmap, id, obj);
167     }
168     free(positions);
169     return (PyObject*)tag;
170 }
171
172 static PyObject* f_SetBackgroundColor(PyObject* self, PyObject* args, PyObject* kwargs)
173 {
174     static char *kwlist[] = {"color", NULL};
175     int r=0,g=0,b=0;
176     TagObject*tag;
177     PyObject*color;
178     
179     tag = (TagObject*)tag_new();
180
181     /* 1st try- copy constructor */
182     if(!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &ColorClass, &color)) {
183         /* 2nd try- color's contructor */
184         color = f_Color(NULL, args, kwargs);
185     }
186     if(!color)
187         return NULL;
188
189     tag->tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
190     RGBA rgba = color_getRGBA(color);
191     swf_SetU8(tag->tag, rgba.r);
192     swf_SetU8(tag->tag, rgba.g);
193     swf_SetU8(tag->tag, rgba.b);
194     mylog(" %08x(%d) SetBackgroundColor(%02x,%02x,%02x) (colorobj=%08x(%d))\n", (int)tag, tag->ob_refcnt, rgba.r, rgba.g, rgba.b, color, color->ob_refcnt);
195     return (PyObject*)tag;
196 }
197 //----------------------------------------------------------------------------
198 static PyObject* f_DefineFont(PyObject* self, PyObject* args, PyObject* kwargs)
199 {
200     static char *kwlist[] = {"filename", NULL};
201     char*filename = 0;
202     TagObject*tag;
203     SWFFONT* font;
204
205     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", kwlist, &filename))
206         return NULL;
207
208     font = swf_LoadFont(filename);
209     if(!font) {
210         PyErr_SetString(PyExc_Exception, setError("Could not load %s", filename));
211         return NULL;
212     }
213
214     tag = (TagObject*)tag_new();
215     tag->font = font;
216     tag->tag = swf_InsertTag(0, ST_DEFINEFONT2);
217     tag->font->id = 0;
218     swf_FontSetDefine2(tag->tag, tag->font);
219     mylog("+%08x(%d) DefineFont\n", (int)tag, tag->ob_refcnt);
220     return (PyObject*)tag;
221 }
222 static SWFFONT* fonttag_getSWFFONT(PyObject*self)
223 {
224     PY_ASSERT_TYPE(self, &TagClass);
225     TagObject*font = (TagObject*)self;
226     return font->font;
227 }
228 //----------------------------------------------------------------------------
229 static PyObject* f_Protect(PyObject* self, PyObject* args, PyObject* kwargs)
230 {
231     static char *kwlist[] = {"password", NULL};
232     char*password = 0;
233     TagObject*tag;
234
235     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", kwlist, &password))
236         return NULL;
237
238     tag = (TagObject*)tag_new();
239     tag->tag = swf_InsertTag(0, ST_PROTECT);
240     if(password) {
241         swf_SetPassword(tag->tag, password);
242     }
243     mylog("+%08x(%d) f_Protect", (int)tag, tag->ob_refcnt);
244     return (PyObject*)tag;
245 }
246 //----------------------------------------------------------------------------
247 static PyObject* f_DefineText(PyObject* self, PyObject* args, PyObject* kwargs)
248 {
249     static char *kwlist[] = {"font", "text", "size", "color", NULL};
250     TagObject*tag = 0;
251     char*text = 0;
252     int textlen = 0;
253     PyObject*unicode16;
254     PyObject*unicode8;
255     int size = 0;
256     RGBA rgba = {255,0,0,0};
257     PyObject*color = 0;
258     PyObject*font = 0;
259     SRECT r;
260
261     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!u#i|O!", kwlist, &TagClass, &font, &text, &textlen, &size, &ColorClass, &color))
262         return NULL;
263     
264     unicode16 = PyUnicode_DecodeUTF16(text, textlen*2, NULL, NULL);
265     unicode8 = PyUnicode_AsUTF8String(unicode16);
266     text = PyString_AS_STRING(unicode8);
267
268     if(color)
269         rgba = color_getRGBA(color);
270
271     mylog("DefineText: text = %s", text);
272     
273     tag = (TagObject*)tag_new();
274
275     int font_id = tagmap_add(tag->tagmap, font); // add dependency on font
276
277     fonttag_getSWFFONT(font)->id = font_id;
278
279     tag ->tag= swf_InsertTag(0, ST_DEFINETEXT2);
280     swf_SetU16(tag->tag, /*ID*/0);
281     r = swf_SetDefineText(tag->tag, fonttag_getSWFFONT(font), &rgba, text, size);
282     mylog("+%08x(%d) DefineText tag=%08x \n", (int)tag, tag->ob_refcnt);
283     
284     //Py_DECREF(unicode16);
285     //Py_DECREF(unicode8);
286     //free(text);
287
288     return (PyObject*)tag;
289 }
290 //----------------------------------------------------------------------------
291 static PyObject* f_PlaceObject(PyObject* self, PyObject* args, PyObject* kwargs)
292 {
293     static char *kwlist[] = {"character", "depth", "matrix", "colortransform", "ratio", "name", "clipdepth", "action", NULL};
294     TagObject*tag;
295     
296     TagObject*character = 0;
297     int depth;
298     int clipdepth = 0;
299     PyObject*matrix = 0;
300     PyObject*cxform = 0;
301     PyObject*action = 0;
302     int ratio = 0;
303     char* name = 0;
304     SWFPLACEOBJECT* po;
305     po = malloc(sizeof(SWFPLACEOBJECT));
306     memset(po, 0, sizeof(SWFPLACEOBJECT));
307
308     swf_GetPlaceObject(0, po);
309
310     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!i|O!O!isiO!", kwlist, 
311                 &TagClass, &character, 
312                 &depth, 
313                 &MatrixClass, &matrix, 
314                 &CXFormClass, &cxform,
315                 &ratio,
316                 &name,
317                 &clipdepth,
318                 &ActionClass, &action
319                 ))
320         return NULL;
321     po->depth = depth;
322     po->id = /*ID*/ 0;
323     po->clipdepth = clipdepth;
324     po->ratio = ratio;
325     po->name = name;
326     if(clipdepth) po->clipdepth = clipdepth;
327     if(matrix) po->matrix = matrix_getMatrix(matrix);
328     if(cxform) po->cxform = colortransform_getCXForm(cxform);
329     if(action) po->actions = action_getAction(action);
330
331     tag = (TagObject*)tag_new();
332     tag->placeobject = po;
333     Py_INCREF(character);
334     tag->character = (PyObject*)character;
335     tag->tag= swf_InsertTag(0, ST_PLACEOBJECT2);
336
337     po->id = tagmap_add(tag->tagmap,(PyObject*)character);
338
339     swf_SetPlaceObject(tag->tag, po);
340     mylog("+%08x(%d) PlaceObject %08x(%d)\n", (int)tag, tag->ob_refcnt, character, character->ob_refcnt);
341
342     return (PyObject*)tag;
343 }
344
345 /* serialize */
346 TAG* tag_getTAG(PyObject*self, TAG*prevTag, PyObject*tagmap)
347 {
348     TagObject*tag = (TagObject*)self;
349     
350     mylog(" %08x(%d) tag_getTAG: tag=%08x id=%d (%s)", (int)self, self->ob_refcnt, tag->tag, tag->tag->id, swf_TagGetName(tag->tag));
351
352     TAG* t = swf_InsertTag(prevTag, tag->tag->id);
353     swf_SetBlock(t, tag->tag->data, tag->tag->len);
354     
355     if(swf_isDefiningTag(t)) {
356         int newid = tagmap_add(tagmap, self);
357         swf_SetDefineID(t, newid);
358     }
359
360     int num = swf_GetNumUsedIDs(t);
361     int * positions = malloc(num*sizeof(int));
362     swf_GetUsedIDs(t, positions);
363     int i;
364     for(i=0;i<num;i++) {
365         int id = GET16(&t->data[positions[i]]);
366         PyObject* obj =  tagmap_id2obj(tag->tagmap, id);
367         if(obj==NULL) {
368             PyErr_SetString(PyExc_Exception, setError("Internal error: id %d not known in taglist:"));
369             free(positions);
370             return 0;
371         }
372         int newid = tagmap_obj2id(tagmap, obj);
373         PUT16(&t->data[positions[i]], newid);
374     }
375     free(positions);
376     return t;
377 }
378
379 PyObject* tag_getDependencies(PyObject*self)
380 {
381     TagObject*tag = (TagObject*)self;
382     mylog(" %08x(%d) tag_getDependencies id=%d tag=%s\n", (int)self, self->ob_refcnt, tag->tag->id, swf_TagGetName(tag->tag));
383     return tagmap_getObjectList(tag->tagmap);
384 }
385
386 int tag_print (PyObject * self, FILE * fi, int flags)
387 {
388     mylog(" %08x(%d) tag_print flags=%08x\n", (int)self, self->ob_refcnt, flags);
389     return 0;
390 }
391
392 PyTypeObject TagClass = 
393 {
394     PyObject_HEAD_INIT(NULL)
395     0,
396     tp_name: "Tag",
397     tp_basicsize: sizeof(TagObject),
398     tp_itemsize: 0,
399     tp_dealloc: tag_dealloc,
400     tp_print: tag_print,
401     tp_getattr: tag_getattr,
402 };
403 static PyMethodDef TagMethods[] = 
404 {
405     /* TAGS */
406     {"SetBackgroundColor", (PyCFunction)f_SetBackgroundColor, METH_KEYWORDS, "Create a SetBackGroundColor Tag."},
407     {"Protect", (PyCFunction)f_Protect, METH_KEYWORDS, "Create a Protect Tag."},
408     {"DefineFont", (PyCFunction)f_DefineFont, METH_KEYWORDS, "Create a DefineFont Tag."},
409     {"DefineText", (PyCFunction)f_DefineText, METH_KEYWORDS, "Create a DefineText Tag."},
410     {"PlaceObject", (PyCFunction)f_PlaceObject, METH_KEYWORDS, "Create a PlaceObject Tag."},
411     {NULL, NULL, 0, NULL}
412 };
413 PyMethodDef* tag_getMethods()
414 {
415     TagClass.ob_type = &PyType_Type;
416     return TagMethods;
417 }
418