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