3 Math and matrix functions, misc tools
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2000, 2001 Rainer Böhme <rfxswf@reflex-studio.de>
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.
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.
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 */
24 // Matrix & Math tools for SWF files
26 #include "../rfxswf.h"
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);
33 fprintf(stderr, "Warning: overflow in matrix multiplication\n");
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;
43 MATRIX * swf_MatrixJoin(MATRIX * d,MATRIX * s1,MATRIX * s2)
46 if (!s1) return (s2)?(MATRIX *)memcpy(d,s2,sizeof(MATRIX)):NULL;
47 if (!s2) return (MATRIX *)memcpy(d,s1,sizeof(MATRIX));
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);
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);
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);
63 MATRIX * swf_MatrixMapTriangle(MATRIX * m,int dx,int dy,int x0,int y0,
64 int x1,int y1,int x2,int y2)
71 if ((!dx)||(!dy)) return NULL; // check DIV by zero
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);
83 void swf_SetDefineID(TAG * tag, U16 newid)
85 int oldlen = tag->len;
87 swf_SetU16(tag, newid); /* set defining ID */
91 U16 swf_GetDefineID(TAG * t)
96 oldTagPos = swf_GetTagPos(t);
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:
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
121 case ST_DEFINEFONTINFO: //pseudodefine
122 case ST_DEFINEFONTINFO2: //pseudodefine
123 case ST_DEFINEFONTALIGNZONES: //pseudodefine
124 case ST_DEFINEFONTNAME: //pseudodefine
126 case ST_DEFINEBINARY:
129 case ST_DEFINESPRITE:
131 case ST_DEFINEVIDEOSTREAM:
132 case ST_GLYPHNAMES: //pseudodefine
133 case ST_VIDEOFRAME: //pseudodefine
134 case ST_NAMECHARACTER: //pseudodefine
135 case ST_DOINITACTION: //pseudodefine
139 fprintf(stderr, "rfxswf: Error: tag %d (%s) has no id\n", t->id, swf_TagGetName(t));
142 swf_SetTagPos(t,oldTagPos);
147 SRECT swf_GetDefineBBox(TAG * t)
152 memset(&b1, 0, sizeof(b1));
154 oldTagPos = swf_GetTagPos(t);
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:
167 case ST_DEFINEVIDEOSTREAM:
171 case ST_DEFINEMORPHSHAPE:
175 swf_ExpandRect2(&b1, &b2);
177 case ST_DEFINEBITSLOSSLESS:
178 case ST_DEFINEBITSLOSSLESS2:
180 case ST_DEFINEBITSJPEG2:
181 case ST_DEFINEBITSJPEG3:
186 swf_SetTagPos(t,oldTagPos);
191 U16 swf_GetPlaceID(TAG * t)
196 oldTagPos = swf_GetTagPos(t);
199 switch (swf_GetTagID(t))
200 { case ST_PLACEOBJECT:
201 case ST_REMOVEOBJECT:
202 case ST_FREECHARACTER:
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;
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;
221 swf_SetTagPos(t,oldTagPos);
226 static int swf_definingtagids[] =
232 ST_DEFINEMORPHSHAPE2,
242 ST_DEFINEBITSLOSSLESS,
243 ST_DEFINEBITSLOSSLESS2,
249 ST_DEFINEVIDEOSTREAM,
254 // tags which may be used inside a sprite definition
255 static int swf_spritetagids[] =
273 /* tags which add content or information to a character with a given ID */
274 static int swf_pseudodefiningtagids[] =
278 ST_DEFINEFONTALIGNZONES,
280 ST_DEFINEBUTTONCXFORM,
281 ST_DEFINEBUTTONSOUND,
282 ST_DEFINESCALINGGRID,
291 U8 swf_isAllowedSpriteTag(TAG * tag)
295 while(swf_spritetagids[t]>=0)
297 if(swf_spritetagids[t] == id)
304 U8 swf_isDefiningTag(TAG * tag)
308 while(swf_definingtagids[t]>=0)
310 if(swf_definingtagids[t] == id)
317 U8 swf_isPseudoDefiningTag(TAG * tag)
321 while(swf_pseudodefiningtagids[t]>=0)
323 if(swf_pseudodefiningtagids[t] == id)
330 int swf_GetDepth(TAG * t)
334 oldTagPos = swf_GetTagPos(t);
337 switch (swf_GetTagID(t))
338 { case ST_PLACEOBJECT:
339 case ST_REMOVEOBJECT:
341 depth = swf_GetU16(t);
343 case ST_REMOVEOBJECT2:
344 depth = swf_GetU16(t);
346 case ST_PLACEOBJECT2:
347 { U8 flags = swf_GetU8(t);
348 depth = swf_GetU16(t);
350 case ST_PLACEOBJECT3:
351 { U8 flags = swf_GetU8(t);
352 U8 flags2 = swf_GetU8(t);
353 depth = swf_GetU16(t);
357 depth = swf_GetU16(t);
360 swf_SetTagPos(t,oldTagPos);
364 void swf_SetDepth(TAG * t, U16 depth)
366 switch (swf_GetTagID(t))
367 { case ST_PLACEOBJECT:
368 case ST_REMOVEOBJECT:
369 PUT16(t->data, depth);
371 case ST_REMOVEOBJECT2:
372 PUT16(t->data, depth);
374 case ST_PLACEOBJECT2:
375 PUT16(&t->data[1], depth);
378 PUT16(t->data, depth);
381 fprintf(stderr, "rfxswf: Error: tag %d has no depth\n", t->id);
385 char* swf_GetName(TAG * t)
391 oldTagPos = swf_GetTagPos(t);
393 switch(swf_GetTagID(t))
396 name = (char*)&t->data[swf_GetTagPos(t)];
398 case ST_PLACEOBJECT3:
399 case ST_PLACEOBJECT2: {
400 U8 flags = swf_GetU8(t);
401 if(t->id == ST_PLACEOBJECT3)
403 swf_GetU16(t); //depth;
407 swf_GetMatrix(t, &m);
409 swf_GetCXForm(t, &c, 1);
412 if(flags&PF_CLIPDEPTH)
415 swf_ResetReadBits(t);
416 name = (char*)&t->data[swf_GetTagPos(t)];
421 swf_SetTagPos(t,oldTagPos);
425 /* used in enumerateUsedIDs */
426 void swf_GetMorphGradient(TAG * tag, GRADIENT * gradient1, GRADIENT * gradient2)
429 int num = swf_GetU8(tag) & 15;
430 if(gradient1) gradient1->num = num;
431 if(gradient2) gradient2->num = num;
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);
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);
448 ratio = swf_GetU8(tag);
449 swf_GetRGBA(tag, &color);
451 gradient1->ratios[t] = ratio;
452 gradient1->rgba[t] = color;
455 ratio = swf_GetU8(tag);
456 swf_GetRGBA(tag, &color);
458 gradient2->ratios[t] = ratio;
459 gradient2->rgba[t] = color;
464 #define DEBUG_ENUMERATE if(0)
465 //#define DEBUG_ENUMERATE
467 void enumerateUsedIDs_fillstyle(TAG * tag, int t, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph)
470 type = swf_GetU8(tag); //type
471 DEBUG_ENUMERATE printf("fill style %d) type=%02x (tagpos=%d)\n", t, type, tag->pos);
475 {swf_GetRGBA(tag, &color);if(morph) swf_GetRGBA(tag, NULL);}
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);
480 else if(type == 0x10 || type == 0x12 || type == 0x13)
482 swf_ResetReadBits(tag);
484 swf_GetMatrix(tag, &m);
485 DEBUG_ENUMERATE swf_DumpMatrix(stdout, &m);
487 swf_GetMatrix(tag, &m);
488 DEBUG_ENUMERATE swf_DumpMatrix(stdout, &m);
490 swf_ResetReadBits(tag);
492 swf_GetMorphGradient(tag, NULL, NULL);
499 swf_GetGradient(tag, &g, /*alpha*/ num>=3?1:0);
500 DEBUG_ENUMERATE swf_DumpGradient(stdout, &g);
505 else if(type == 0x40 || type == 0x41 || type == 0x42 || type == 0x43)
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);
513 swf_ResetReadBits(tag);
514 swf_GetMatrix(tag, NULL);
516 swf_GetMatrix(tag, NULL);
519 fprintf(stderr, "rfxswf:swftools.c Unknown fillstyle:0x%02x in tag %02d\n",type, tag->id);
523 void enumerateUsedIDs_linestyle(TAG * tag, int t, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph)
527 width = swf_GetU16(tag);
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);
544 {swf_GetRGBA(tag, &color);if(morph) swf_GetRGBA(tag, NULL);}
546 {swf_GetRGB(tag, &color);if(morph) swf_GetRGB(tag, NULL);}
548 enumerateUsedIDs_fillstyle(tag, t, callback, callback_data, num, morph);
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);
553 void enumerateUsedIDs_styles(TAG * tag, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph)
557 count = swf_GetU8(tag);
558 if(count == 0xff && num>1) // defineshape2,3,4 only
559 count = swf_GetU16(tag);
561 DEBUG_ENUMERATE printf("%d fill styles\n", count);
564 enumerateUsedIDs_fillstyle(tag, t, callback, callback_data, num, morph);
566 swf_ResetReadBits(tag);
567 count = swf_GetU8(tag); // line style array
569 count = swf_GetU16(tag);
570 DEBUG_ENUMERATE printf("%d line styles\n", count);
573 enumerateUsedIDs_linestyle(tag, t, callback, callback_data, num, morph);
577 void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), void*callback_data)
580 swf_ResetReadBits(tag);
584 case ST_DEFINEBUTTONSOUND: {
586 callback(tag, tag->pos + base, callback_data);
589 callback(tag, tag->pos + base, callback_data);
590 swf_GetU16(tag); //sound id
591 flags = swf_GetU8(tag);
593 swf_GetU32(tag); // in point
595 swf_GetU32(tag); // out points
597 swf_GetU16(tag); // loop count
600 int npoints = swf_GetU8(tag);
602 for(s=0;s<npoints;s++)
611 case ST_DEFINEBUTTONCXFORM:
612 callback(tag, tag->pos + base, callback_data); //button id
616 case ST_EXPORTASSETS: {
617 int num = swf_GetU16(tag);
620 callback(tag, tag->pos + base, callback_data); //button id
621 swf_GetU16(tag); //id
622 while(swf_GetU8(tag)); //name
626 case ST_IMPORTASSETS:
627 case ST_IMPORTASSETS2: {
628 swf_GetString(tag); //count
629 swf_GetU8(tag); //reserved
630 swf_GetU8(tag); //reserved
631 int num = swf_GetU16(tag); //url
634 callback(tag, tag->pos + base, callback_data); //button id
635 swf_GetU16(tag); //id
636 while(swf_GetU8(tag)); //name
644 case ST_FREECHARACTER: /* unusual tags, which all start with an ID */
645 case ST_NAMECHARACTER:
646 case ST_DEFINEFONTNAME:
647 case ST_GENERATORTEXT:
648 callback(tag, tag->pos + base, callback_data);
651 callback(tag, tag->pos + base, callback_data);
653 case ST_PLACEOBJECT2:
654 // only if placeflaghascharacter
655 if(!(tag->data[0]&2))
657 callback(tag, 3 + base, callback_data);
659 case ST_PLACEOBJECT3:
660 // only if placeflaghascharacter
661 if(!(tag->data[0]&2))
663 callback(tag, 4 + base, callback_data);
665 case ST_REMOVEOBJECT:
666 callback(tag, tag->pos + base, callback_data);
669 callback(tag, tag->pos + base, callback_data);
671 case ST_DEFINESPRITE: {
673 break; // sprite is expanded
675 swf_GetU16(tag); // id
676 swf_GetU16(tag); // framenum
679 U16 flags = swf_GetU16(tag);
682 TAG *tag2 = swf_InsertTag(NULL, id);
685 len = swf_GetU32(tag);
688 tag2->len = tag2->memsize = len;
689 tag2->data = (U8*)rfx_alloc(len);
690 memcpy(tag2->data, &tag->data[tag->pos], len);
691 /* I never saw recursive sprites, but they are (theoretically)
692 possible, so better add base here again */
693 enumerateUsedIDs(tag2, tag->pos + base, callback, callback_data);
694 swf_DeleteTag(0, tag2);
695 swf_GetBlock(tag, NULL, len);
699 case ST_DEFINEBUTTON2: // has some font ids in the button records
702 case ST_DEFINEBUTTON: {
703 swf_GetU16(tag); //button id
707 swf_GetU8(tag); //flag
708 offset = swf_GetU16(tag); //offset
712 U8 flags = swf_GetU8(tag);
715 callback(tag, tag->pos + base, callback_data);
716 swf_GetU16(tag); //char
717 swf_GetU16(tag); //layer
718 swf_ResetReadBits(tag);
719 swf_GetMatrix(tag, NULL);
721 swf_ResetReadBits(tag);
722 swf_GetCXForm(tag, NULL, 1);
725 U8 num = swf_GetU8(tag);
728 swf_DeleteFilter(swf_GetFilter(tag));
732 U8 blendmode = swf_GetU8(tag);
738 case ST_DEFINEEDITTEXT: {
740 swf_GetU16(tag); //id
741 swf_GetRect(tag, NULL); //bounding box
742 swf_ResetReadBits(tag);
743 flags1 = swf_GetU8(tag);
744 flags2 = swf_GetU8(tag);
746 callback(tag, tag->pos + base, callback_data);
751 case ST_DEFINETEXT: {
752 int glyphbits, advancebits;
754 id = swf_GetU16(tag); //id
755 swf_GetRect(tag, NULL); //bounding box
756 swf_ResetReadBits(tag);
757 swf_GetMatrix(tag, NULL); //matrix
758 swf_ResetReadBits(tag);
759 glyphbits = swf_GetU8(tag); //glyphbits
760 advancebits = swf_GetU8(tag); //advancebits
764 swf_ResetReadBits(tag);
765 flags = swf_GetBits(tag, 8);
768 swf_ResetReadBits(tag);
769 if(flags & 8) { // hasfont
770 callback(tag, tag->pos + base, callback_data);
771 id = swf_GetU16(tag);
773 if(flags & 4) { // hascolor
774 if(num==1) swf_GetRGB(tag, NULL);
775 else swf_GetRGBA(tag, NULL);
777 if(flags & 2) { //has x offset
778 swf_ResetReadBits(tag);
781 if(flags & 1) { //has y offset
782 swf_ResetReadBits(tag);
785 if(flags & 8) { //has height
786 swf_ResetReadBits(tag);
790 flags = swf_GetBits(tag, 8);
792 swf_ResetReadBits(tag);
793 for(t=0;t<flags;t++) {
794 swf_GetBits(tag, glyphbits);
795 swf_GetBits(tag, advancebits);
800 case ST_DEFINEFONTALIGNZONES:
801 case ST_DEFINESCALINGGRID:
803 case ST_CSMTEXTSETTINGS:
804 case ST_DEFINEFONTINFO:
805 case ST_DEFINEFONTINFO2:
807 callback(tag, tag->pos + base, callback_data);
809 case ST_DEFINEVIDEOSTREAM:
812 case ST_DOINITACTION:
813 callback(tag, tag->pos + base, callback_data);
816 case ST_DEFINEMORPHSHAPE2:
817 case ST_DEFINESHAPE4:
819 case ST_DEFINEMORPHSHAPE:
820 case ST_DEFINESHAPE3:
822 case ST_DEFINESHAPE2:
824 case ST_DEFINESHAPE: {
830 if(tag->id == ST_DEFINEMORPHSHAPE || tag->id==ST_DEFINEMORPHSHAPE2) {
835 id = swf_GetU16(tag); // id;
836 SRECT r={0,0,0,0},r2={0,0,0,0};
837 swf_GetRect(tag, &r); // shape bounds
839 swf_ResetReadBits(tag);
840 swf_GetRect(tag, NULL); // shape bounds2
842 swf_ResetReadBits(tag);
843 swf_GetRect(tag, NULL); // edge bounds1
847 swf_ResetReadBits(tag);
848 swf_GetRect(tag, &r2); // edge bounds
849 U8 flags = swf_GetU8(tag); // flags, &1: contains scaling stroke, &2: contains non-scaling stroke
850 DEBUG_ENUMERATE printf("flags: %02x (1=scaling strokes, 2=non-scaling strokes)\n", flags);
853 swf_GetU32(tag); //offset to endedges
856 DEBUG_ENUMERATE printf("Tag:%d Name:%s ID:%d\n", tag->id, swf_TagGetName(tag), id);
857 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);
858 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);
860 DEBUG_ENUMERATE printf("style tag pos: %d\n", tag->pos);
861 enumerateUsedIDs_styles(tag, callback, callback_data, num, morph);
862 DEBUG_ENUMERATE printf("-------\n");
863 swf_ResetReadBits(tag);
864 while(--numshapes>=0) /* morph shapes define two shapes */
866 DEBUG_ENUMERATE printf("shape:%d\n", numshapes);
867 fillbits = swf_GetBits(tag, 4);
868 linebits = swf_GetBits(tag, 4);
869 DEBUG_ENUMERATE printf("fillbits=%d linebits=%d\n", fillbits, linebits);
870 swf_ResetReadBits(tag);
874 flags = swf_GetBits(tag, 1);
875 if(!flags) { //style change
876 flags = swf_GetBits(tag, 5);
880 int n = swf_GetBits(tag, 5);
881 x = swf_GetBits(tag, n); //x
882 y = swf_GetBits(tag, n); //y
883 DEBUG_ENUMERATE printf("moveTo %.2f %.2f\n",x/20.0,y/20.0);
885 if(flags&2) { //fill0
887 fill0 = swf_GetBits(tag, fillbits);
888 DEBUG_ENUMERATE printf("fill0 %d\n", fill0);
890 if(flags&4) { //fill1
892 fill1 = swf_GetBits(tag, fillbits);
893 DEBUG_ENUMERATE printf("fill1 %d\n", fill1);
895 if(flags&8) { //linestyle
897 line = swf_GetBits(tag, linebits);
898 DEBUG_ENUMERATE printf("linestyle %d\n",line);
901 DEBUG_ENUMERATE printf("more fillstyles\n");
902 enumerateUsedIDs_styles(tag, callback, callback_data, num, 0);
903 fillbits = swf_GetBits(tag, 4);
904 linebits = swf_GetBits(tag, 4);
907 flags = swf_GetBits(tag, 1);
908 if(flags) { //straight edge
909 int n = swf_GetBits(tag, 4) + 2;
910 if(swf_GetBits(tag, 1)) { //line flag
911 x += swf_GetSBits(tag, n); //delta x
912 y += swf_GetSBits(tag, n); //delta y
913 DEBUG_ENUMERATE printf("lineTo %.2f %.2f\n",x/20.0,y/20.0);
915 int v=swf_GetBits(tag, 1);
917 d = swf_GetSBits(tag, n); //vert/horz
922 DEBUG_ENUMERATE printf("lineTo %.2f %.2f (%s)\n",x/20.0,y/20.0, v?"vertical":"horizontal");
924 } else { //curved edge
925 int n = swf_GetBits(tag, 4) + 2;
927 x1 = swf_GetSBits(tag, n);
928 y1 = swf_GetSBits(tag, n);
929 x2 = swf_GetSBits(tag, n);
930 y2 = swf_GetSBits(tag, n);
931 DEBUG_ENUMERATE printf("splineTo %.2f %.2f %.2f %.2f\n", x1/20.0, y1/20.0, x2/20.0, y2/20.0);
943 void callbackCount(TAG * t,int pos, void*ptr)
946 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
949 void callbackFillin(TAG * t,int pos, void*ptr)
953 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
956 int swf_GetNumUsedIDs(TAG * t)
959 enumerateUsedIDs(t, 0, callbackCount, &num);
963 void swf_GetUsedIDs(TAG * t, int * positions)
965 int * ptr = positions;
966 enumerateUsedIDs(t, 0, callbackFillin, &ptr);
969 char swf_Relocate (SWF*swf, char*bitmap)
973 memset(slaveids, -1, sizeof(slaveids));
979 for(current_id++;current_id<65536;current_id++) { \
980 if(!bitmap[current_id]) { \
985 if(current_id==65536) { \
986 fprintf(stderr, "swf_Relocate: Couldn't relocate: Out of IDs\n"); \
995 if(swf_isDefiningTag(tag))
1000 id = swf_GetDefineID(tag); //own id
1002 if(!bitmap[id]) { //free
1004 } else if(slaveids[id]>0) {
1005 newid = slaveids[id];
1011 slaveids[id] = newid;
1013 swf_SetDefineID(tag, newid);
1016 num = swf_GetNumUsedIDs(tag);
1018 ptr = (int*)rfx_alloc(sizeof(int)*num);
1019 swf_GetUsedIDs(tag, ptr);
1021 for(t=0;t<num;t++) {
1022 int id = GET16(&tag->data[ptr[t]]);
1023 if(slaveids[id]<0) {
1024 if(!id && bitmap[id]) {
1025 /* id 0 is only used in SWF versions >=9. It's the ID of
1026 the main timeline. It's used in e.g. SYMBOLTAG tags, but
1027 never defined, so if we're asked to reallocate it, we have
1028 to allocate an ID for it on the fly. */
1032 slaveids[id] = newid;
1034 } else if(!bitmap[id]) {
1035 /* well- we don't know this id, but it's not reserved anyway, so just
1038 /* this actually happens with files created with Flash CS4 and never.
1039 Apparently e.g. DefineButton tags are able to use forward declarations of objects. */
1040 fprintf(stderr, "warning: Mapping id (%d) never encountered before in %s\n", id,
1041 swf_TagGetName(tag));
1044 id = slaveids[id] = newid;
1050 PUT16(&tag->data[ptr[t]], id);
1060 void swf_Relocate2(SWF*swf, int*id2id)
1063 tag = swf->firstTag;
1065 if(swf_isDefiningTag(tag)) {
1066 int id = swf_GetDefineID(tag);
1069 swf_SetDefineID(tag, id);
1072 int num = swf_GetNumUsedIDs(tag);
1076 ptr = (int*)rfx_alloc(sizeof(int)*num);
1077 swf_GetUsedIDs(tag, ptr);
1078 for(t=0;t<num;t++) {
1079 int id = GET16(&tag->data[ptr[t]]);
1082 PUT16(&tag->data[ptr[t]], id);
1090 void swf_RelocateDepth(SWF*swf, char*bitmap)
1094 tag = swf->firstTag;
1095 for(nr=65535;nr>=0;nr--) {
1099 // now nr is the highest used depth. So we start
1100 // assigning depths at nr+1
1106 /* TODO * clip depths
1109 if(tag->id == ST_PLACEOBJECT2) {
1111 swf_GetPlaceObject(tag, &obj);
1113 int newdepth = obj.clipdepth+nr;
1114 if(newdepth>65535) {
1115 fprintf(stderr, "Couldn't relocate depths: too large values\n");
1118 obj.clipdepth = newdepth;
1119 swf_ResetTag(tag, ST_PLACEOBJECT2);
1120 swf_SetPlaceObject(tag, &obj);
1122 swf_PlaceObjectFree(&obj);
1125 depth = swf_GetDepth(tag);
1127 int newdepth = depth+nr;
1128 if(newdepth>65535) {
1129 fprintf(stderr, "Couldn't relocate depths: too large values\n");
1132 swf_SetDepth(tag, newdepth);
1138 U8 swf_isShapeTag(TAG*tag)
1140 if(tag->id == ST_DEFINESHAPE ||
1141 tag->id == ST_DEFINESHAPE2 ||
1142 tag->id == ST_DEFINESHAPE3 ||
1143 tag->id == ST_DEFINESHAPE4)
1148 U8 swf_isPlaceTag(TAG*tag)
1150 if(tag->id == ST_PLACEOBJECT ||
1151 tag->id == ST_PLACEOBJECT2 ||
1152 tag->id == ST_PLACEOBJECT3)
1156 U8 swf_isTextTag(TAG*tag)
1158 if(tag->id == ST_DEFINETEXT ||
1159 tag->id == ST_DEFINETEXT2)
1164 U8 swf_isFontTag(TAG*tag)
1166 if(tag->id == ST_DEFINEFONT ||
1167 tag->id == ST_DEFINEFONT2 ||
1168 tag->id == ST_DEFINEFONT3 ||
1169 tag->id == ST_DEFINEFONTINFO)
1174 U8 swf_isImageTag(TAG*tag)
1176 if(tag->id == ST_DEFINEBITSJPEG ||
1177 tag->id == ST_DEFINEBITSJPEG2 ||
1178 tag->id == ST_DEFINEBITSJPEG3 ||
1179 tag->id == ST_DEFINEBITSLOSSLESS ||
1180 tag->id == ST_DEFINEBITSLOSSLESS2)
1185 TAG* swf_Concatenate (TAG*list1,TAG*list2)
1187 TAG*tag=0,*lasttag=0;
1189 char depthmap[65536];
1191 memset(bitmap, 0, sizeof(bitmap));
1192 memset(depthmap, 0, sizeof(depthmap));
1193 memset(&swf1, 0, sizeof(swf1));
1194 memset(&swf2, 0, sizeof(swf2));
1196 swf1.firstTag = list1;
1198 swf2.firstTag = list2;
1203 if(!swf_isDefiningTag(tag)) {
1204 int id = swf_GetDefineID(tag);
1207 if(tag->id == ST_PLACEOBJECT ||
1208 tag->id == ST_PLACEOBJECT2) {
1209 int depth = swf_GetDepth(tag);
1210 depthmap[depth] = 1;
1212 if(tag->id == ST_REMOVEOBJECT ||
1213 tag->id == ST_REMOVEOBJECT2) {
1214 int depth = swf_GetDepth(tag);
1215 depthmap[depth] = 0;
1220 swf_Relocate(&swf2, bitmap);
1221 swf_RelocateDepth(&swf2, depthmap);
1222 lasttag->next = swf2.firstTag;
1223 swf2.firstTag->prev = lasttag;
1225 return swf1.firstTag;
1228 static int tagHash(TAG*tag)
1231 unsigned int a = 0x6b973e5a;
1232 /* start at pos 2, as 0 and 1 are the id */
1233 for(t=2;t<tag->len;t++) {
1236 a += tag->data[t]*0xefbc35a5*b*(t+1);
1238 return a&0x7fffffff; //always return positive number
1241 void swf_Optimize(SWF*swf)
1243 const int hash_size = 131072;
1244 char* dontremap = (char*)rfx_calloc(sizeof(char)*65536);
1245 U16* remap = (U16*)rfx_alloc(sizeof(U16)*65536);
1246 TAG* id2tag = (TAG*)rfx_calloc(sizeof(TAG*)*65536);
1247 TAG** hashmap = (TAG**)rfx_calloc(sizeof(TAG*)*hash_size);
1250 for(t=0;t<65536;t++) {
1256 tag = swf->firstTag;
1258 /* make sure we don't remap to this tag,
1259 as it might have different "helper tags"
1260 FIXME: a better way would be to compare
1261 the helper tags, too.
1263 if(swf_isPseudoDefiningTag(tag) &&
1264 tag->id != ST_NAMECHARACTER) {
1265 dontremap[swf_GetDefineID(tag)] = 1;
1269 tag = swf->firstTag;
1271 TAG*next = tag->next;
1274 int num = swf_GetNumUsedIDs(tag);
1275 int*positions = (int*)rfx_alloc(sizeof(int)*num);
1277 swf_GetUsedIDs(tag, positions);
1278 for(t=0;t<num;t++) {
1279 int id = GET16(&tag->data[positions[t]]);
1281 PUT16(&tag->data[positions[t]], id);
1283 rfx_free(positions);
1285 /* now look for previous tags with the same
1287 if(swf_isDefiningTag(tag)) {
1289 int id = swf_GetDefineID(tag);
1290 int hash = tagHash(tag);
1293 while((tag2 = hashmap[hash%hash_size])) {
1294 if(tag2 != (TAG*)0 && tag->len == tag2->len) {
1295 if(memcmp(&tag->data[2],&tag2->data[2],tag->len-2) == 0) {
1303 while(hashmap[hash%hash_size]) hash++;
1304 hashmap[hash%hash_size] = tag;
1306 /* we found two identical tags- remap one
1308 remap[id] = swf_GetDefineID(tag2);
1309 swf_DeleteTag(swf, tag);
1311 } else if(swf_isPseudoDefiningTag(tag)) {
1312 int id = swf_GetDefineID(tag);
1314 /* if this tag was remapped, we don't
1315 need the helper tag anymore. Discard
1317 swf_DeleteTag(swf, tag);
1324 rfx_free(dontremap);
1330 void swf_SetDefineBBox(TAG * tag, SRECT newbbox)
1334 swf_SetTagPos(tag,0);
1336 switch (swf_GetTagID(tag))
1338 case ST_DEFINESHAPE:
1339 case ST_DEFINESHAPE2:
1340 case ST_DEFINESHAPE3:
1341 case ST_DEFINEEDITTEXT:
1343 case ST_DEFINETEXT2:
1344 case ST_DEFINEVIDEOSTREAM: {
1345 U32 after_bbox_offset = 0, len;
1347 id = swf_GetU16(tag);
1348 swf_GetRect(tag, &b1);
1349 swf_ResetReadBits(tag);
1350 after_bbox_offset = tag->pos;
1351 len = tag->len - after_bbox_offset;
1352 data = (U8*)malloc(len);
1353 memcpy(data, &tag->data[after_bbox_offset], len);
1356 swf_SetRect(tag, &newbbox);
1357 swf_SetBlock(tag, data, len);
1359 tag->pos = tag->readBit = 0;
1363 fprintf(stderr, "rfxswf: Tag %d (%s) has no bbox\n", tag->id, swf_TagGetName(tag));
1367 RGBA swf_GetSWFBackgroundColor(SWF*swf)
1369 TAG*t=swf->firstTag;
1371 color.r = color.b = color.g = 0;
1374 if(t->id == ST_SETBACKGROUNDCOLOR) {
1375 swf_SetTagPos(t, 0);
1376 color.r = swf_GetU8(t);
1377 color.g = swf_GetU8(t);
1378 color.b = swf_GetU8(t);