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 program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
23 
24 // Matrix & Math tools for SWF files
25 
26 #include "../rfxswf.h"
27 
28 #define S64 long long
RFXSWF_SP(SFIXED a1,SFIXED a2,SFIXED b1,SFIXED b2)29 SFIXED RFXSWF_SP(SFIXED a1,SFIXED a2,SFIXED b1,SFIXED b2)
30 { S64 a = ((S64)a1*(S64)b1+(S64)a2*(S64)b2)>>16;
31   SFIXED result = (SFIXED)(a);
32   if(a!=result)
33       fprintf(stderr, "Warning: overflow in matrix multiplication\n");
34   return result;
35 }
RFXSWF_QFIX(int zaehler,int nenner)36 SFIXED RFXSWF_QFIX(int zaehler,int nenner) // bildet Quotient von zwei INTs in SFIXED
37 { S64 z = zaehler<<16;
38   S64 a = z/(S64)nenner;
39   return (SFIXED)a;
40 }
41 #undef S64
42 
swf_MatrixJoin(MATRIX * d,MATRIX * s1,MATRIX * s2)43 MATRIX * swf_MatrixJoin(MATRIX * d,MATRIX * s1,MATRIX * s2)
44 {
45   if (!d) return NULL;
46   if (!s1) return (s2)?(MATRIX *)memcpy(d,s2,sizeof(MATRIX)):NULL;
47   if (!s2) return (MATRIX *)memcpy(d,s1,sizeof(MATRIX));
48 
49   d->tx = s1->tx + RFXSWF_SP(s1->sx,s1->r1,s2->tx,s2->ty);
50   d->ty = s1->ty + RFXSWF_SP(s1->r0,s1->sy,s2->tx,s2->ty);
51 
52   d->sx = RFXSWF_SP(s1->sx,s1->r1,s2->sx,s2->r0);
53   d->r0 = RFXSWF_SP(s1->r0,s1->sy,s2->sx,s2->r0);
54 
55   d->r1 = RFXSWF_SP(s1->sx,s1->r1,s2->r1,s2->sy);
56   d->sy = RFXSWF_SP(s1->r0,s1->sy,s2->r1,s2->sy);
57 
58   //DumpMatrix(NULL,d);
59 
60   return d;
61 }
62 
swf_MatrixMapTriangle(MATRIX * m,int dx,int dy,int x0,int y0,int x1,int y1,int x2,int y2)63 MATRIX * swf_MatrixMapTriangle(MATRIX * m,int dx,int dy,int x0,int y0,
64                                int x1,int y1,int x2,int y2)
65 { int dx1 = x1 - x0;
66   int dy1 = y1 - y0;
67   int dx2 = x2 - x0;
68   int dy2 = y2 - y0;
69 
70   if (!m) return NULL;
71   if ((!dx)||(!dy)) return NULL; // check DIV by zero
72 
73   m->tx = x0;
74   m->ty = y0;
75   m->sx = RFXSWF_QFIX(dx1,dx);
76   m->sy = RFXSWF_QFIX(dy2,dy);
77   m->r0 = RFXSWF_QFIX(dy1,dx);
78   m->r1 = RFXSWF_QFIX(dx2,dy);
79 
80   return m;
81 }
82 
swf_SetDefineID(TAG * tag,U16 newid)83 void swf_SetDefineID(TAG * tag, U16 newid)
84 {
85   int oldlen = tag->len;
86   tag->len = 0;
87   swf_SetU16(tag, newid); /* set defining ID */
88   tag->len = oldlen;
89 }
90 
swf_GetDefineID(TAG * t)91 U16 swf_GetDefineID(TAG * t)
92 // up to SWF 4.0
93 { U32 oldTagPos;
94   U16 id = 0;
95 
96   oldTagPos = swf_GetTagPos(t);
97   swf_SetTagPos(t,0);
98 
99   switch (swf_GetTagID(t))
100   { case ST_DEFINESHAPE:
101     case ST_DEFINESHAPE2:
102     case ST_DEFINESHAPE3:
103     case ST_DEFINESHAPE4:
104     case ST_DEFINEMORPHSHAPE:
105     case ST_DEFINEMORPHSHAPE2:
106     case ST_DEFINEEDITTEXT:
107     case ST_DEFINEBITS:
108     case ST_DEFINEBITSJPEG2:
109     case ST_DEFINEBITSJPEG3:
110     case ST_DEFINEBITSLOSSLESS:
111     case ST_DEFINEBITSLOSSLESS2:
112     case ST_DEFINESCALINGGRID: //pseudodefine
113     case ST_DEFINEBUTTON:
114     case ST_DEFINEBUTTON2:
115     case ST_DEFINEBUTTONCXFORM: //pseudodefine
116     case ST_DEFINEBUTTONSOUND: //pseudodefine
117     case ST_CSMTEXTSETTINGS: //pseudodefine
118     case ST_DEFINEFONT:
119     case ST_DEFINEFONT2:
120     case ST_DEFINEFONT3:
121     case ST_DEFINEFONTINFO: //pseudodefine
122     case ST_DEFINEFONTINFO2: //pseudodefine
123     case ST_DEFINEFONTALIGNZONES: //pseudodefine
124     case ST_DEFINEFONTNAME: //pseudodefine
125     case ST_DEFINETEXT:
126     case ST_DEFINEBINARY:
127     case ST_DEFINETEXT2:
128     case ST_DEFINESOUND:
129     case ST_DEFINESPRITE:
130     case ST_DEFINEMOVIE:
131     case ST_DEFINEVIDEOSTREAM:
132     case ST_GLYPHNAMES: //pseudodefine
133     case ST_VIDEOFRAME: //pseudodefine
134     case ST_NAMECHARACTER: //pseudodefine
135     case ST_DOINITACTION: //pseudodefine
136       id = swf_GetU16(t);
137       break;
138     default:
139       fprintf(stderr, "rfxswf: Error: tag %d (%s) has no id\n", t->id, swf_TagGetName(t));
140   }
141 
142   swf_SetTagPos(t,oldTagPos);
143 
144   return id;
145 }
146 
swf_GetDefineBBox(TAG * t)147 SRECT swf_GetDefineBBox(TAG * t)
148 {
149   U32 oldTagPos;
150   U16 id = 0;
151   SRECT b1,b2;
152   memset(&b1, 0, sizeof(b1));
153 
154   oldTagPos = swf_GetTagPos(t);
155   swf_SetTagPos(t,0);
156 
157   swf_GetRect(0, &b1);
158 
159   switch (swf_GetTagID(t))
160   { case ST_DEFINESHAPE:
161     case ST_DEFINESHAPE2:
162     case ST_DEFINESHAPE3:
163     case ST_DEFINESHAPE4:
164     case ST_DEFINEEDITTEXT:
165     case ST_DEFINETEXT:
166     case ST_DEFINETEXT2:
167     case ST_DEFINEVIDEOSTREAM:
168       id = swf_GetU16(t);
169       swf_GetRect(t, &b1);
170       break;
171     case ST_DEFINEMORPHSHAPE:
172       id = swf_GetU16(t);
173       swf_GetRect(t, &b1);
174       swf_GetRect(t, &b2);
175       swf_ExpandRect2(&b1, &b2);
176       break;
177     case ST_DEFINEBITSLOSSLESS:
178     case ST_DEFINEBITSLOSSLESS2:
179     case ST_DEFINEBITS:
180     case ST_DEFINEBITSJPEG2:
181     case ST_DEFINEBITSJPEG3:
182       // FIXME
183       break;
184   }
185 
186   swf_SetTagPos(t,oldTagPos);
187 
188   return b1;
189 }
190 
swf_GetPlaceID(TAG * t)191 U16 swf_GetPlaceID(TAG * t)
192 // up to SWF 4.0
193 { U32 oldTagPos;
194   U16 id = 0;
195 
196   oldTagPos = swf_GetTagPos(t);
197   swf_SetTagPos(t,0);
198 
199   switch (swf_GetTagID(t))
200   { case ST_PLACEOBJECT:
201     case ST_REMOVEOBJECT:
202     case ST_FREECHARACTER:
203     case ST_STARTSOUND:
204       id = swf_GetU16(t);
205       break;
206 
207     case ST_PLACEOBJECT2:
208     { U8 flags = swf_GetU8(t);
209       U16 d = swf_GetU16(t);
210       id = (flags&PF_CHAR)?swf_GetU16(t):id;
211     } break;
212     case ST_PLACEOBJECT3:
213     { U8 flags = swf_GetU8(t);
214       U8 flags2 = swf_GetU8(t);
215       U16 d = swf_GetU16(t);
216       id = (flags&PF_CHAR)?swf_GetU16(t):id;
217     } break;
218 
219   }
220 
221   swf_SetTagPos(t,oldTagPos);
222 
223   return id;
224 }
225 
226 static int swf_definingtagids[] =
227 {ST_DEFINESHAPE,
228  ST_DEFINESHAPE2,
229  ST_DEFINESHAPE3,
230  ST_DEFINESHAPE4,
231  ST_DEFINEMORPHSHAPE,
232  ST_DEFINEMORPHSHAPE2,
233  ST_DEFINEFONT,
234  ST_DEFINEFONT2,
235  ST_DEFINEFONT3,
236  ST_DEFINETEXT,
237  ST_DEFINETEXT2,
238  ST_DEFINEEDITTEXT,
239  ST_DEFINEBITS,
240  ST_DEFINEBITSJPEG2,
241  ST_DEFINEBITSJPEG3,
242  ST_DEFINEBITSLOSSLESS,
243  ST_DEFINEBITSLOSSLESS2,
244  ST_DEFINEMOVIE,
245  ST_DEFINESPRITE,
246  ST_DEFINEBUTTON,
247  ST_DEFINEBUTTON2,
248  ST_DEFINESOUND,
249  ST_DEFINEVIDEOSTREAM,
250  ST_DEFINEBINARY,
251  -1
252 };
253 
254 // tags which may be used inside a sprite definition
255 static int swf_spritetagids[] =
256 {ST_SHOWFRAME,
257  ST_PLACEOBJECT,
258  ST_PLACEOBJECT2,
259  ST_PLACEOBJECT3,
260  ST_REMOVEOBJECT,
261  ST_REMOVEOBJECT2,
262  ST_DOACTION,
263  ST_DOABC,
264  ST_STARTSOUND,
265  ST_FRAMELABEL,
266  ST_SOUNDSTREAMHEAD,
267  ST_SOUNDSTREAMHEAD2,
268  ST_SOUNDSTREAMBLOCK,
269  ST_END,
270  -1
271 };
272 
273 /* tags which add content or information to a character with a given ID */
274 static int swf_pseudodefiningtagids[] =
275 {
276  ST_DEFINEFONTINFO,
277  ST_DEFINEFONTINFO2,
278  ST_DEFINEFONTALIGNZONES,
279  ST_DEFINEFONTNAME,
280  ST_DEFINEBUTTONCXFORM,
281  ST_DEFINEBUTTONSOUND,
282  ST_DEFINESCALINGGRID,
283  ST_CSMTEXTSETTINGS,
284  ST_NAMECHARACTER,
285  ST_DOINITACTION,
286  ST_VIDEOFRAME,
287  ST_GLYPHNAMES,
288  -1
289 };
290 
swf_isAllowedSpriteTag(TAG * tag)291 U8 swf_isAllowedSpriteTag(TAG * tag)
292 {
293     int id = tag->id;
294     int t=0;
295     while(swf_spritetagids[t]>=0)
296     {
297         if(swf_spritetagids[t] == id)
298             return 1;
299         t++;
300     }
301     return 0;
302 }
303 
swf_isDefiningTag(TAG * tag)304 U8 swf_isDefiningTag(TAG * tag)
305 {
306     int id = tag->id;
307     int t=0;
308     while(swf_definingtagids[t]>=0)
309     {
310         if(swf_definingtagids[t] == id)
311             return 1;
312         t++;
313     }
314     return 0;
315 }
316 
swf_isPseudoDefiningTag(TAG * tag)317 U8 swf_isPseudoDefiningTag(TAG * tag)
318 {
319     int id = tag->id;
320     int t=0;
321     while(swf_pseudodefiningtagids[t]>=0)
322     {
323         if(swf_pseudodefiningtagids[t] == id)
324             return 1;
325         t++;
326     }
327     return 0;
328 }
329 
swf_GetDepth(TAG * t)330 int swf_GetDepth(TAG * t)
331 {
332   int depth = -1;
333   U32 oldTagPos;
334   oldTagPos = swf_GetTagPos(t);
335   swf_SetTagPos(t,0);
336 
337   switch (swf_GetTagID(t))
338   { case ST_PLACEOBJECT:
339     case ST_REMOVEOBJECT:
340       swf_GetU16(t); //id
341       depth = swf_GetU16(t);
342       break;
343     case ST_REMOVEOBJECT2:
344       depth = swf_GetU16(t);
345       break;
346     case ST_PLACEOBJECT2:
347     { U8 flags = swf_GetU8(t);
348       depth = swf_GetU16(t);
349     } break;
350     case ST_PLACEOBJECT3:
351     { U8 flags = swf_GetU8(t);
352       U8 flags2 = swf_GetU8(t);
353       depth = swf_GetU16(t);
354     } break;
355     case ST_SETTABINDEX:
356     {
357       depth = swf_GetU16(t);
358     }
359   }
360   swf_SetTagPos(t,oldTagPos);
361   return depth;
362 }
363 
swf_SetDepth(TAG * t,U16 depth)364 void swf_SetDepth(TAG * t, U16 depth)
365 {
366   switch (swf_GetTagID(t))
367   { case ST_PLACEOBJECT:
368     case ST_REMOVEOBJECT:
369       PUT16(t->data, depth);
370       break;
371     case ST_REMOVEOBJECT2:
372       PUT16(t->data, depth);
373       break;
374     case ST_PLACEOBJECT2:
375       PUT16(&t->data[1], depth);
376       break;
377     case ST_SETTABINDEX:
378       PUT16(t->data, depth);
379       break;
380     default:
381       fprintf(stderr, "rfxswf: Error: tag %d has no depth\n", t->id);
382   }
383 }
384 
swf_GetName(TAG * t)385 char* swf_GetName(TAG * t)
386 {
387     char* name = 0;
388     U32 oldTagPos;
389     MATRIX m;
390     CXFORM c;
391     oldTagPos = swf_GetTagPos(t);
392     swf_SetTagPos(t,0);
393     switch(swf_GetTagID(t))
394     {
395         case ST_FRAMELABEL:
396             name = (char*)&t->data[swf_GetTagPos(t)];
397         break;
398         case ST_PLACEOBJECT3:
399         case ST_PLACEOBJECT2: {
400             U8 flags = swf_GetU8(t);
401 	    if(t->id == ST_PLACEOBJECT3)
402 		swf_GetU8(t);
403             swf_GetU16(t); //depth;
404             if(flags&PF_CHAR)
405               swf_GetU16(t); //id
406             if(flags&PF_MATRIX)
407               swf_GetMatrix(t, &m);
408             if(flags&PF_CXFORM)
409               swf_GetCXForm(t, &c, 1);
410             if(flags&PF_RATIO)
411               swf_GetU16(t);
412             if(flags&PF_CLIPDEPTH)
413               swf_GetU16(t);
414             if(flags&PF_NAME) {
415               swf_ResetReadBits(t);
416               name = (char*)&t->data[swf_GetTagPos(t)];
417             }
418         }
419         break;
420     }
421     swf_SetTagPos(t,oldTagPos);
422     return name;
423 }
424 
425 /* used in enumerateUsedIDs */
swf_GetMorphGradient(TAG * tag,GRADIENT * gradient1,GRADIENT * gradient2)426 void swf_GetMorphGradient(TAG * tag, GRADIENT * gradient1, GRADIENT * gradient2)
427 {
428     int t;
429     int num = swf_GetU8(tag) & 15;
430     if(gradient1) gradient1->num = num;
431     if(gradient2) gradient2->num = num;
432 
433     if(gradient1) {
434 	gradient1->num = num;
435 	gradient1->rgba = (RGBA*)rfx_calloc(sizeof(RGBA)*gradient1->num);
436 	gradient1->ratios = (U8*)rfx_calloc(sizeof(gradient1->ratios[0])*gradient1->num);
437     }
438     if(gradient2) {
439 	gradient2->num = num;
440 	gradient2->rgba = (RGBA*)rfx_calloc(sizeof(RGBA)*gradient2->num);
441 	gradient2->ratios = (U8*)rfx_calloc(sizeof(gradient2->ratios[0])*gradient2->num);
442     }
443     for(t=0;t<num;t++)
444     {
445 	U8 ratio;
446 	RGBA color;
447 
448 	ratio = swf_GetU8(tag);
449 	swf_GetRGBA(tag, &color);
450 	if(gradient1) {
451 	    gradient1->ratios[t] = ratio;
452 	    gradient1->rgba[t] = color;
453 	}
454 
455 	ratio = swf_GetU8(tag);
456 	swf_GetRGBA(tag, &color);
457 	if(gradient2) {
458 	    gradient2->ratios[t] = ratio;
459 	    gradient2->rgba[t] = color;
460 	}
461     }
462 }
463 
464 #define DEBUG_ENUMERATE if(0)
465 //#define DEBUG_ENUMERATE
466 
enumerateUsedIDs_fillstyle(TAG * tag,int t,void (* callback)(TAG *,int,void *),void * callback_data,int num,int morph)467 void enumerateUsedIDs_fillstyle(TAG * tag, int t, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph)
468 {
469     int type;
470     type = swf_GetU8(tag); //type
471     DEBUG_ENUMERATE printf("fill style %d) type=%02x (tagpos=%d)\n", t, type, tag->pos);
472     if(type == 0) {
473 	RGBA color;
474 	if(num >= 3)
475 	    {swf_GetRGBA(tag, &color);if(morph) swf_GetRGBA(tag, NULL);}
476 	else
477 	    {swf_GetRGB(tag, &color);if(morph) swf_GetRGB(tag, NULL);}
478 	DEBUG_ENUMERATE printf("               %02x%02x%02x%02x\n", color.r,color.g,color.b,color.a);
479     }
480     else if(type == 0x10 || type == 0x12 || type == 0x13)
481     {
482 	swf_ResetReadBits(tag);
483 	MATRIX m;
484 	swf_GetMatrix(tag, &m);
485 	DEBUG_ENUMERATE swf_DumpMatrix(stdout, &m);
486 	if(morph) {
487 	    swf_GetMatrix(tag, &m);
488 	    DEBUG_ENUMERATE swf_DumpMatrix(stdout, &m);
489 	}
490 	swf_ResetReadBits(tag);
491 	if(morph) {
492 	    swf_GetMorphGradient(tag, NULL, NULL);
493 	    if(type == 0x13) {
494 		swf_GetU16(tag);
495 		swf_GetU16(tag);
496 	    }
497 	} else {
498 	    GRADIENT g;
499 	    swf_GetGradient(tag, &g, /*alpha*/ num>=3?1:0);
500 	    DEBUG_ENUMERATE swf_DumpGradient(stdout, &g);
501 	    if(type == 0x13)
502 		swf_GetU16(tag);
503 	}
504     }
505     else if(type == 0x40 || type == 0x41 || type == 0x42 || type == 0x43)
506     {
507 	swf_ResetReadBits(tag);
508 	if(tag->data[tag->pos] != 0xff ||
509 	   tag->data[tag->pos+1] != 0xff)
510 	(callback)(tag, tag->pos, callback_data);
511 
512 	swf_GetU16(tag);
513 	swf_ResetReadBits(tag);
514 	swf_GetMatrix(tag, NULL);
515 	if(morph)
516 	    swf_GetMatrix(tag, NULL);
517     }
518     else {
519 	fprintf(stderr, "rfxswf:swftools.c Unknown fillstyle:0x%02x in tag %02d\n",type, tag->id);
520     }
521 }
522 
enumerateUsedIDs_linestyle(TAG * tag,int t,void (* callback)(TAG *,int,void *),void * callback_data,int num,int morph)523 void enumerateUsedIDs_linestyle(TAG * tag, int t, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph)
524 {
525     U16  width;
526     RGBA color;
527     width = swf_GetU16(tag);
528     char fill=0;
529     if(morph)
530 	swf_GetU16(tag);
531     if(num >= 4) {
532 	U16 flags = swf_GetU16(tag);
533 	DEBUG_ENUMERATE printf("line style %d) flags: %08x\n", t, flags);
534 	if((flags & 0x30) == 0x20) {
535 	    U16 miter = swf_GetU16(tag); // miter limit
536 	    DEBUG_ENUMERATE printf("line style %d) miter join: %08x\n", t, miter);
537 	}
538 	if(flags & 0x08) {
539 	    fill = 1;
540 	}
541     }
542     if(!fill) {
543 	if(num >= 3)
544 	    {swf_GetRGBA(tag, &color);if(morph) swf_GetRGBA(tag, NULL);}
545 	else
546 	    {swf_GetRGB(tag, &color);if(morph) swf_GetRGB(tag, NULL);}
547     } else {
548 	enumerateUsedIDs_fillstyle(tag, t, callback, callback_data, num, morph);
549     }
550     DEBUG_ENUMERATE printf("line style %d) width=%.2f color=%02x%02x%02x%02x \n", t, width/20.0, color.r,color.g,color.b,color.a);
551 }
552 
enumerateUsedIDs_styles(TAG * tag,void (* callback)(TAG *,int,void *),void * callback_data,int num,int morph)553 void enumerateUsedIDs_styles(TAG * tag, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph)
554 {
555     U16 count;
556     int t;
557     count = swf_GetU8(tag);
558     if(count == 0xff && num>1) // defineshape2,3,4 only
559 	count = swf_GetU16(tag);
560 
561     DEBUG_ENUMERATE printf("%d fill styles\n", count);
562     for(t=0;t<count;t++)
563     {
564 	enumerateUsedIDs_fillstyle(tag, t, callback, callback_data, num, morph);
565     }
566     swf_ResetReadBits(tag);
567     count = swf_GetU8(tag); // line style array
568     if(count == 0xff)
569 	count = swf_GetU16(tag);
570     DEBUG_ENUMERATE printf("%d line styles\n", count);
571     for(t=0;t<count;t++)
572     {
573 	enumerateUsedIDs_linestyle(tag, t, callback, callback_data, num, morph);
574     }
575 }
576 
enumerateUsedIDs(TAG * tag,int base,void (* callback)(TAG *,int,void *),void * callback_data)577 void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), void*callback_data)
578 {
579     int num = 1;
580     swf_ResetReadBits(tag);
581     tag->pos = 0;
582     switch(tag->id)
583     {
584 	case ST_DEFINEBUTTONSOUND: {
585 	    int t;
586 	    callback(tag, tag->pos + base, callback_data);
587 	    swf_GetU16(tag); //button id
588 	    for(t=0;t<4;t++) {
589 		int flags;
590 		callback(tag, tag->pos + base, callback_data);
591 		U16 sound_id = swf_GetU16(tag); //sound id
592 		if(!sound_id)
593 		    continue;
594 		flags = swf_GetU8(tag);
595 		if(flags&1)
596 		    swf_GetU32(tag); // in point
597 		if(flags&2)
598 		    swf_GetU32(tag); // out points
599 		if(flags&4)
600 		    swf_GetU16(tag); // loop count
601 		if(flags&8)
602 		{
603 		    int npoints = swf_GetU8(tag);
604 		    int s;
605 		    for(s=0;s<npoints;s++)
606 		    {
607 			swf_GetU32(tag);
608 			swf_GetU16(tag);
609 			swf_GetU16(tag);
610 		    }
611 		}
612 	    }
613         } break;
614 	case ST_DEFINEBUTTONCXFORM:
615 	    callback(tag, tag->pos + base, callback_data); //button id
616 	break;
617 
618 	case ST_SYMBOLCLASS:
619 	case ST_EXPORTASSETS: {
620 	    int num =  swf_GetU16(tag);
621 	    int t;
622 	    for(t=0;t<num;t++) {
623 		callback(tag, tag->pos + base, callback_data); //button id
624 		swf_GetU16(tag); //id
625 		while(swf_GetU8(tag)); //name
626 	    }
627 	} break;
628 
629 	case ST_IMPORTASSETS:
630 	case ST_IMPORTASSETS2: {
631 	    swf_GetString(tag); //count
632 	    swf_GetU8(tag); //reserved
633 	    swf_GetU8(tag); //reserved
634 	    int num =  swf_GetU16(tag); //url
635 	    int t;
636 	    for(t=0;t<num;t++) {
637 		callback(tag, tag->pos + base, callback_data); //button id
638 		swf_GetU16(tag); //id
639 		while(swf_GetU8(tag)); //name
640 	    }
641 	} break;
642 
643         case ST_DOABC:
644         case ST_RAWABC:
645         break;
646 
647 	case ST_FREECHARACTER: /* unusual tags, which all start with an ID */
648 	case ST_NAMECHARACTER:
649 	case ST_DEFINEFONTNAME:
650 	case ST_GENERATORTEXT:
651 	    callback(tag, tag->pos + base, callback_data);
652         break;
653 	case ST_PLACEOBJECT:
654 	    callback(tag, tag->pos + base, callback_data);
655         break;
656 	case ST_PLACEOBJECT2:
657 	    // only if placeflaghascharacter
658 	    if(!(tag->data[0]&2))
659 		break;
660 	    callback(tag, 3 + base, callback_data);
661         break;
662 	case ST_PLACEOBJECT3:
663 	    // only if placeflaghascharacter
664 	    if(!(tag->data[0]&2))
665 		break;
666 	    callback(tag, 4 + base, callback_data);
667         break;
668 	case ST_REMOVEOBJECT:
669 	    callback(tag, tag->pos + base, callback_data);
670 	break;
671 	case ST_STARTSOUND:
672 	    callback(tag, tag->pos + base, callback_data);
673 	break;
674 	case ST_DEFINESPRITE: {
675 	    if(tag->len <= 4)
676 		break; // sprite is expanded
677 
678 	    swf_GetU16(tag); // id
679 	    swf_GetU16(tag); // framenum
680 
681 	    while(1) {
682 		U16 flags = swf_GetU16(tag);
683 		U32 len;
684 		U16 id = flags>>6;
685 		TAG *tag2 = swf_InsertTag(NULL, id);
686 		len = flags&0x3f;
687 		if(len == 63)
688 		    len = swf_GetU32(tag);
689 		if(id == ST_END)
690 		    break;
691 		tag2->len = tag2->memsize = len;
692 		tag2->data = (U8*)rfx_alloc(len);
693 		memcpy(tag2->data, &tag->data[tag->pos], len);
694 		/* I never saw recursive sprites, but they are (theoretically)
695 		   possible, so better add base here again */
696 		enumerateUsedIDs(tag2, tag->pos + base, callback, callback_data);
697 		swf_DeleteTag(0, tag2);
698 		swf_GetBlock(tag, NULL, len);
699 	    }
700 	}
701 	break;
702 	case ST_DEFINEBUTTON2: // has some font ids in the button records
703 	    num++;
704 	//fallthrough
705 	case ST_DEFINEBUTTON: {
706 	    swf_GetU16(tag); //button id
707 	    if(num>1)
708 	    {
709 		int offset;
710 		swf_GetU8(tag); //flag
711 		offset = swf_GetU16(tag); //offset
712 	    }
713 	    while(1)
714 	    {
715 		U8 flags = swf_GetU8(tag);
716 		if(!flags) //flags
717 		    break;
718 		callback(tag, tag->pos + base, callback_data);
719 		swf_GetU16(tag); //char
720 		swf_GetU16(tag); //layer
721 		swf_ResetReadBits(tag);
722 		swf_GetMatrix(tag, NULL);
723 		if(num>1) {
724 		  swf_ResetReadBits(tag);
725 		  swf_GetCXForm(tag, NULL, 1);
726 		}
727 		if(flags&0x10) {
728 		    U8 num = swf_GetU8(tag);
729 		    int t;
730 		    for(t=0;t<num;t++) {
731 			swf_DeleteFilter(swf_GetFilter(tag));
732 		    }
733 		}
734 		if(flags&0x20) {
735 		    U8 blendmode = swf_GetU8(tag);
736 		}
737 	    }
738 	    // ...
739 	}
740 	break;
741 	case ST_DEFINEEDITTEXT:  {
742 	    U8 flags1,flags2;
743 	    swf_GetU16(tag); //id
744 	    swf_GetRect(tag, NULL); //bounding box
745 	    swf_ResetReadBits(tag);
746 	    flags1 = swf_GetU8(tag);
747 	    flags2 = swf_GetU8(tag);
748 	    if(flags1 & 1)
749 		callback(tag, tag->pos + base, callback_data);
750 	}
751 	break;
752 	case ST_DEFINETEXT2:
753 	    num ++;
754 	case ST_DEFINETEXT: {
755 	    int glyphbits, advancebits;
756 	    int id;
757 	    id = swf_GetU16(tag); //id
758 	    swf_GetRect(tag, NULL); //bounding box
759 	    swf_ResetReadBits(tag);
760 	    swf_GetMatrix(tag, NULL); //matrix
761 	    swf_ResetReadBits(tag);
762 	    glyphbits = swf_GetU8(tag); //glyphbits
763 	    advancebits = swf_GetU8(tag); //advancebits
764 	    while(1) {
765 		U16 flags;
766 		int t;
767 		swf_ResetReadBits(tag);
768 		flags = swf_GetBits(tag, 8);
769 		if(!flags) break;
770 
771 		swf_ResetReadBits(tag);
772 		if(flags & 8) { // hasfont
773 		    callback(tag, tag->pos + base, callback_data);
774 		    id = swf_GetU16(tag);
775 		}
776 		if(flags & 4) { // hascolor
777 		    if(num==1) swf_GetRGB(tag, NULL);
778 		    else       swf_GetRGBA(tag, NULL);
779 		}
780 		if(flags & 2) { //has x offset
781 		    swf_ResetReadBits(tag);
782 		    swf_GetU16(tag);
783 		}
784 		if(flags & 1) { //has y offset
785 		    swf_ResetReadBits(tag);
786 		    swf_GetU16(tag);
787 		}
788 		if(flags & 8) { //has height
789 		    swf_ResetReadBits(tag);
790 		    swf_GetU16(tag);
791 		}
792 
793 		flags = swf_GetBits(tag, 8);
794 		if(!flags) break;
795 		swf_ResetReadBits(tag);
796 		for(t=0;t<flags;t++) {
797 		    swf_GetBits(tag, glyphbits);
798 		    swf_GetBits(tag, advancebits);
799 		}
800 	    }
801 	    break;
802 	}
803 	case ST_DEFINEFONTALIGNZONES:
804 	case ST_DEFINESCALINGGRID:
805 	case ST_GLYPHNAMES:
806 	case ST_CSMTEXTSETTINGS:
807 	case ST_DEFINEFONTINFO:
808 	case ST_DEFINEFONTINFO2:
809 	case ST_VIDEOFRAME:
810 	    callback(tag, tag->pos + base, callback_data);
811 	break;
812 	case ST_DEFINEVIDEOSTREAM:
813 	break;
814 
815 	case ST_DOINITACTION:
816 	    callback(tag, tag->pos + base, callback_data);
817 	break;
818 
819 	case ST_DEFINEMORPHSHAPE2:
820 	case ST_DEFINESHAPE4:
821 	num++;
822 	case ST_DEFINEMORPHSHAPE:
823 	case ST_DEFINESHAPE3:
824 	num++; //fallthrough
825 	case ST_DEFINESHAPE2:
826 	num++; //fallthrough
827 	case ST_DEFINESHAPE: {
828 	    int fillbits;
829 	    int linebits;
830 	    int id;
831 	    int numshapes = 1;
832 	    int morph = 0;
833 	    if(tag->id == ST_DEFINEMORPHSHAPE || tag->id==ST_DEFINEMORPHSHAPE2) {
834 		numshapes = 2;
835 		morph = 1;
836 	    }
837 
838 	    id = swf_GetU16(tag); // id;
839 	    SRECT r={0,0,0,0},r2={0,0,0,0};
840 	    swf_GetRect(tag, &r); // shape bounds
841 	    if(morph) {
842 		swf_ResetReadBits(tag);
843 		swf_GetRect(tag, NULL); // shape bounds2
844 		if(num>=4) {
845 		    swf_ResetReadBits(tag);
846 		    swf_GetRect(tag, NULL); // edge bounds1
847 		}
848 	    }
849 	    if(num>=4) {
850 		swf_ResetReadBits(tag);
851 		swf_GetRect(tag, &r2); // edge bounds
852 		U8 flags = swf_GetU8(tag); // flags, &1: contains scaling stroke, &2: contains non-scaling stroke
853 		DEBUG_ENUMERATE printf("flags: %02x (1=scaling strokes, 2=non-scaling strokes)\n", flags);
854 	    }
855 	    if(morph) {
856 		swf_GetU32(tag); //offset to endedges
857 	    }
858 
859 	    DEBUG_ENUMERATE printf("Tag:%d Name:%s ID:%d\n", tag->id, swf_TagGetName(tag), id);
860 	    DEBUG_ENUMERATE printf("BBox %.2f %.2f %.2f %.2f\n", r.xmin/20.0,r.ymin/20.0,r.xmax/20.0,r.ymax/20.0);
861 	    DEBUG_ENUMERATE printf("BBox %.2f %.2f %.2f %.2f\n", r2.xmin/20.0,r2.ymin/20.0,r2.xmax/20.0,r2.ymax/20.0);
862 
863 	    DEBUG_ENUMERATE printf("style tag pos: %d\n", tag->pos);
864 	    enumerateUsedIDs_styles(tag, callback, callback_data, num, morph);
865 	    DEBUG_ENUMERATE printf("-------\n");
866 	    swf_ResetReadBits(tag);
867 	    while(--numshapes>=0) /* morph shapes define two shapes */
868 	    {
869 		DEBUG_ENUMERATE printf("shape:%d\n", numshapes);
870 		fillbits = swf_GetBits(tag, 4);
871 		linebits = swf_GetBits(tag, 4);
872 		DEBUG_ENUMERATE printf("fillbits=%d linebits=%d\n", fillbits, linebits);
873 		swf_ResetReadBits(tag);
874 		int x=0,y=0;
875 		while(1) {
876 		    int flags;
877 		    flags = swf_GetBits(tag, 1);
878 		    if(!flags) { //style change
879 			flags = swf_GetBits(tag, 5);
880 			if(!flags)
881 			    break;
882 			if(flags&1) { //move
883 			    int n = swf_GetBits(tag, 5);
884 			    x = swf_GetBits(tag, n); //x
885 			    y = swf_GetBits(tag, n); //y
886 			    DEBUG_ENUMERATE printf("moveTo %.2f %.2f\n",x/20.0,y/20.0);
887 			}
888 			if(flags&2) { //fill0
889 			    int fill0;
890 			    fill0 = swf_GetBits(tag, fillbits);
891 			    DEBUG_ENUMERATE printf("fill0 %d\n", fill0);
892 			}
893 			if(flags&4) { //fill1
894 			    int fill1;
895 			    fill1 = swf_GetBits(tag, fillbits);
896 			    DEBUG_ENUMERATE printf("fill1 %d\n", fill1);
897 			}
898 			if(flags&8) { //linestyle
899 			    int line;
900 			    line = swf_GetBits(tag, linebits);
901 			    DEBUG_ENUMERATE printf("linestyle %d\n",line);
902 			}
903 			if(flags&16) {
904 			    DEBUG_ENUMERATE printf("more fillstyles\n");
905 			    enumerateUsedIDs_styles(tag, callback, callback_data, num, 0);
906 			    fillbits = swf_GetBits(tag, 4);
907 			    linebits = swf_GetBits(tag, 4);
908 			}
909 		    } else {
910 			flags = swf_GetBits(tag, 1);
911 			if(flags) { //straight edge
912 			    int n = swf_GetBits(tag, 4) + 2;
913 			    if(swf_GetBits(tag, 1)) { //line flag
914 				x += swf_GetSBits(tag, n); //delta x
915 				y += swf_GetSBits(tag, n); //delta y
916 				DEBUG_ENUMERATE printf("lineTo %.2f %.2f\n",x/20.0,y/20.0);
917 			    } else {
918 				int v=swf_GetBits(tag, 1);
919 				int d;
920 				d = swf_GetSBits(tag, n); //vert/horz
921 				if(!v)
922 				    x += d;
923 				else
924 				    y += d;
925 				DEBUG_ENUMERATE printf("lineTo %.2f %.2f (%s)\n",x/20.0,y/20.0, v?"vertical":"horizontal");
926 			    }
927 			} else { //curved edge
928 			    int n = swf_GetBits(tag, 4) + 2;
929 			    int x1,y1,x2,y2;
930 			    x1 = swf_GetSBits(tag, n);
931 			    y1 = swf_GetSBits(tag, n);
932 			    x2 = swf_GetSBits(tag, n);
933 			    y2 = swf_GetSBits(tag, n);
934 			    DEBUG_ENUMERATE printf("splineTo %.2f %.2f %.2f %.2f\n", x1/20.0, y1/20.0, x2/20.0, y2/20.0);
935 			}
936 		    }
937 		}
938 	    }
939 	}
940 	break;
941 	default:
942 	break;
943     }
944 }
945 
callbackCount(TAG * t,int pos,void * ptr)946 void callbackCount(TAG * t,int pos, void*ptr)
947 {
948     (*(int*)ptr)++;
949     DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
950 }
951 
callbackFillin(TAG * t,int pos,void * ptr)952 void callbackFillin(TAG * t,int pos, void*ptr)
953 {
954     **(int**)ptr = pos;
955     (*(int**)ptr)++;
956     DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
957 }
958 
swf_GetNumUsedIDs(TAG * t)959 int swf_GetNumUsedIDs(TAG * t)
960 {
961     int num = 0;
962     enumerateUsedIDs(t, 0, callbackCount, &num);
963     return num;
964 }
965 
swf_GetUsedIDs(TAG * t,int * positions)966 void swf_GetUsedIDs(TAG * t, int * positions)
967 {
968     int * ptr = positions;
969     enumerateUsedIDs(t, 0, callbackFillin, &ptr);
970 }
971 
swf_Relocate(SWF * swf,char * bitmap)972 char swf_Relocate (SWF*swf, char*bitmap)
973 {
974     TAG*tag;
975     int slaveids[65536];
976     memset(slaveids, -1, sizeof(slaveids));
977     tag = swf->firstTag;
978     char ok = 1;
979 
980     int current_id=0;
981 #define NEW_ID(n) \
982 		for(current_id++;current_id<65536;current_id++) { \
983 		    if(!bitmap[current_id]) { \
984 			n = current_id; \
985 			break; \
986 		    } \
987 		} \
988                 if(current_id==65536) { \
989                     fprintf(stderr, "swf_Relocate: Couldn't relocate: Out of IDs\n"); \
990                     return 0; \
991                 }
992 
993     while(tag)
994     {
995 	int num;
996 	int *ptr;
997 
998 	if(swf_isDefiningTag(tag))
999 	{
1000 	    int newid;
1001 	    int id;
1002 
1003 	    id = swf_GetDefineID(tag); //own id
1004 
1005 	    if(!bitmap[id]) { //free
1006 		newid = id;
1007 	    } else if(slaveids[id]>0) {
1008 		newid = slaveids[id];
1009 	    } else {
1010 		NEW_ID(newid);
1011 	    }
1012 
1013 	    bitmap[newid] = 1;
1014 	    slaveids[id] = newid;
1015 
1016 	    swf_SetDefineID(tag, newid);
1017 	}
1018 
1019 	num = swf_GetNumUsedIDs(tag);
1020 	if(num) {
1021 	    ptr = (int*)rfx_alloc(sizeof(int)*num);
1022 	    swf_GetUsedIDs(tag, ptr);
1023 	    int t;
1024 	    for(t=0;t<num;t++) {
1025 		int id = GET16(&tag->data[ptr[t]]);
1026 		if(slaveids[id]<0) {
1027 		    if(!id && bitmap[id]) {
1028 			/* id 0 is only used in SWF versions >=9. It's the ID of
1029 			   the main timeline. It's used in e.g. SYMBOLTAG tags, but
1030 			   never defined, so if we're asked to reallocate it, we have
1031 			   to allocate an ID for it on the fly. */
1032 			int newid;
1033 			NEW_ID(newid);
1034 			bitmap[newid] = 1;
1035 			slaveids[id] = newid;
1036 			id = newid;
1037 		    } else if(!bitmap[id]) {
1038 			/* well- we don't know this id, but it's not reserved anyway, so just
1039 			   leave it alone */
1040 		    } else {
1041 			/* this actually happens with files created with Flash CS4 and never.
1042 			   Apparently e.g. DefineButton tags are able to use forward declarations of objects. */
1043 			fprintf(stderr, "warning: Mapping id (%d) never encountered before in %s\n", id,
1044 				swf_TagGetName(tag));
1045 			int newid;
1046 			NEW_ID(newid);
1047 			id = slaveids[id] = newid;
1048 			ok = 0;
1049 		    }
1050 		} else {
1051 		    id = slaveids[id];
1052 		}
1053 		PUT16(&tag->data[ptr[t]], id);
1054 	    }
1055             free(ptr);
1056 	}
1057 	tag=tag->next;
1058     }
1059     return ok;
1060 }
1061 
1062 /* untested */
swf_Relocate2(SWF * swf,int * id2id)1063 void swf_Relocate2(SWF*swf, int*id2id)
1064 {
1065     TAG*tag;
1066     tag = swf->firstTag;
1067     while(tag) {
1068 	if(swf_isDefiningTag(tag)) {
1069 	    int id = swf_GetDefineID(tag);
1070 	    id = id2id[id];
1071 	    if(id>=0) {
1072 		swf_SetDefineID(tag, id);
1073 	    }
1074 	}
1075 	int num = swf_GetNumUsedIDs(tag);
1076 	if(num) {
1077 	    int *ptr;
1078 	    int t;
1079 	    ptr = (int*)rfx_alloc(sizeof(int)*num);
1080 	    swf_GetUsedIDs(tag, ptr);
1081 	    for(t=0;t<num;t++) {
1082 		int id = GET16(&tag->data[ptr[t]]);
1083 		id = id2id[id];
1084 		if(id>=0) {
1085 		    PUT16(&tag->data[ptr[t]], id);
1086 		}
1087 	    }
1088             free(ptr);
1089 	}
1090     }
1091 }
1092 
swf_RelocateDepth(SWF * swf,char * bitmap)1093 void swf_RelocateDepth(SWF*swf, char*bitmap)
1094 {
1095     TAG*tag;
1096     int nr;
1097     tag = swf->firstTag;
1098     for(nr=65535;nr>=0;nr--) {
1099 	if(bitmap[nr] != 0)
1100 	    break;
1101     }
1102     // now nr is the highest used depth. So we start
1103     // assigning depths at nr+1
1104     nr++;
1105 
1106     while(tag)
1107     {
1108 	int depth;
1109 	/* TODO * clip depths
1110 	        * sprites
1111 	 */
1112 	if(tag->id == ST_PLACEOBJECT2) {
1113 	    SWFPLACEOBJECT obj;
1114 	    swf_GetPlaceObject(tag, &obj);
1115 	    if(obj.clipdepth) {
1116 		int newdepth = obj.clipdepth+nr;
1117 		if(newdepth>65535) {
1118 		    fprintf(stderr, "Couldn't relocate depths: too large values\n");
1119 		    newdepth = 65535;
1120 		}
1121 		obj.clipdepth = newdepth;
1122 		swf_ResetTag(tag, ST_PLACEOBJECT2);
1123 		swf_SetPlaceObject(tag, &obj);
1124 	    }
1125 	    swf_PlaceObjectFree(&obj);
1126 	}
1127 
1128 	depth = swf_GetDepth(tag);
1129 	if(depth>=0) {
1130 	    int newdepth = depth+nr;
1131 	    if(newdepth>65535) {
1132 		fprintf(stderr, "Couldn't relocate depths: too large values\n");
1133 		newdepth = 65535;
1134 	    }
1135 	    swf_SetDepth(tag, newdepth);
1136 	}
1137 	tag=tag->next;
1138     }
1139 }
1140 
swf_isShapeTag(TAG * tag)1141 U8 swf_isShapeTag(TAG*tag)
1142 {
1143     if(tag->id == ST_DEFINESHAPE ||
1144        tag->id == ST_DEFINESHAPE2 ||
1145        tag->id == ST_DEFINESHAPE3 ||
1146        tag->id == ST_DEFINESHAPE4)
1147         return 1;
1148     return 0;
1149 }
1150 
swf_isPlaceTag(TAG * tag)1151 U8 swf_isPlaceTag(TAG*tag)
1152 {
1153     if(tag->id == ST_PLACEOBJECT ||
1154        tag->id == ST_PLACEOBJECT2 ||
1155        tag->id == ST_PLACEOBJECT3)
1156         return 1;
1157     return 0;
1158 }
swf_isTextTag(TAG * tag)1159 U8 swf_isTextTag(TAG*tag)
1160 {
1161     if(tag->id == ST_DEFINETEXT ||
1162        tag->id == ST_DEFINETEXT2)
1163         return 1;
1164     return 0;
1165 }
1166 
swf_isFontTag(TAG * tag)1167 U8 swf_isFontTag(TAG*tag)
1168 {
1169     if(tag->id == ST_DEFINEFONT ||
1170        tag->id == ST_DEFINEFONT2 ||
1171        tag->id == ST_DEFINEFONT3 ||
1172        tag->id == ST_DEFINEFONTINFO)
1173         return 1;
1174     return 0;
1175 }
1176 
swf_isImageTag(TAG * tag)1177 U8  swf_isImageTag(TAG*tag)
1178 {
1179     if(tag->id == ST_DEFINEBITSJPEG ||
1180        tag->id == ST_DEFINEBITSJPEG2 ||
1181        tag->id == ST_DEFINEBITSJPEG3 ||
1182        tag->id == ST_DEFINEBITSLOSSLESS ||
1183        tag->id == ST_DEFINEBITSLOSSLESS2)
1184         return 1;
1185     return 0;
1186 }
1187 
swf_Concatenate(TAG * list1,TAG * list2)1188 TAG* swf_Concatenate (TAG*list1,TAG*list2)
1189 {
1190     TAG*tag=0,*lasttag=0;
1191     char bitmap[65536];
1192     char depthmap[65536];
1193     SWF swf1,swf2;
1194     memset(bitmap, 0, sizeof(bitmap));
1195     memset(depthmap, 0, sizeof(depthmap));
1196     memset(&swf1, 0, sizeof(swf1));
1197     memset(&swf2, 0, sizeof(swf2));
1198 
1199     swf1.firstTag = list1;
1200     swf_FoldAll(&swf1);
1201     swf2.firstTag = list2;
1202     swf_FoldAll(&swf2);
1203 
1204     tag = list1;
1205     while(tag) {
1206 	if(!swf_isDefiningTag(tag)) {
1207 	    int id = swf_GetDefineID(tag);
1208 	    bitmap[id] = 1;
1209 	}
1210 	if(tag->id == ST_PLACEOBJECT ||
1211 	   tag->id == ST_PLACEOBJECT2) {
1212 	    int depth = swf_GetDepth(tag);
1213 	    depthmap[depth] = 1;
1214 	}
1215 	if(tag->id == ST_REMOVEOBJECT ||
1216 	   tag->id == ST_REMOVEOBJECT2) {
1217 	    int depth = swf_GetDepth(tag);
1218 	    depthmap[depth] = 0;
1219 	}
1220 	tag = tag->next;
1221 	lasttag = tag;
1222     }
1223     swf_Relocate(&swf2, bitmap);
1224     swf_RelocateDepth(&swf2, depthmap);
1225     lasttag->next = swf2.firstTag;
1226     swf2.firstTag->prev = lasttag;
1227 
1228     return swf1.firstTag;
1229 }
1230 
tagHash(TAG * tag)1231 static int tagHash(TAG*tag)
1232 {
1233     int t, h=0;
1234     unsigned int a = 0x6b973e5a;
1235     /* start at pos 2, as 0 and 1 are the id */
1236     for(t=2;t<tag->len;t++) {
1237         unsigned int b = a;
1238         a >>= 8;
1239         a += tag->data[t]*0xefbc35a5*b*(t+1);
1240     }
1241     return a&0x7fffffff; //always return positive number
1242 }
1243 
swf_Optimize(SWF * swf)1244 void swf_Optimize(SWF*swf)
1245 {
1246     const int hash_size = 131072;
1247     char* dontremap = (char*)rfx_calloc(sizeof(char)*65536);
1248     U16* remap = (U16*)rfx_alloc(sizeof(U16)*65536);
1249     TAG* id2tag = (TAG*)rfx_calloc(sizeof(TAG*)*65536);
1250     TAG** hashmap = (TAG**)rfx_calloc(sizeof(TAG*)*hash_size);
1251     TAG* tag;
1252     int t;
1253     for(t=0;t<65536;t++) {
1254         remap[t] = t;
1255     }
1256 
1257     swf_FoldAll(swf);
1258 
1259     tag = swf->firstTag;
1260     while(tag) {
1261         /* make sure we don't remap to this tag,
1262            as it might have different "helper tags"
1263            FIXME: a better way would be to compare
1264                   the helper tags, too.
1265          */
1266         if(swf_isPseudoDefiningTag(tag) &&
1267            tag->id != ST_NAMECHARACTER) {
1268             dontremap[swf_GetDefineID(tag)] = 1;
1269         }
1270         tag=tag->next;
1271     }
1272     tag = swf->firstTag;
1273     while(tag) {
1274         TAG*next = tag->next;
1275 
1276         /* remap the tag */
1277         int num = swf_GetNumUsedIDs(tag);
1278         int*positions = (int*)rfx_alloc(sizeof(int)*num);
1279         int t;
1280         swf_GetUsedIDs(tag, positions);
1281         for(t=0;t<num;t++) {
1282             int id = GET16(&tag->data[positions[t]]);
1283             id = remap[id];
1284             PUT16(&tag->data[positions[t]], id);
1285         }
1286         rfx_free(positions);
1287 
1288         /* now look for previous tags with the same
1289            content */
1290         if(swf_isDefiningTag(tag)) {
1291             TAG*tag2;
1292             int id = swf_GetDefineID(tag);
1293             int hash = tagHash(tag);
1294             int match=0;
1295             if(!dontremap[id])
1296             while((tag2 = hashmap[hash%hash_size])) {
1297                 if(tag2 != (TAG*)0 && tag->len == tag2->len) {
1298 		    if(memcmp(&tag->data[2],&tag2->data[2],tag->len-2) == 0) {
1299 			match = 1;
1300 			break;
1301 		    }
1302                 }
1303                 hash++;
1304             }
1305             if(!match) {
1306                 while(hashmap[hash%hash_size]) hash++;
1307                 hashmap[hash%hash_size] = tag;
1308             } else {
1309 		/* we found two identical tags- remap one
1310 		   of them */
1311                 remap[id] = swf_GetDefineID(tag2);
1312                 swf_DeleteTag(swf, tag);
1313             }
1314         } else if(swf_isPseudoDefiningTag(tag)) {
1315             int id = swf_GetDefineID(tag);
1316             if(remap[id]!=id) {
1317                 /* if this tag was remapped, we don't
1318                    need the helper tag anymore. Discard
1319                    it. */
1320                 swf_DeleteTag(swf, tag);
1321             }
1322         }
1323 
1324         tag = next;
1325     }
1326 
1327     rfx_free(dontremap);
1328     rfx_free(remap);
1329     rfx_free(id2tag);
1330     rfx_free(hashmap);
1331 }
1332 
swf_SetDefineBBox(TAG * tag,SRECT newbbox)1333 void swf_SetDefineBBox(TAG * tag, SRECT newbbox)
1334 {
1335     U16 id = 0;
1336     SRECT b1;
1337     swf_SetTagPos(tag,0);
1338 
1339     switch (swf_GetTagID(tag))
1340     {
1341 	case ST_DEFINESHAPE:
1342 	case ST_DEFINESHAPE2:
1343 	case ST_DEFINESHAPE3:
1344 	case ST_DEFINEEDITTEXT:
1345 	case ST_DEFINETEXT:
1346 	case ST_DEFINETEXT2:
1347 	case ST_DEFINEVIDEOSTREAM: {
1348 	      U32 after_bbox_offset = 0, len;
1349 	      U8*data;
1350 	      id = swf_GetU16(tag);
1351 	      swf_GetRect(tag, &b1);
1352 	      swf_ResetReadBits(tag);
1353 	      after_bbox_offset = tag->pos;
1354 	      len = tag->len - after_bbox_offset;
1355 	      data = (U8*)malloc(len);
1356 	      memcpy(data, &tag->data[after_bbox_offset], len);
1357 	      tag->writeBit = 0;
1358 	      tag->len = 2;
1359 	      swf_SetRect(tag, &newbbox);
1360 	      swf_SetBlock(tag, data, len);
1361 	      free(data);
1362 	      tag->pos = tag->readBit = 0;
1363 
1364 	} break;
1365 	default:
1366 	    fprintf(stderr, "rfxswf: Tag %d (%s) has no bbox\n", tag->id, swf_TagGetName(tag));
1367     }
1368 }
1369 
swf_GetSWFBackgroundColor(SWF * swf)1370 RGBA swf_GetSWFBackgroundColor(SWF*swf)
1371 {
1372     TAG*t=swf->firstTag;
1373     RGBA color;
1374     color.r = color.b = color.g = 0;
1375     color.a = 255;
1376     while(t) {
1377 	if(t->id == ST_SETBACKGROUNDCOLOR) {
1378 	    swf_SetTagPos(t, 0);
1379 	    color.r = swf_GetU8(t);
1380 	    color.g = swf_GetU8(t);
1381 	    color.b = swf_GetU8(t);
1382 	    break;
1383 	}
1384 	t=t->next;
1385     }
1386     return color;
1387 }
1388 
1389