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