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