0178bf06407b8de49a5e156d65321b7bd491e8dd
[swftools.git] / lib / modules / swftools.c
1 /* swftools.c
2
3    Math and matrix functions, misc tools
4
5    Extension module for the rfxswf library.
6    Part of the swftools package.
7
8    Copyright (c) 2000, 2001 Rainer Böhme <rfxswf@reflex-studio.de>
9  
10    This file is distributed under the GPL, see file COPYING for details 
11
12 */
13
14 // Matrix & Math tools for SWF files
15
16 #define S64 long long
17 SFIXED RFXSWF_SP(SFIXED a1,SFIXED a2,SFIXED b1,SFIXED b2)
18 { S64 a;
19   a = (S64)a1*(S64)b1+(S64)a2*(S64)b2;
20   return (SFIXED)(a>>16);
21 }
22 SFIXED RFXSWF_QFIX(int zaehler,int nenner) // bildet Quotient von zwei INTs in SFIXED
23 { S64 z = zaehler<<16;
24   S64 a = z/(S64)nenner;
25   return (SFIXED)a;
26 }
27 #undef S64
28
29 MATRIX * swf_MatrixJoin(MATRIX * d,MATRIX * s1,MATRIX * s2)
30 {        
31   if (!d) return NULL;
32   if (!s1) return (s2)?(MATRIX *)memcpy(d,s2,sizeof(MATRIX)):NULL;
33   if (!s2) return (MATRIX *)memcpy(d,s1,sizeof(MATRIX));
34   
35   d->tx = s1->tx + s2->tx;
36   d->ty = s1->ty + s2->ty;
37   
38   d->sx = RFXSWF_SP(s1->sx,s1->r1,s2->sx,s2->r0);
39   d->sy = RFXSWF_SP(s1->r0,s1->sy,s2->r1,s2->sy);
40   d->r0 = RFXSWF_SP(s1->r0,s1->sy,s2->sx,s2->r0);
41   d->r1 = RFXSWF_SP(s1->sx,s1->r1,s2->r1,s2->sy);
42
43   //DumpMatrix(NULL,d);
44   
45   return d;
46 }
47
48 MATRIX * swf_MatrixMapTriangle(MATRIX * m,int dx,int dy,int x0,int y0,
49                                int x1,int y1,int x2,int y2)
50 { int dx1 = x1 - x0;
51   int dy1 = y1 - y0;
52   int dx2 = x2 - x0;
53   int dy2 = y2 - y0;
54   
55   if (!m) return NULL;
56   if ((!dx)||(!dy)) return NULL; // check DIV by zero
57
58   m->tx = x0;
59   m->ty = y0;
60   m->sx = RFXSWF_QFIX(dx1,dx);
61   m->sy = RFXSWF_QFIX(dy2,dy);
62   m->r0 = RFXSWF_QFIX(dy1,dx);
63   m->r1 = RFXSWF_QFIX(dx2,dy);
64   
65   return m;
66 }
67
68 void swf_SetDefineID(TAG * tag, U16 newid)
69 {
70   int oldlen = tag->len;
71   tag->len = 0;
72   swf_SetU16(tag, newid); /* set defining ID */
73   tag->len = oldlen;
74 }
75
76 U16 swf_GetDefineID(TAG * t)
77 // up to SWF 4.0
78 { U32 oldTagPos;
79   U16 id = 0;
80
81   oldTagPos = swf_GetTagPos(t);
82   swf_SetTagPos(t,0);
83
84   switch (swf_GetTagID(t))
85   { case ST_DEFINESHAPE:
86     case ST_DEFINESHAPE2:
87     case ST_DEFINESHAPE3:
88     case ST_DEFINEMORPHSHAPE:
89     case ST_DEFINEEDITTEXT:
90     case ST_DEFINEBITS:
91     case ST_DEFINEBITSJPEG2:
92     case ST_DEFINEBITSJPEG3:
93     case ST_DEFINEBITSLOSSLESS:
94     case ST_DEFINEBITSLOSSLESS2:
95     case ST_DEFINEBUTTON:
96     case ST_DEFINEBUTTON2:
97     case ST_DEFINEBUTTONCXFORM: //pseudodefine
98     case ST_DEFINEBUTTONSOUND: //pseudodefine
99     case ST_DEFINEFONT:
100     case ST_DEFINEFONT2:
101     case ST_DEFINEFONTINFO: //pseudodefine
102     case ST_DEFINEFONTINFO2: //pseudodefine
103     case ST_DEFINETEXT:
104     case ST_DEFINETEXT2:
105     case ST_DEFINESOUND:
106     case ST_DEFINESPRITE:
107     case ST_DEFINEVIDEOSTREAM:
108     case ST_NAMECHARACTER: //pseudodefine
109       id = swf_GetU16(t);
110       break;
111   }
112
113   swf_SetTagPos(t,oldTagPos);
114
115   return id;
116 }
117
118 U16 swf_GetPlaceID(TAG * t)
119 // up to SWF 4.0
120 { U32 oldTagPos;
121   U16 id = 0;
122
123   oldTagPos = swf_GetTagPos(t);
124   swf_SetTagPos(t,0);
125
126   switch (swf_GetTagID(t))
127   { case ST_PLACEOBJECT:
128     case ST_REMOVEOBJECT:
129     case ST_FREECHARACTER:
130     case ST_STARTSOUND:
131       id = swf_GetU16(t);
132       break;
133
134     case ST_PLACEOBJECT2:
135     { U8 flags = swf_GetU8(t);
136       U16 d = swf_GetU16(t);
137       id = (flags&PF_CHAR)?swf_GetU16(t):id;
138     } break;
139
140   }
141
142   swf_SetTagPos(t,oldTagPos);
143
144   return id;
145 }
146
147 static int swf_definingtagids[] =
148 {ST_DEFINESHAPE,
149  ST_DEFINESHAPE2,
150  ST_DEFINESHAPE3,
151  ST_DEFINEMORPHSHAPE,
152  ST_DEFINEFONT,
153  ST_DEFINEFONT2,
154  ST_DEFINETEXT,
155  ST_DEFINETEXT2,
156  ST_DEFINEEDITTEXT,
157  ST_DEFINEBITS,
158  ST_DEFINEBITSJPEG2,
159  ST_DEFINEBITSJPEG3,
160  ST_DEFINEBITSLOSSLESS,
161  ST_DEFINEBITSLOSSLESS2,
162  ST_DEFINEMOVIE,
163  ST_DEFINESPRITE,
164  ST_DEFINEBUTTON,
165  ST_DEFINEBUTTON2,
166  ST_DEFINESOUND,
167  ST_DEFINEVIDEOSTREAM,
168  -1
169 };
170
171 // tags which may be used inside a sprite definition
172 static int swf_spritetagids[] =
173 {ST_SHOWFRAME,
174  ST_PLACEOBJECT,
175  ST_PLACEOBJECT2,
176  ST_REMOVEOBJECT,
177  ST_REMOVEOBJECT2, //?
178  ST_DOACTION,
179  ST_STARTSOUND,
180  ST_FRAMELABEL,
181  ST_SOUNDSTREAMHEAD,
182  ST_SOUNDSTREAMHEAD2,
183  ST_SOUNDSTREAMBLOCK,
184  ST_END,
185  -1
186 };
187
188 static int swf_pseudodefiningtagids[] = 
189 {
190  ST_DEFINEFONTINFO,
191  ST_DEFINEFONTINFO2,
192  ST_DEFINEBUTTONCXFORM,
193  ST_DEFINEBUTTONSOUND,
194  ST_NAMECHARACTER,
195  ST_DOINITACTION,
196  -1
197 };
198
199 U8 swf_isAllowedSpriteTag(TAG * tag)
200 {
201     int id = tag->id;
202     int t=0;
203     while(swf_spritetagids[t]>=0)
204     {
205         if(swf_spritetagids[t] == id) 
206             return 1;
207         t++;
208     }
209     return 0; 
210 }
211
212 U8 swf_isDefiningTag(TAG * tag)
213 {
214     int id = tag->id;
215     int t=0;
216     while(swf_definingtagids[t]>=0)
217     {
218         if(swf_definingtagids[t] == id) 
219             return 1;
220         t++;
221     }
222     return 0; 
223 }
224
225 U8 swf_isPseudoDefiningTag(TAG * tag)
226 {
227     int id = tag->id;
228     int t=0;
229     while(swf_pseudodefiningtagids[t]>=0)
230     {
231         if(swf_pseudodefiningtagids[t] == id) 
232             return 1;
233         t++;
234     }
235     return 0; 
236 }
237
238 U16 swf_GetDepth(TAG * t)
239 // up to SWF 4.0
240
241   U16 depth = 0;
242   U32 oldTagPos;
243   oldTagPos = swf_GetTagPos(t);
244   swf_SetTagPos(t,0);
245
246   switch (swf_GetTagID(t))
247   { case ST_PLACEOBJECT:
248     case ST_REMOVEOBJECT:
249       swf_GetU16(t); //id
250       depth = swf_GetU16(t);
251       break;
252     case ST_REMOVEOBJECT2:
253       depth = swf_GetU16(t);
254       break;
255     case ST_PLACEOBJECT2:
256     { U8 flags = swf_GetU8(t);
257       depth = swf_GetU16(t);
258     } break;
259   }
260   swf_SetTagPos(t,oldTagPos);
261   return depth;
262 }
263
264 char* swf_GetName(TAG * t)
265 {
266     char* name = 0;
267     U32 oldTagPos;
268     MATRIX m;
269     CXFORM c;
270     oldTagPos = swf_GetTagPos(t);
271     swf_SetTagPos(t,0);
272     switch(swf_GetTagID(t))
273     {
274         case ST_FRAMELABEL:
275             name = &t->data[swf_GetTagPos(t)];
276         break;
277         case ST_PLACEOBJECT2: {   
278             U8 flags = swf_GetU8(t);
279             swf_GetU16(t); //depth;
280             if(flags&PF_CHAR) 
281               swf_GetU16(t); //id
282             if(flags&PF_MATRIX)
283               swf_GetMatrix(t, &m);
284             if(flags&PF_CXFORM)
285               swf_GetCXForm(t, &c, 1);
286             if(flags&PF_RATIO)
287               swf_GetU16(t);
288             if(flags&PF_NAME) {
289               swf_ResetReadBits(t);
290               name = &t->data[swf_GetTagPos(t)];
291             }
292         }
293         break;
294     }
295     swf_SetTagPos(t,oldTagPos);
296     return name;
297 }
298
299 /* used in enumerateUsedIDs */
300 void swf_GetMorphGradient(TAG * tag, GRADIENT * gradient1, GRADIENT * gradient2)
301 {
302     GRADIENT dummy1;
303     GRADIENT dummy2;
304     int t;
305     if(!gradient1)
306         gradient1 = &dummy1;
307     if(!gradient2)
308         gradient2 = &dummy2;
309     gradient1->num = 
310     gradient2->num = swf_GetU8(tag);
311     for(t=0;t<gradient1->num;t++)
312     {
313         int s=t;
314         if(s>=8) //FIXME
315             s=7;
316         gradient1->ratios[t] = swf_GetU8(tag);
317         swf_GetRGBA(tag, &gradient1->rgba[t]);
318         gradient2->ratios[t] = swf_GetU8(tag);
319         swf_GetRGBA(tag, &gradient2->rgba[t]);
320     }
321 }
322
323 #define DEBUG_ENUMERATE if(0)
324
325 static void enumerateUsedIDs_styles(TAG * tag, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph)
326 {
327     U16 count;
328     int t;
329     count = swf_GetU8(tag);
330     if(count == 0xff && num>1) // defineshape2,3 only
331         count = swf_GetU16(tag);
332
333     for(t=0;t<count;t++)
334     {
335         int type;
336         U8*pos;
337         swf_ResetReadBits(tag);
338         type = swf_GetU8(tag); //type
339         if(type == 0) {
340             if(num == 3)
341                 {swf_GetRGBA(tag, NULL);if(morph) swf_GetRGBA(tag, NULL);}
342             else 
343                 {swf_GetRGB(tag, NULL);if(morph) swf_GetRGB(tag, NULL);}
344         }
345         else if(type == 0x10 || type == 0x12)
346         {
347             swf_ResetReadBits(tag);
348             swf_GetMatrix(tag, NULL);
349             if(morph)
350                 swf_GetMatrix(tag, NULL);
351             swf_ResetReadBits(tag);
352             if(morph)
353                 swf_GetMorphGradient(tag, NULL, NULL);
354             else
355                 swf_GetGradient(tag, NULL, /*alpha*/ num>=3?1:0);
356         }
357         else if(type == 0x40 || type == 0x41)
358         {
359             swf_ResetReadBits(tag);
360             // we made it.
361             if(tag->data[tag->pos] != 0xff ||
362                tag->data[tag->pos+1] != 0xff)
363             (callback)(tag, tag->pos, callback_data);
364
365             swf_GetU16(tag);
366             swf_ResetReadBits(tag);
367             swf_GetMatrix(tag, NULL);
368             if(morph)
369                 swf_GetMatrix(tag, NULL);
370         }
371         else {
372             fprintf(stderr, "rfxswf:swftools.c Unknown fillstyle:0x%02x\n",type);
373         }
374     }
375     swf_ResetReadBits(tag);
376     count = swf_GetU8(tag); // line style array
377     if(count == 0xff)
378         count = swf_GetU16(tag);
379     for(t=0;t<count;t++) 
380     {
381         swf_GetU16(tag);
382         if(morph)
383             swf_GetU16(tag);
384         if(num == 3)
385             {swf_GetRGBA(tag, NULL);if(morph) swf_GetRGBA(tag, NULL);}
386         else
387             {swf_GetRGB(tag, NULL);if(morph) swf_GetRGB(tag, NULL);}
388     }
389 }
390
391 void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), void*callback_data)
392 {
393     int num = 1;
394     swf_ResetReadBits(tag);
395     tag->pos = 0;
396     switch(tag->id)
397     {
398         case ST_DEFINEBUTTONCXFORM: {
399             int t;
400             callback(tag, tag->pos + base, callback_data);
401             for(t=0;t<4;t++) {
402                 int flags;
403                 callback(tag, tag->pos + base, callback_data);
404                 swf_GetU16(tag); //sound id
405                 flags = swf_GetU8(tag);
406                 if(flags&1)
407                     swf_GetU32(tag); // in point
408                 if(flags&2)
409                     swf_GetU32(tag); // out points
410                 if(flags&4)
411                     swf_GetU16(tag); // loop count
412                 if(flags&8)
413                 {
414                     int npoints = swf_GetU8(tag);
415                     int s;
416                     for(s=0;s<npoints;s++)
417                     {
418                         swf_GetU32(tag);
419                         swf_GetU16(tag);
420                         swf_GetU16(tag);
421                     }
422                 }
423             }
424         } break;
425         case ST_DEFINEBUTTONSOUND:
426             callback(tag, tag->pos + base, callback_data); //button id
427         break;
428
429         case ST_EXPORTASSETS: {
430             int num =  swf_GetU16(tag);
431             int t;
432             for(t=0;t<num;t++) {
433                 callback(tag, tag->pos + base, callback_data); //button id
434                 swf_GetU16(tag); //id
435                 while(swf_GetU8(tag)); //name
436             }
437         } break;
438
439         case ST_FREECHARACTER: /* unusual tags, which all start with an ID */
440         case ST_NAMECHARACTER:
441         case ST_GENERATORTEXT:
442         case ST_MX3:
443             callback(tag, tag->pos + base, callback_data);
444         break;
445         case ST_PLACEOBJECT:
446             callback(tag, tag->pos + base, callback_data);
447         break;
448         case ST_PLACEOBJECT2:
449             // only if placeflaghascharacter
450             if(!(tag->data[0]&2))
451                 break;
452             callback(tag, 3 + base, callback_data);
453         break;
454         case ST_REMOVEOBJECT:
455             callback(tag, tag->pos + base, callback_data);
456         break;
457         case ST_STARTSOUND:
458             callback(tag, tag->pos + base, callback_data);
459         break;
460         case ST_DEFINESPRITE: {
461             if(tag->len <= 4)
462                 break; // sprite is expanded
463
464             swf_GetU16(tag); // id
465             swf_GetU16(tag); // framenum
466
467             while(1) {
468                 U16 flags = swf_GetU16(tag);
469                 U32 len;
470                 U16 id = flags>>6;
471                 TAG *tag2 = swf_InsertTag(NULL, id);
472                 len = flags&0x3f;
473                 if(len == 63)
474                     len = swf_GetU32(tag);
475                 if(id == ST_END)
476                     break;
477                 tag2->len = tag2->memsize = len;
478                 tag2->data = malloc(len);
479                 memcpy(tag2->data, &tag->data[tag->pos], len);
480                 /* I never saw recursive sprites, but they are (theoretically) 
481                    possible, so better add base here again */
482                 enumerateUsedIDs(tag2, tag->pos + base, callback, callback_data);
483                 swf_DeleteTag(tag2);
484                 swf_GetBlock(tag, NULL, len);
485             }
486         } 
487         break;
488         case ST_DEFINEBUTTON2: // has some font ids in the button records
489             num++; 
490         //fallthrough
491         case ST_DEFINEBUTTON: {
492             swf_GetU16(tag); //button id
493             if(num>1)
494             { 
495                 int offset;
496                 swf_GetU8(tag); //flag
497                 offset = swf_GetU16(tag); //offset
498             }
499             while(1)
500             {
501                 U16 charid;
502                 if(!swf_GetU8(tag)) //flags
503                     break; 
504                 callback(tag, tag->pos + base, callback_data);
505                 swf_GetU16(tag); //char
506                 swf_GetU16(tag); //layer
507                 swf_ResetReadBits(tag);
508                 swf_GetMatrix(tag, NULL);
509                 if(num>1) {
510                   swf_ResetReadBits(tag);
511                   swf_GetCXForm(tag, NULL, 1);
512                 }
513             }
514             // ...
515         }
516         break;
517         case ST_DEFINEEDITTEXT:  {
518             U8 flags1,flags2;
519             swf_GetU16(tag); //id
520             swf_GetRect(tag, NULL); //bounding box
521             swf_ResetReadBits(tag);
522             flags1 = swf_GetU8(tag);
523             flags2 = swf_GetU8(tag);
524             if(flags1 & 1)
525                 callback(tag, tag->pos + base, callback_data);
526         }
527         break;
528         case ST_DEFINETEXT2:
529             num ++;
530         case ST_DEFINETEXT: { 
531             int glyphbits, advancebits;
532             int id;
533             id = swf_GetU16(tag); //id
534             swf_GetRect(tag, NULL); //bounding box
535             swf_ResetReadBits(tag);
536             swf_GetMatrix(tag, NULL); //matrix
537             swf_ResetReadBits(tag);
538             glyphbits = swf_GetU8(tag); //glyphbits
539             advancebits = swf_GetU8(tag); //advancebits
540             while(1) {
541                 U16 flags;
542                 swf_ResetReadBits(tag);
543                 flags = swf_GetBits(tag, 8);
544                 if(!flags) break;
545                 if(flags & 128) // text style record
546                 {
547                     swf_ResetReadBits(tag);
548                     if(flags & 8) { // hasfont
549                         callback(tag, tag->pos + base, callback_data);
550                         id = swf_GetU16(tag);
551                     }
552                     if(flags & 4) { // hascolor
553                         if(num==1) swf_GetRGB(tag, NULL);
554                         else       swf_GetRGBA(tag, NULL);
555                     }
556                     if(flags & 2) { //has x offset
557                         swf_ResetReadBits(tag);
558                         swf_GetU16(tag);
559                     }
560                     if(flags & 1) { //has y offset
561                         swf_ResetReadBits(tag);
562                         swf_GetU16(tag);
563                     }
564                     if(flags & 8) { //has height
565                         swf_ResetReadBits(tag);
566                         swf_GetU16(tag);
567                     }
568                 } else { // glyph record
569                     int t;
570                     swf_ResetReadBits(tag);
571                     for(t=0;t<flags;t++) {
572                         swf_GetBits(tag, glyphbits);
573                         swf_GetBits(tag, advancebits);
574                     }
575                 }
576             }
577             break;
578         }
579         case ST_DEFINEFONTINFO:
580         case ST_DEFINEFONTINFO2:
581         case ST_VIDEOFRAME:
582             callback(tag, tag->pos + base, callback_data);
583         break;
584         case ST_DEFINEVIDEOSTREAM:
585         break;
586
587         case ST_DOINITACTION:
588             callback(tag, tag->pos + base, callback_data);
589         break;
590
591         case ST_DEFINEMORPHSHAPE:
592         case ST_DEFINESHAPE3:
593         num++; //fallthrough
594         case ST_DEFINESHAPE2:
595         num++; //fallthrough
596         case ST_DEFINESHAPE: {
597             int fillbits;
598             int linebits;
599             int id; 
600             int numshapes = 1;
601             int morph = 0;
602             if(tag->id == ST_DEFINEMORPHSHAPE) {
603                 numshapes = 2;
604                 morph = 1;
605             }
606
607             id = swf_GetU16(tag); // id;
608             swf_GetRect(tag, NULL); // bounds
609             if(morph) {
610                 swf_ResetReadBits(tag);
611                 swf_GetRect(tag, NULL); // bounds2
612                 swf_GetU32(tag); //offset to endedges
613             }
614    
615             DEBUG_ENUMERATE printf("Tag:%d Name:%s ID:%d\n", tag->id, swf_TagGetName(tag), id);
616
617             enumerateUsedIDs_styles(tag, callback, callback_data, num, morph);
618             DEBUG_ENUMERATE printf("-------\n");
619             while(--numshapes>=0) /* morph shapes define two shapes */
620             {
621                 DEBUG_ENUMERATE printf("shape:%d\n", numshapes);
622                 fillbits = swf_GetBits(tag, 4);
623                 linebits = swf_GetBits(tag, 4);
624                 DEBUG_ENUMERATE printf("%d %d\n", fillbits, linebits);
625                 swf_ResetReadBits(tag);
626                 while(1) {
627                     int flags;
628                     flags = swf_GetBits(tag, 1);
629                     if(!flags) { //style change
630                         flags = swf_GetBits(tag, 5);
631                         if(!flags)
632                             break;
633                         if(flags&1) { //move
634                             int n = swf_GetBits(tag, 5); 
635                             int x,y;
636                             x = swf_GetBits(tag, n); //x
637                             y = swf_GetBits(tag, n); //y
638                             DEBUG_ENUMERATE printf("move %f %f\n",x/20.0,y/20.0);
639                         }
640                         if(flags&2) { //fill0
641                             int fill0;
642                             fill0 = swf_GetBits(tag, fillbits); 
643                             DEBUG_ENUMERATE printf("fill0 %d\n", fill0);
644                         }
645                         if(flags&4) { //fill1
646                             int fill1;
647                             fill1 = swf_GetBits(tag, fillbits); 
648                             DEBUG_ENUMERATE printf("fill1 %d\n", fill1);
649                         }
650                         if(flags&8) { //linestyle
651                             int line;
652                             line = swf_GetBits(tag, linebits); 
653                             DEBUG_ENUMERATE printf("linestyle %d\n",line);
654                         }
655                         if(flags&16) {
656                             DEBUG_ENUMERATE printf("more fillstyles\n");
657                             enumerateUsedIDs_styles(tag, callback, callback_data, num, 0);
658                             fillbits = swf_GetBits(tag, 4);
659                             linebits = swf_GetBits(tag, 4);
660                         }
661                     } else {
662                         flags = swf_GetBits(tag, 1);
663                         if(flags) { //straight edge
664                             int n = swf_GetBits(tag, 4) + 2;
665                             if(swf_GetBits(tag, 1)) { //line flag
666                                 int x,y;
667                                 x = swf_GetSBits(tag, n); //delta x
668                                 y = swf_GetSBits(tag, n); //delta y
669                                 DEBUG_ENUMERATE printf("line %f %f\n",x/20.0,y/20.0);
670                             } else {
671                                 int v=swf_GetBits(tag, 1);
672                                 int d;
673                                 d = swf_GetSBits(tag, n); //vert/horz
674                                 DEBUG_ENUMERATE printf("%s %f\n",v?"vertical":"horizontal", d/20.0);
675                             }
676                         } else { //curved edge
677                             int n = swf_GetBits(tag, 4) + 2;
678                             int x1,y1,x2,y2;
679                             x1 = swf_GetSBits(tag, n);
680                             y1 = swf_GetSBits(tag, n);
681                             x2 = swf_GetSBits(tag, n);
682                             y2 = swf_GetSBits(tag, n);
683                             DEBUG_ENUMERATE printf("curve %f %f %f %f\n", x1/20.0, y1/20.0, x2/20.0, y2/20.0);
684                         }
685                     }
686                 }
687             }
688         }
689         break;
690         default:
691         break;
692     }
693 }
694
695 void callbackCount(TAG * t,int pos, void*ptr)
696 {
697     (*(int*)ptr)++;
698     DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
699 }
700
701 void callbackFillin(TAG * t,int pos, void*ptr)
702 {
703     **(int**)ptr = pos;
704     (*(int**)ptr)++;
705     DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
706 }
707
708 int swf_GetNumUsedIDs(TAG * t)
709 {
710     int num = 0;
711     enumerateUsedIDs(t, 0, callbackCount, &num);
712     return num;
713 }
714
715 void swf_GetUsedIDs(TAG * t, int * positions)
716 {
717     int * ptr = positions;
718     enumerateUsedIDs(t, 0, callbackFillin, &ptr);
719 }
720
721 void swf_Relocate (SWF*swf, char*bitmap)
722 {
723     TAG*tag;
724     int slaveids[65536];
725     memset(slaveids, -1, sizeof(slaveids));
726     tag = swf->firstTag;
727     while(tag)
728     {
729         int num; 
730         int *ptr;
731         int t;
732
733         if(swf_isDefiningTag(tag))
734         {
735             int newid;
736             int id;
737             
738             id = swf_GetDefineID(tag); //own id
739
740             if(!bitmap[id]) { //free
741                 newid = id;
742             }
743             else {
744                 newid = 0;
745                 for (t=1;t<65536;t++)
746                 {
747                     if(!bitmap[t])
748                     {
749                         newid = t;
750                         break;
751                     }
752                 }
753             }
754             bitmap[newid] = 1;
755             slaveids[id] = newid;
756
757             swf_SetDefineID(tag, newid);
758         } 
759         
760         num = swf_GetNumUsedIDs(tag);
761         ptr = malloc(sizeof(int)*num);
762         swf_GetUsedIDs(tag, ptr);
763
764         for(t=0;t<num;t++) {
765             int id = GET16(&tag->data[ptr[t]]);
766             if(slaveids[id]<0) {
767                 fprintf(stderr, "swf_Relocate: Mapping id never encountered before: %d\n", id);
768                 return ;
769             }
770             id = slaveids[id];
771             PUT16(&tag->data[ptr[t]], id);
772         }
773         tag=tag->next;
774     }
775 }
776