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