fixed tag organisation, started video stuff
[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
13 typedef struct _TagObject {
14     PyObject_HEAD
15     tag_internals_t internals;
16 } TagObject;
17
18 //----------------------------------------------------------------------------
19 static PyMethodDef generic_methods[] = 
20 {
21   {NULL, NULL, 0, NULL}
22 };
23 static tag_internals_t generic_tag =
24 {
25     parse: 0,
26     dealloc: 0,
27     fillTAG: 0,
28     tagfunctions: generic_methods,
29     datasize: 0,
30 };
31 //----------------------------------------------------------------------------
32
33 static struct tag_parser {
34     int id;
35     tag_internals_t*spec;
36     struct tag_parser* next;
37 } tag_parsers[1024];
38 static char parsers_initialized = 0;
39
40 void register_tag(int id, tag_internals_t*spec)
41 {
42     assert(id>=0 && id<1024);
43     if(!parsers_initialized) {
44         memset(tag_parsers, 0, sizeof(tag_parsers));
45         parsers_initialized = 1;
46     }
47     tag_parsers[id].id = id;
48     tag_parsers[id].spec = spec;
49 };
50
51 static tag_internals_t* get_parser(int id)
52 {
53     if(parsers_initialized<2) {
54         int t;
55         struct tag_parser*last = &tag_parsers[0];
56         for(t=0;t<1024;t++) {
57             if(tag_parsers[t].spec) {
58                 last->next = &tag_parsers[t];
59                 last = &tag_parsers[t];
60             }
61         }
62         parsers_initialized = 2;
63     }
64     assert(id>=0 && id<1024);
65     return tag_parsers[id].spec;
66 }
67
68 //----------------------------------------------------------------------------
69 static void tag_dealloc(PyObject * self)
70 {
71     TagObject*tag = (TagObject*)self;
72     if(tag->internals.tag)
73         mylog("-%08x(%d) tag_dealoc [%s]\n", (int)self, self->ob_refcnt, swf_TagGetName(tag->internals.tag));
74     else
75         mylog("-%08x(%d) tag_dealoc [?]\n", (int)self, self->ob_refcnt);
76     if(tag->internals.dealloc) {
77         if(!tag->internals.data)
78             mylog("-%08x(%d) tag_dealoc: Warning: calling dealloc without any data(?)\n", (int)self, self->ob_refcnt);
79         tag->internals.dealloc(&tag->internals);
80     }
81     if(tag->internals.data) {
82         free(tag->internals.data);
83         tag->internals.data = 0;
84     }
85     if(tag->internals.tag) {
86         swf_DeleteTag(tag->internals.tag);
87         tag->internals.tag = 0;
88     }
89     Py_DECREF(tag->internals.tagmap);
90     tag->internals.tagmap = 0;
91     PyObject_Del(self);
92 }
93 //----------------------------------------------------------------------------
94 static PyObject* tag_setU8(PyObject * self, PyObject*other)
95 {
96     return NULL;
97 }
98 //----------------------------------------------------------------------------
99 static PyMethodDef common_tagfunctions[] =
100 {{"setU8", tag_setU8, METH_VARARGS, "sets a byte to the tag data"},
101  {NULL, NULL, 0, NULL}
102 };
103
104 static int fillTAG(PyObject*self) 
105 {
106     TagObject*tag = (TagObject*)self;
107     if(tag->internals.tag)
108         return 1;
109     if(!tag->internals.fillTAG) {
110         PyErr_SetString(PyExc_Exception, setError("No way to fill TAG with data"));
111         return 0;
112     }
113     if(!tag->internals.fillTAG(&tag->internals)) {
114         return 0; // pass through exception
115     }
116     if(!tag->internals.tag) {
117         PyErr_SetString(PyExc_Exception, setError("Couldn't fill tag"));
118         return 0;
119     }
120     return 1;
121 }
122 static PyObject* tag_getattr(PyObject * self, char* a)
123 {
124     TagObject*tag = (TagObject*)self;
125     PyObject* ret = NULL;
126     int t;
127
128     /* -- fields -- */
129     if(!strcmp(a, "tagid")) {
130         if(!fillTAG(self))
131             return 0;
132         return Py_BuildValue("i", tag->internals.tag->id);
133     }
134     if(!strcmp(a, "name")) {
135         if(!fillTAG(self))
136             return 0;
137         char* name = swf_TagGetName(tag->internals.tag);
138         return Py_BuildValue("s", name);
139     }
140     
141     /* search for a tag specific function */
142     if(tag->internals.tagfunctions) {
143         mylog(" %08x(%d) tag_getattr: tag has specific functions\n", (int)self, self->ob_refcnt);
144         ret = Py_FindMethod(tag->internals.tagfunctions, self, a);
145         if(!ret) return ret;
146         ret = FindMethodMore(ret, common_tagfunctions, self, a);
147         mylog(" %08x(%d) tag_getattr %s: %08x\n", (int)self, self->ob_refcnt, a, ret);
148         return ret;
149     }
150    
151     ret = Py_FindMethod(common_tagfunctions, self, a);
152
153     mylog(" %08x(%d) tag_getattr %s: %08x\n", (int)self, self->ob_refcnt, a, ret);
154     return ret;
155 }
156 //----------------------------------------------------------------------------
157 //                     Tag Constructors
158 //----------------------------------------------------------------------------
159 PyObject* tag_new(tag_internals_t*tag_internals)
160 {
161     TagObject*tag = PyObject_New(TagObject, &TagClass);
162     mylog("+%08x(%d) tag_new\n", (int)tag, tag->ob_refcnt);
163     memcpy(&tag->internals, tag_internals, sizeof(tag_internals_t));
164     if(tag->internals.datasize) {
165         tag->internals.data = malloc(tag->internals.datasize);
166         memset(tag->internals.data , 0, tag->internals.datasize);
167     } else {
168         tag->internals.data = 0;
169     }
170     tag->internals.tag = 0;
171     tag->internals.tagmap = tagmap_new();
172
173     return (PyObject*)tag;
174 }
175 PyObject* tag_new2(TAG*t, PyObject* tagmap)
176 {
177     TagObject*tag = PyObject_New(TagObject, &TagClass);
178     mylog("+%08x(%d) tag_new2 tag=%08x id=%d (%s)\n", (int)tag, tag->ob_refcnt, t, t->id, swf_TagGetName(t));
179     
180     PyObject*mytagmap = tagmap_new();
181
182     int num = swf_GetNumUsedIDs(t);
183     if(num) { // tag has dependencies
184         int * positions = malloc(num*sizeof(int));
185         swf_GetUsedIDs(t, positions);
186         int i;
187         for(i=0;i<num;i++) {
188             int id = GET16(&t->data[positions[i]]);
189             PyObject*obj = tagmap_id2obj(tagmap, id);
190             if(obj==NULL) {
191                 PyErr_SetString(PyExc_Exception, setError("TagID %d not defined", id));
192                 return NULL;
193             }
194             //mylog("+%08x(%d) tag_new2 handling id %d at %d/%d\n", (int)tag, tag->ob_refcnt, id, positions[i], t->len);
195             //mylog("+%08x(%d) tag_new2 add dependency %d to id %d, object %08x(%d)\n", (int)tag, tag->ob_refcnt, i, id, obj, obj->ob_refcnt);
196             tagmap_addMapping(mytagmap, id, obj);
197         }
198         free(positions);
199     }
200
201     tag_internals_t*spec = get_parser(t->id);
202     if(spec) {
203         memcpy(&tag->internals, spec, sizeof(tag_internals_t));
204     } else {
205         memcpy(&tag->internals, &generic_tag, sizeof(tag_internals_t));
206     }
207     if(tag->internals.datasize) {
208         tag->internals.data = malloc(tag->internals.datasize);
209         memset(tag->internals.data, 0, tag->internals.datasize);
210     } else {
211         tag->internals.data = 0;
212     }
213     tag->internals.tag = swf_InsertTag(0, t->id);
214     swf_SetBlock(tag->internals.tag, t->data, t->len);
215     tag->internals.tagmap = mytagmap;
216
217     // call tag->internals.init()?
218
219     return (PyObject*)tag;
220 }
221 //----------------------------------------------------------------------------
222 /* serialize */
223 TAG* tag_getTAG(PyObject*self, TAG*prevTag, PyObject*tagmap)
224 {
225     TagObject*tag = (TagObject*)self;
226
227     if(!fillTAG(self))
228         return 0;
229     mylog(" %08x(%d) tag_getTAG: tag=%08x id=%d (%s)", (int)self, self->ob_refcnt, tag->internals.tag, tag->internals.tag->id, swf_TagGetName(tag->internals.tag));
230
231     TAG* t = swf_InsertTag(prevTag, tag->internals.tag->id);
232     swf_SetBlock(t, tag->internals.tag->data, tag->internals.tag->len);
233     
234     if(swf_isDefiningTag(t)) {
235         int newid = tagmap_add(tagmap, self);
236         swf_SetDefineID(t, newid);
237     }
238
239     int num = swf_GetNumUsedIDs(t);
240     if(num) { // tag has dependencies
241         int * positions = malloc(num*sizeof(int));
242         swf_GetUsedIDs(t, positions);
243         int i;
244         for(i=0;i<num;i++) {
245             int id = GET16(&t->data[positions[i]]);
246             PyObject* obj =  tagmap_id2obj(tag->internals.tagmap, id);
247             if(obj==NULL) {
248                 PyErr_SetString(PyExc_Exception, setError("Internal error: id %d not known in taglist:"));
249                 free(positions);
250                 return 0;
251             }
252             int newid = tagmap_obj2id(tag->internals.tagmap, obj);
253             PUT16(&t->data[positions[i]], newid);
254         }
255         free(positions);
256     }
257     return t;
258 }
259 //----------------------------------------------------------------------------
260 tag_internals_t* tag_getinternals(PyObject*self)
261 {
262     TagObject*tag = (TagObject*)self;
263     mylog(" %08x(%d) tag_getInternals\n", (int)self, self->ob_refcnt);
264     return &tag->internals;
265 }
266 //----------------------------------------------------------------------------
267 PyObject* tag_getDependencies(PyObject*self)
268 {
269     TagObject*tag = (TagObject*)self;
270     mylog(" %08x(%d) tag_getDependencies\n", (int)self, self->ob_refcnt);
271     return tagmap_getObjectList(tag->internals.tagmap);
272 }
273 //----------------------------------------------------------------------------
274 int tag_print(PyObject * self, FILE * fi, int flags)
275 {
276     TagObject*tag = (TagObject*)self;
277     mylog(" %08x(%d) tag_print flags=%08x\n", (int)self, self->ob_refcnt, flags);
278     if(!fillTAG(self))
279         return -1;
280         fprintf(fi, "tag-%08x-%d-%s", (int)tag->internals.tag, tag->internals.tag->id, swf_TagGetName(tag->internals.tag));
281     return 0;
282 }
283 //----------------------------------------------------------------------------
284 PyTypeObject TagClass = 
285 {
286     PyObject_HEAD_INIT(NULL)
287     0,
288     tp_name: "Tag",
289     tp_basicsize: sizeof(TagObject),
290     tp_itemsize: 0,
291     tp_dealloc: tag_dealloc,
292     tp_print: tag_print,
293     tp_getattr: tag_getattr,
294 };