Bus error fix.
[swftools.git] / src / reloc.c
1 /* reloc.h
2    Implements swf_relocate(), which changes the id range of a swf file in
3    memory.
4
5    Part of the swftools package.
6    
7    Copyright (c) 2001 Matthias Kramm <kramm@quiss.org> 
8
9    This file is distributed under the GPL, see file COPYING for details */
10
11 #include "flash.h"
12 #include "../lib/rfxswf.h"
13
14 static struct swffile file;
15
16 int slaveids[65536];
17
18 void maponeid(void*idpos)
19 {
20     u16*idptr = (u16*)idpos;
21     U16 id = GET16(idptr);
22     if(slaveids[id]<0) {
23         logf("<error> Trying to map id never encountered before: id=%d", id);
24         return ;
25     }
26     logf("<debug> mapping %d to %d", id, slaveids[id]);
27     PUT16(idptr, slaveids[id]);
28 }
29
30
31 void mapstyles(struct reader_t*reader, int num, void(*callback)(void*))
32 {
33     u16 count;
34     int t;
35     reader_resetbits(reader);
36     count = reader_readu8(reader);
37     if(count == 0xff && num>1) // defineshape2,3 only
38         count = reader_readu16(reader);
39
40 //          printf("%d fillstyles\n", count);
41     for(t=0;t<count;t++)
42     {
43         int type;
44         u8*pos;
45         pos=reader_getinputpos(reader);
46 //              printf("%02x %02x %02x %02x %02x %02x %02x %02x\n", 
47 //                      pos[0],pos[1],pos[2],pos[3],pos[4],pos[5],pos[6],pos[7]);
48         reader_resetbits(reader);
49         type = reader_readu8(reader); //type
50 //              printf("fillstyle %d is type 0x%02x\n", t, type);
51         if(type == 0) {
52 //          printf("solid fill\n");
53             if(num == 3)
54                 readRGBA(reader);
55             else 
56                 readRGB(reader);
57         }
58         else if(type == 0x10 || type == 0x12)
59         {
60 //          printf("gradient fill\n");
61             reader_resetbits(reader);
62             readMATRIX(reader);
63             reader_resetbits(reader);
64             readGRADIENT(reader, num);
65         }
66         else if(type == 0x40 || type == 0x41)
67         {
68             reader_resetbits(reader);
69             // we made it.
70 //          printf("bitmap fill:%04x\n", *(u16*)getinputpos());
71             if(GET16(reader_getinputpos(reader)) != 65535)
72                 (callback)(reader_getinputpos(reader));
73
74             reader_readu16(reader);
75             reader_resetbits(reader);
76             readMATRIX(reader);
77         }
78         else {
79             logf("<error> Unknown fillstyle:0x%02x\n",type);
80         }
81     }
82     reader_resetbits(reader);
83     count = reader_readu8(reader); // line style array
84 //          printf("%d linestyles\n", count);
85     if(count == 0xff)
86         count = reader_readu16(reader);
87     for(t=0;t<count;t++) 
88     {
89         reader_readu16(reader);
90         if(num == 3)
91             readRGBA(reader);
92         else
93             readRGB(reader);
94     }
95 }
96
97 // take a memory region which contains a tag, and
98 // map the ids inside this tag to new values
99 void map_ids_mem(u8*mem, int length, void(*callback)(void*))
100 {
101     int num=1;
102     struct swf_tag newtag_instance;
103     struct swf_tag*newtag = &newtag_instance;
104     struct reader_t reader;
105     reader_init (&reader, mem, length);
106     swf_read_tag(&reader, newtag);
107
108     switch(newtag->id)
109     {
110         case TAGID_DEFINEBUTTONCXFORM: {
111             int t;
112             struct reader_t reader;
113             callback(&newtag->data[0]); //button id
114             reader_init (&reader, newtag->data, newtag->length);
115             for(t=0;t<4;t++) {
116                 int flags;
117                 callback(&newtag->data[0]);
118                 reader_readu16(&reader); //sound id
119                 flags = reader_readu8(&reader);
120                 if(flags&1)
121                     reader_readu32(&reader); // in point
122                 if(flags&2)
123                     reader_readu32(&reader); // out points
124                 if(flags&4)
125                     reader_readu16(&reader); // loop count
126                 if(flags&8)
127                 {
128                     int npoints = reader_readu8(&reader);
129                     int s;
130                     for(s=0;s<npoints;s++)
131                     {
132                         reader_readu32(&reader);
133                         reader_readu16(&reader);
134                         reader_readu16(&reader);
135                     }
136                 }
137             }
138         } break;
139         case TAGID_DEFINEBUTTONSOUND:
140             callback(&newtag->data[0]); //button id
141         break;
142         case TAGID_PLACEOBJECT:
143             callback(&newtag->data[0]);
144         break;
145         case TAGID_PLACEOBJECT2:
146             // only if placeflaghascharacter
147             if(!(newtag->data[0]&2))
148                 break;
149             callback(&newtag->data[3]);
150         break;
151         case TAGID_REMOVEOBJECT:
152             callback(&newtag->data[0]);
153         break;
154         case TAGID_STARTSOUND:
155             callback(&newtag->data[0]);
156         break;
157         case TAGID_DEFINESPRITE: {
158             u8*mem = &newtag->data[4];
159             int len = newtag->length-4;
160
161             while(1) {
162                 u8*fmem = mem;
163                 int flen = len;
164                 struct swf_tag sprtag;
165                 struct reader_t reader;
166
167                 reader_init (&reader, mem, len);
168                 swf_read_tag (&reader, &sprtag);
169
170                 mem = reader_getinputpos(&reader);
171                 len = reader_getinputlength(&reader);
172
173                 if(sprtag.id == TAGID_END)
174                     break;
175
176                 map_ids_mem (fmem,flen,callback);
177             }
178         } 
179         break;
180         case TAGID_DEFINEBUTTON2: // has some font ids in the button records
181             num++; 
182         //fallthrough
183         case TAGID_DEFINEBUTTON: {
184             struct reader_t reader;
185             reader_init (&reader, newtag->data, newtag->length);
186             reader_readu16(&reader); //button id
187             if(num>1)
188             { 
189                 int offset;
190                 reader_readu8(&reader); //flag
191                 offset = reader_readu16(&reader); //offset
192             }
193             while(1)
194             {
195                 u16 charid;
196                 if(!reader_readu8(&reader)) //flags
197                     break; 
198                 charid = GET16(reader_getinputpos(&reader));
199                 callback(reader_getinputpos(&reader));
200                 reader_readu16(&reader); //char
201                 reader_readu16(&reader); //layer
202                 reader_resetbits(&reader);
203                 readMATRIX(&reader);
204                 if(num>1) {
205                   reader_resetbits(&reader);
206                   readCXFORM(&reader, 1);
207                 }
208             }
209             // ...
210         }
211         break;
212         case TAGID_DEFINEEDITTEXT:  {
213             u8 flags1,flags2;
214             struct reader_t reader;
215             reader_init (&reader, newtag->data, newtag->length);
216             reader_readu16(&reader); //id
217             readRECT(&reader); //bounding box
218             reader_resetbits(&reader);
219             flags1 = reader_readu8(&reader);
220             flags2 = reader_readu8(&reader);
221             if(flags1 & 128)
222                 callback(reader_getinputpos(&reader));
223         }
224         break;
225         case TAGID_DEFINETEXT2:
226             num ++;
227         case TAGID_DEFINETEXT: { 
228             int glyphbits, advancebits;
229             int id;
230             struct reader_t reader;
231             reader_init (&reader, newtag->data, newtag->length);
232             id = reader_readu16(&reader); //id
233             readRECT(&reader); //bounding box
234             reader_resetbits(&reader);
235             readMATRIX(&reader); //matrix
236             reader_resetbits(&reader);
237             glyphbits = reader_readu8(&reader); //glyphbits
238             advancebits = reader_readu8(&reader); //advancebits
239             while(1) {
240                 u16 flags;
241                 reader_resetbits(&reader);
242                 flags = reader_getbits(&reader, 8);
243                 if(!flags) break;
244                 if(flags & 128) // text style record
245                 {
246                     reader_resetbits(&reader);
247                     if(flags & 8) { // hasfont
248                         callback(reader_getinputpos(&reader));
249                         id = reader_readu16(&reader);
250                     }
251                     if(flags & 4) { // hascolor
252                         if(num==1) readRGB(&reader);
253                         else       readRGBA(&reader);
254                     }
255                     if(flags & 2) { //has x offset
256                         reader_resetbits(&reader);
257                         reader_readu16(&reader);
258                     }
259                     if(flags & 1) { //has y offset
260                         reader_resetbits(&reader);
261                         reader_readu16(&reader);
262                     }
263                     if(flags & 8) { //has height
264                         reader_resetbits(&reader);
265                         reader_readu16(&reader);
266                     }
267                 } else { // glyph record
268                     int t;
269                     reader_resetbits(&reader);
270                     for(t=0;t<flags;t++) {
271                         reader_getbits(&reader, glyphbits);
272                         reader_getbits(&reader, advancebits);
273                     }
274                 }
275             }
276             break;
277         }
278         case TAGID_DEFINEFONTINFO:
279             callback(&newtag->data[0]);
280         break;
281
282         case TAGID_DEFINESHAPE3: // these thingies might have bitmap ids in their fillstyles
283         num++; //fallthrough
284         case TAGID_DEFINESHAPE2:
285         num++; //fallthrough
286         case TAGID_DEFINESHAPE: {
287             int fillbits;
288             int linebits;
289             struct RECT r;
290             struct reader_t reader;
291             //printf("defineshape%d\n", num);
292             reader_init (&reader, newtag->data, newtag->length);
293             reader_readu16(&reader); // id;
294             r = readRECT(&reader); // bounds
295 //          printf("%d shape bounds: %d %d %d %d\n",newtag->id,r.x1,r.y1,r.x2,r.y2);
296
297             mapstyles(&reader, num, callback);
298             fillbits = reader_getbits(&reader, 4);
299             linebits = reader_getbits(&reader, 4);
300             reader_resetbits(&reader);
301             //printf("%d %d\n", fillbits, linebits);
302             while(1) {
303                 int flags;
304                 /*printf("data: %02x %02x >%02x< %02x %02x\n",
305                     ((u8*)getinputpos())[-2],
306                     ((u8*)getinputpos())[-1],
307                     ((u8*)getinputpos())[0],
308                     ((u8*)getinputpos())[1],
309                     ((u8*)getinputpos())[2]);*/
310                 flags = reader_getbits(&reader, 1);
311                 if(!flags) { //style change
312                     flags = reader_getbits(&reader, 5);
313                     //printf("style flags:%02x\n",flags);
314                     if(!flags)
315                         break;
316                     if(flags&1) { //move
317                         int n = reader_getbits(&reader, 5); 
318                         //printf("n:%d\n",n);
319                         reader_getbits(&reader, n); //x
320                         reader_getbits(&reader, n); //y
321                     }
322                     if(flags&2) { //fill0
323                         reader_getbits(&reader, fillbits); 
324                     }
325                     if(flags&4) { //fill1
326                         reader_getbits(&reader, fillbits); 
327                     }
328                     if(flags&8) { //linestyle
329                         reader_getbits(&reader, linebits); 
330                     }
331                     if(flags&16) {
332                         mapstyles(&reader, num, callback);
333                         fillbits = reader_getbits(&reader, 4);
334                         linebits = reader_getbits(&reader, 4);
335                     }
336                 } else {
337                     flags = reader_getbits(&reader, 1);
338                     //printf("edge:%d\n", flags);
339                     if(flags) { //straight edge
340                         int n = reader_getbits(&reader, 4) + 2;
341                         if(reader_getbits(&reader, 1)) { //line flag
342                             reader_getbits(&reader, n); //delta x
343                             reader_getbits(&reader, n); //delta y
344                         } else {
345                             int v=reader_getbits(&reader, 1);
346                             reader_getbits(&reader, n); //vert/horz
347                         }
348                     } else { //curved edge
349                         int n = reader_getbits(&reader, 4) + 2;
350                         reader_getbits(&reader, n);
351                         reader_getbits(&reader, n);
352                         reader_getbits(&reader, n);
353                         reader_getbits(&reader, n);
354                     }
355                 }
356             }
357         }
358         break;
359         default:
360         break;
361     }
362 }
363
364 static int*bitmap;
365
366 static int get_free_id()
367 {
368     int t;
369     for (t=1;t<65536;t++)
370     {
371         if(bitmap[t] == -1)
372         {
373             bitmap[t] = 1;
374             return t;
375         }
376     }
377     return -1;
378 }
379
380 static struct swf_tag* map_ids(struct swf_tag*tag)
381 {
382     map_ids_mem(tag->fulldata, tag->fulllength, maponeid);
383     return tag;
384 }
385
386 void swf_relocate (u8*data, int length, int*_bitmap)
387 {
388     int pos;
389     bitmap = _bitmap;
390     read_swf(&file, data, length);
391     memset(slaveids, -1, sizeof(slaveids));
392
393     pos = 0;
394     while(file.tags[pos].id != 0) {
395         struct swf_tag*tag = &file.tags[pos];
396         
397         logf("<debug> relocator: processing tag %02x", tag->id);
398         map_ids(&file.tags[pos]);
399
400         if(is_defining_tag(tag->id))
401         {
402             int newid;
403             int id;
404             
405             id = getidfromtag(tag); //own id
406
407             if(bitmap[id] < 0) { //free
408                 newid = id;
409             }
410             else {
411                 newid = get_free_id(id);
412             }
413             bitmap[newid] = 1;
414             slaveids[id] = newid;
415
416             logf("<debug> relocator: id %d mapped to %d",id, newid);
417             
418             setidintag(tag, newid);
419
420             logf("<debug> [reloc] write tag %02x (%d bytes in body)", 
421                     tag->id, tag->length);
422         } 
423         pos++;
424     }
425 }
426