changed -f to -r option.
[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             callback(tag, tag->pos + base, callback_data);
443         break;
444         case ST_PLACEOBJECT:
445             callback(tag, tag->pos + base, callback_data);
446         break;
447         case ST_PLACEOBJECT2:
448             // only if placeflaghascharacter
449             if(!(tag->data[0]&2))
450                 break;
451             callback(tag, 3 + base, callback_data);
452         break;
453         case ST_REMOVEOBJECT:
454             callback(tag, tag->pos + base, callback_data);
455         break;
456         case ST_STARTSOUND:
457             callback(tag, tag->pos + base, callback_data);
458         break;
459         case ST_DEFINESPRITE: {
460             if(tag->len <= 4)
461                 break; // sprite is expanded
462
463             swf_GetU16(tag); // id
464             swf_GetU16(tag); // framenum
465
466             while(1) {
467                 U16 flags = swf_GetU16(tag);
468                 U32 len;
469                 U16 id = flags>>6;
470                 TAG *tag2 = swf_InsertTag(NULL, id);
471                 len = flags&0x3f;
472                 if(len == 63)
473                     len = swf_GetU32(tag);
474                 if(id == ST_END)
475                     break;
476                 tag2->len = tag2->memsize = len;
477                 tag2->data = malloc(len);
478                 memcpy(tag2->data, &tag->data[tag->pos], len);
479                 /* I never saw recursive sprites, but they are (theoretically) 
480                    possible, so better add base here again */
481                 enumerateUsedIDs(tag2, tag->pos + base, callback, callback_data);
482                 swf_DeleteTag(tag2);
483                 swf_GetBlock(tag, NULL, len);
484             }
485         } 
486         break;
487         case ST_DEFINEBUTTON2: // has some font ids in the button records
488             num++; 
489         //fallthrough
490         case ST_DEFINEBUTTON: {
491             swf_GetU16(tag); //button id
492             if(num>1)
493             { 
494                 int offset;
495                 swf_GetU8(tag); //flag
496                 offset = swf_GetU16(tag); //offset
497             }
498             while(1)
499             {
500                 U16 charid;
501                 if(!swf_GetU8(tag)) //flags
502                     break; 
503                 callback(tag, tag->pos + base, callback_data);
504                 swf_GetU16(tag); //char
505                 swf_GetU16(tag); //layer
506                 swf_ResetReadBits(tag);
507                 swf_GetMatrix(tag, NULL);
508                 if(num>1) {
509                   swf_ResetReadBits(tag);
510                   swf_GetCXForm(tag, NULL, 1);
511                 }
512             }
513             // ...
514         }
515         break;
516         case ST_DEFINEEDITTEXT:  {
517             U8 flags1,flags2;
518             swf_GetU16(tag); //id
519             swf_GetRect(tag, NULL); //bounding box
520             swf_ResetReadBits(tag);
521             flags1 = swf_GetU8(tag);
522             flags2 = swf_GetU8(tag);
523             if(flags1 & 1)
524                 callback(tag, tag->pos + base, callback_data);
525         }
526         break;
527         case ST_DEFINETEXT2:
528             num ++;
529         case ST_DEFINETEXT: { 
530             int glyphbits, advancebits;
531             int id;
532             id = swf_GetU16(tag); //id
533             swf_GetRect(tag, NULL); //bounding box
534             swf_ResetReadBits(tag);
535             swf_GetMatrix(tag, NULL); //matrix
536             swf_ResetReadBits(tag);
537             glyphbits = swf_GetU8(tag); //glyphbits
538             advancebits = swf_GetU8(tag); //advancebits
539             while(1) {
540                 U16 flags;
541                 swf_ResetReadBits(tag);
542                 flags = swf_GetBits(tag, 8);
543                 if(!flags) break;
544                 if(flags & 128) // text style record
545                 {
546                     swf_ResetReadBits(tag);
547                     if(flags & 8) { // hasfont
548                         callback(tag, tag->pos + base, callback_data);
549                         id = swf_GetU16(tag);
550                     }
551                     if(flags & 4) { // hascolor
552                         if(num==1) swf_GetRGB(tag, NULL);
553                         else       swf_GetRGBA(tag, NULL);
554                     }
555                     if(flags & 2) { //has x offset
556                         swf_ResetReadBits(tag);
557                         swf_GetU16(tag);
558                     }
559                     if(flags & 1) { //has y offset
560                         swf_ResetReadBits(tag);
561                         swf_GetU16(tag);
562                     }
563                     if(flags & 8) { //has height
564                         swf_ResetReadBits(tag);
565                         swf_GetU16(tag);
566                     }
567                 } else { // glyph record
568                     int t;
569                     swf_ResetReadBits(tag);
570                     for(t=0;t<flags;t++) {
571                         swf_GetBits(tag, glyphbits);
572                         swf_GetBits(tag, advancebits);
573                     }
574                 }
575             }
576             break;
577         }
578         case ST_DEFINEFONTINFO:
579         case ST_DEFINEFONTINFO2:
580         case ST_VIDEOFRAME:
581             callback(tag, tag->pos + base, callback_data);
582         break;
583         case ST_DEFINEVIDEOSTREAM:
584         break;
585
586         case ST_DOINITACTION:
587             callback(tag, tag->pos + base, callback_data);
588         break;
589
590         case ST_DEFINEMORPHSHAPE:
591         case ST_DEFINESHAPE3:
592         num++; //fallthrough
593         case ST_DEFINESHAPE2:
594         num++; //fallthrough
595         case ST_DEFINESHAPE: {
596             int fillbits;
597             int linebits;
598             int id; 
599             int numshapes = 1;
600             int morph = 0;
601             if(tag->id == ST_DEFINEMORPHSHAPE) {
602                 numshapes = 2;
603                 morph = 1;
604             }
605
606             id = swf_GetU16(tag); // id;
607             swf_GetRect(tag, NULL); // bounds
608             if(morph) {
609                 swf_ResetReadBits(tag);
610                 swf_GetRect(tag, NULL); // bounds2
611                 swf_GetU32(tag); //offset to endedges
612             }
613    
614             DEBUG_ENUMERATE printf("Tag:%d Name:%s ID:%d\n", tag->id, swf_TagGetName(tag), id);
615
616             enumerateUsedIDs_styles(tag, callback, callback_data, num, morph);
617             DEBUG_ENUMERATE printf("-------\n");
618             while(--numshapes>=0) /* morph shapes define two shapes */
619             {
620                 DEBUG_ENUMERATE printf("shape:%d\n", numshapes);
621                 fillbits = swf_GetBits(tag, 4);
622                 linebits = swf_GetBits(tag, 4);
623                 DEBUG_ENUMERATE printf("%d %d\n", fillbits, linebits);
624                 swf_ResetReadBits(tag);
625                 while(1) {
626                     int flags;
627                     flags = swf_GetBits(tag, 1);
628                     if(!flags) { //style change
629                         flags = swf_GetBits(tag, 5);
630                         if(!flags)
631                             break;
632                         if(flags&1) { //move
633                             int n = swf_GetBits(tag, 5); 
634                             int x,y;
635                             x = swf_GetBits(tag, n); //x
636                             y = swf_GetBits(tag, n); //y
637                             DEBUG_ENUMERATE printf("move %f %f\n",x/20.0,y/20.0);
638                         }
639                         if(flags&2) { //fill0
640                             int fill0;
641                             fill0 = swf_GetBits(tag, fillbits); 
642                             DEBUG_ENUMERATE printf("fill0 %d\n", fill0);
643                         }
644                         if(flags&4) { //fill1
645                             int fill1;
646                             fill1 = swf_GetBits(tag, fillbits); 
647                             DEBUG_ENUMERATE printf("fill1 %d\n", fill1);
648                         }
649                         if(flags&8) { //linestyle
650                             int line;
651                             line = swf_GetBits(tag, linebits); 
652                             DEBUG_ENUMERATE printf("linestyle %d\n",line);
653                         }
654                         if(flags&16) {
655                             DEBUG_ENUMERATE printf("more fillstyles\n");
656                             enumerateUsedIDs_styles(tag, callback, callback_data, num, 0);
657                             fillbits = swf_GetBits(tag, 4);
658                             linebits = swf_GetBits(tag, 4);
659                         }
660                     } else {
661                         flags = swf_GetBits(tag, 1);
662                         if(flags) { //straight edge
663                             int n = swf_GetBits(tag, 4) + 2;
664                             if(swf_GetBits(tag, 1)) { //line flag
665                                 int x,y;
666                                 x = swf_GetSBits(tag, n); //delta x
667                                 y = swf_GetSBits(tag, n); //delta y
668                                 DEBUG_ENUMERATE printf("line %f %f\n",x/20.0,y/20.0);
669                             } else {
670                                 int v=swf_GetBits(tag, 1);
671                                 int d;
672                                 d = swf_GetSBits(tag, n); //vert/horz
673                                 DEBUG_ENUMERATE printf("%s %f\n",v?"vertical":"horizontal", d/20.0);
674                             }
675                         } else { //curved edge
676                             int n = swf_GetBits(tag, 4) + 2;
677                             int x1,y1,x2,y2;
678                             x1 = swf_GetSBits(tag, n);
679                             y1 = swf_GetSBits(tag, n);
680                             x2 = swf_GetSBits(tag, n);
681                             y2 = swf_GetSBits(tag, n);
682                             DEBUG_ENUMERATE printf("curve %f %f %f %f\n", x1/20.0, y1/20.0, x2/20.0, y2/20.0);
683                         }
684                     }
685                 }
686             }
687         }
688         break;
689         default:
690         break;
691     }
692 }
693
694 void callbackCount(TAG * t,int pos, void*ptr)
695 {
696     (*(int*)ptr)++;
697     DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
698 }
699
700 void callbackFillin(TAG * t,int pos, void*ptr)
701 {
702     **(int**)ptr = pos;
703     (*(int**)ptr)++;
704     DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
705 }
706
707 int swf_GetNumUsedIDs(TAG * t)
708 {
709     int num = 0;
710     enumerateUsedIDs(t, 0, callbackCount, &num);
711     return num;
712 }
713
714 void swf_GetUsedIDs(TAG * t, int * positions)
715 {
716     int * ptr = positions;
717     enumerateUsedIDs(t, 0, callbackFillin, &ptr);
718 }
719
720 void swf_Relocate (SWF*swf, char*bitmap)
721 {
722     TAG*tag;
723     int slaveids[65536];
724     memset(slaveids, -1, sizeof(slaveids));
725     tag = swf->firstTag;
726     while(tag)
727     {
728         int num; 
729         int *ptr;
730         int t;
731
732         if(swf_isDefiningTag(tag))
733         {
734             int newid;
735             int id;
736             
737             id = swf_GetDefineID(tag); //own id
738
739             if(!bitmap[id]) { //free
740                 newid = id;
741             }
742             else {
743                 newid = 0;
744                 for (t=1;t<65536;t++)
745                 {
746                     if(!bitmap[t])
747                     {
748                         newid = t;
749                         break;
750                     }
751                 }
752             }
753             bitmap[newid] = 1;
754             slaveids[id] = newid;
755
756             swf_SetDefineID(tag, newid);
757         } 
758         
759         num = swf_GetNumUsedIDs(tag);
760         ptr = malloc(sizeof(int)*num);
761         swf_GetUsedIDs(tag, ptr);
762
763         for(t=0;t<num;t++) {
764             int id = GET16(&tag->data[ptr[t]]);
765             if(slaveids[id]<0) {
766                 fprintf(stderr, "swf_Relocate: Mapping id never encountered before: %d\n", id);
767                 return ;
768             }
769             id = slaveids[id];
770             PUT16(&tag->data[ptr[t]], id);
771         }
772         tag=tag->next;
773     }
774 }
775