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