* fixed relocation of definebutton.
[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
18 void map_ids_mem(u8*mem, int length);
19 static struct swf_tag* map_ids(struct swf_tag*tag)
20 {
21     map_ids_mem(tag->fulldata, tag->fulllength);
22     return tag;
23 }
24
25 void maponeid(void*idpos)
26 {
27     u16*idptr = (u16*)idpos;
28     if(slaveids[*idptr]<0) {
29         logf("<error> Trying to map id never encountered before: id=%d", *idptr);
30         return ;
31     }
32     logf("<debug> mapping %d to %d", *idptr, slaveids[*idptr]);
33     *idptr =  slaveids[*idptr];
34 }
35
36
37 // take a memory region which contains a tag, and
38 // map the ids inside this tag to new values
39 void map_ids_mem(u8*mem, int length)
40 {
41     int num=1;
42     struct swf_tag newtag_instance;
43     struct swf_tag*newtag = &newtag_instance;
44     reader_init (mem, length);
45     swf_read_tag(newtag);
46
47     switch(newtag->id)
48     {
49         case TAGID_PLACEOBJECT:
50             maponeid(&newtag->data[0]);
51         break;
52         case TAGID_PLACEOBJECT2:
53             // only if placeflaghascharacter
54             if(!(newtag->data[0]&2))
55                 break;
56             maponeid(&newtag->data[3]);
57         break;
58         case TAGID_REMOVEOBJECT:
59             maponeid(&newtag->data[0]);
60         break;
61         case TAGID_STARTSOUND:
62             maponeid(&newtag->data[0]);
63         break;
64         case TAGID_DEFINESPRITE: {
65             u8*mem = &newtag->data[4];
66             int len = newtag->length-4;
67
68             while(1) {
69                 u8*fmem = mem;
70                 int flen = len;
71                 struct swf_tag sprtag;
72
73                 reader_init (mem, len);
74                 swf_read_tag (&sprtag);
75
76                 mem = getinputpos();
77                 len = getinputlength();
78
79                 if(sprtag.id == TAGID_END)
80                     break;
81
82                 map_ids_mem (fmem,flen);
83             }
84         } 
85         break;
86         case TAGID_DEFINEBUTTON2: // has some font ids in the button records
87             num++; 
88         //fallthrough
89         case TAGID_DEFINEBUTTON:
90             reader_init (newtag->data, newtag->length);
91             readu16(); //button id
92             if(num>1)
93             { 
94                 readu8(); //flag
95                 readu16(); //offset
96             }
97             while(1)
98             {
99                 u16 charid;
100                 if(!readu8()) //flags
101                     break; 
102                 charid = *(u16*)getinputpos();
103                 maponeid(getinputpos());
104                 readu16(); //char
105                 readu16(); //layer
106                 readMATRIX();
107                 if(num>1)
108                   readCXFORM();
109             }
110             // ...
111         break;
112         case TAGID_DEFINEEDITTEXT:  {
113             u8 flags1,flags2;
114             reader_init (newtag->data, newtag->length);
115             readu16(); //id
116             readRECT(); //bounding box
117             resetbits();
118             flags1 = readu8();
119             flags2 = readu8();
120             if(flags1 & 128)
121                 maponeid(getinputpos());
122         }
123         break;
124         case TAGID_DEFINETEXT2:
125             num ++;
126         case TAGID_DEFINETEXT: { 
127             int glyphbits, advancebits;
128             int id;
129             reader_init (newtag->data, newtag->length);
130             id = readu16(); //id
131             readRECT(); //bounding box
132             readMATRIX(); //matrix
133             resetbits();
134             glyphbits = readu8(); //glyphbits
135             advancebits = readu8(); //advancebits
136             while(1) {
137                 u16 flags;
138                 resetbits();
139                 flags = getbits(8);
140                 if(!flags) break;
141                 if(flags & 128) // text style record
142                 {
143                     resetbits();
144                     if(flags & 8) { // hasfont
145                         maponeid(getinputpos());
146                         id = readu16();
147                     }
148                     if(flags & 4) { // hascolor
149                         if(num==1) readRGB();
150                         else       readRGBA();
151                     }
152                     if(flags & 2) { //has x offset
153                         resetbits();
154                         readu16();
155                     }
156                     if(flags & 1) { //has y offset
157                         resetbits();
158                         readu16();
159                     }
160                     if(flags & 8) { //has height
161                         resetbits();
162                         readu16();
163                     }
164                 } else { // glyph record
165                     int t;
166                     resetbits();
167                     for(t=0;t<flags;t++) {
168                         getbits(glyphbits);
169                         getbits(advancebits);
170                     }
171                 }
172             }
173             break;
174         }
175         case TAGID_DEFINEFONTINFO:
176             maponeid(&newtag->data[0]);
177         break;
178
179         case TAGID_DEFINESHAPE3: // these thingies might have bitmap ids in their fillstyles
180         num++; //fallthrough
181         case TAGID_DEFINESHAPE2:
182         num++; //fallthrough
183         case TAGID_DEFINESHAPE: {
184             u16 count;
185             int t;
186             struct RECT r;
187             reader_init (newtag->data, newtag->length);
188             readu16(); // id;
189             r = readRECT(); // bounds
190 //          printf("%d shape bounds: %d %d %d %d\n",newtag->id,r.x1,r.y1,r.x2,r.y2);
191             resetbits();
192             count = readu8();
193             if(count == 0xff && num>1) // defineshape2,3 only
194                 count = readu16();
195 //          printf("%d fillstyles\n", count);
196             for(t=0;t<count;t++)
197             {
198                 int type;
199                 u8*pos;
200                 pos=getinputpos();
201 //              printf("%02x %02x %02x %02x %02x %02x %02x %02x\n", 
202 //                      pos[0],pos[1],pos[2],pos[3],pos[4],pos[5],pos[6],pos[7]);
203                 resetbits();
204                 type = readu8(); //type
205 //              printf("fillstyle %d is type 0x%02x\n", t, type);
206                 if(type == 0) {
207                     if(num == 3)
208                         readRGBA();
209                     else 
210                         readRGB();
211                 }
212                 if(type == 0x10 || type == 0x12)
213                 {
214                     readMATRIX();
215                     resetbits();
216                     readGRADIENT(num);
217                 }
218                 if(type == 0x40 || type == 0x41)
219                 {
220                     resetbits();
221                     // we made it.
222                     if(*(u16*)getinputpos() != 65535)
223                         maponeid(getinputpos());
224
225                     readu16();
226                     readMATRIX();
227                 }
228                 //...
229             }
230         }
231         break;
232         default:
233         break;
234     }
235 }
236
237 static int*bitmap;
238
239 static int get_free_id()
240 {
241     int t;
242     for (t=1;t<65536;t++)
243     {
244         if(bitmap[t] == -1)
245         {
246             bitmap[t] = 1;
247             return t;
248         }
249     }
250     return -1;
251 }
252
253 void swf_relocate (u8*data, int length, int*_bitmap)
254 {
255     int pos;
256     bitmap = _bitmap;
257     read_swf(&file, data, length);
258     memset(slaveids, -1, sizeof(slaveids));
259
260     pos = 0;
261     while(file.tags[pos].id != 0) {
262         struct swf_tag*tag = &file.tags[pos];
263         
264         logf("<debug> relocator: processing tag %02x", tag->id);
265         map_ids(&file.tags[pos]);
266
267         if(is_defining_tag(tag->id))
268         {
269             int newid;
270             int id;
271             
272             id = getidfromtag(tag); //own id
273
274             if(bitmap[id] < 0) { //free
275                 newid = id;
276             }
277             else {
278                 newid = get_free_id(id);
279             }
280             bitmap[newid] = 1;
281             slaveids[id] = newid;
282
283             logf("<debug> relocator: id %d mapped to %d",id, newid);
284             
285             setidintag(tag, newid);
286
287             logf("<debug> [reloc] write tag %02x (%d bytes in body)", 
288                     tag->id, tag->length);
289         } 
290         pos++;
291     }
292 }
293