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