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_DEFINEBINARY:
647 case ST_DEFINEFONTNAME:
648 case ST_GENERATORTEXT:
649 callback(tag, tag->pos + base, callback_data);
652 callback(tag, tag->pos + base, callback_data);
654 case ST_PLACEOBJECT2:
655 // only if placeflaghascharacter
656 if(!(tag->data[0]&2))
658 callback(tag, 3 + base, callback_data);
660 case ST_PLACEOBJECT3:
661 // only if placeflaghascharacter
662 if(!(tag->data[0]&2))
664 callback(tag, 4 + base, callback_data);
666 case ST_REMOVEOBJECT:
667 callback(tag, tag->pos + base, callback_data);
670 callback(tag, tag->pos + base, callback_data);
672 case ST_DEFINESPRITE: {
674 break; // sprite is expanded
676 swf_GetU16(tag); // id
677 swf_GetU16(tag); // framenum
680 U16 flags = swf_GetU16(tag);
683 TAG *tag2 = swf_InsertTag(NULL, id);
686 len = swf_GetU32(tag);
689 tag2->len = tag2->memsize = len;
690 tag2->data = (U8*)rfx_alloc(len);
691 memcpy(tag2->data, &tag->data[tag->pos], len);
692 /* I never saw recursive sprites, but they are (theoretically)
693 possible, so better add base here again */
694 enumerateUsedIDs(tag2, tag->pos + base, callback, callback_data);
695 swf_DeleteTag(0, tag2);
696 swf_GetBlock(tag, NULL, len);
700 case ST_DEFINEBUTTON2: // has some font ids in the button records
703 case ST_DEFINEBUTTON: {
704 swf_GetU16(tag); //button id
708 swf_GetU8(tag); //flag
709 offset = swf_GetU16(tag); //offset
713 U8 flags = swf_GetU8(tag);
716 callback(tag, tag->pos + base, callback_data);
717 swf_GetU16(tag); //char
718 swf_GetU16(tag); //layer
719 swf_ResetReadBits(tag);
720 swf_GetMatrix(tag, NULL);
722 swf_ResetReadBits(tag);
723 swf_GetCXForm(tag, NULL, 1);
726 U8 num = swf_GetU8(tag);
729 swf_DeleteFilter(swf_GetFilter(tag));
733 U8 blendmode = swf_GetU8(tag);
739 case ST_DEFINEEDITTEXT: {
741 swf_GetU16(tag); //id
742 swf_GetRect(tag, NULL); //bounding box
743 swf_ResetReadBits(tag);
744 flags1 = swf_GetU8(tag);
745 flags2 = swf_GetU8(tag);
747 callback(tag, tag->pos + base, callback_data);
752 case ST_DEFINETEXT: {
753 int glyphbits, advancebits;
755 id = swf_GetU16(tag); //id
756 swf_GetRect(tag, NULL); //bounding box
757 swf_ResetReadBits(tag);
758 swf_GetMatrix(tag, NULL); //matrix
759 swf_ResetReadBits(tag);
760 glyphbits = swf_GetU8(tag); //glyphbits
761 advancebits = swf_GetU8(tag); //advancebits
765 swf_ResetReadBits(tag);
766 flags = swf_GetBits(tag, 8);
769 swf_ResetReadBits(tag);
770 if(flags & 8) { // hasfont
771 callback(tag, tag->pos + base, callback_data);
772 id = swf_GetU16(tag);
774 if(flags & 4) { // hascolor
775 if(num==1) swf_GetRGB(tag, NULL);
776 else swf_GetRGBA(tag, NULL);
778 if(flags & 2) { //has x offset
779 swf_ResetReadBits(tag);
782 if(flags & 1) { //has y offset
783 swf_ResetReadBits(tag);
786 if(flags & 8) { //has height
787 swf_ResetReadBits(tag);
791 flags = swf_GetBits(tag, 8);
793 swf_ResetReadBits(tag);
794 for(t=0;t<flags;t++) {
795 swf_GetBits(tag, glyphbits);
796 swf_GetBits(tag, advancebits);
801 case ST_DEFINEFONTALIGNZONES:
802 case ST_DEFINESCALINGGRID:
804 case ST_CSMTEXTSETTINGS:
805 case ST_DEFINEFONTINFO:
806 case ST_DEFINEFONTINFO2:
808 callback(tag, tag->pos + base, callback_data);
810 case ST_DEFINEVIDEOSTREAM:
813 case ST_DOINITACTION:
814 callback(tag, tag->pos + base, callback_data);
817 case ST_DEFINEMORPHSHAPE2:
818 case ST_DEFINESHAPE4:
820 case ST_DEFINEMORPHSHAPE:
821 case ST_DEFINESHAPE3:
823 case ST_DEFINESHAPE2:
825 case ST_DEFINESHAPE: {
831 if(tag->id == ST_DEFINEMORPHSHAPE || tag->id==ST_DEFINEMORPHSHAPE2) {
836 id = swf_GetU16(tag); // id;
837 SRECT r={0,0,0,0},r2={0,0,0,0};
838 swf_GetRect(tag, &r); // shape bounds
840 swf_ResetReadBits(tag);
841 swf_GetRect(tag, NULL); // shape bounds2
843 swf_ResetReadBits(tag);
844 swf_GetRect(tag, NULL); // edge bounds1
848 swf_ResetReadBits(tag);
849 swf_GetRect(tag, &r2); // edge bounds
850 U8 flags = swf_GetU8(tag); // flags, &1: contains scaling stroke, &2: contains non-scaling stroke
851 DEBUG_ENUMERATE printf("flags: %02x (1=scaling strokes, 2=non-scaling strokes)\n", flags);
854 swf_GetU32(tag); //offset to endedges
857 DEBUG_ENUMERATE printf("Tag:%d Name:%s ID:%d\n", tag->id, swf_TagGetName(tag), id);
858 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);
859 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);
861 DEBUG_ENUMERATE printf("style tag pos: %d\n", tag->pos);
862 enumerateUsedIDs_styles(tag, callback, callback_data, num, morph);
863 DEBUG_ENUMERATE printf("-------\n");
864 swf_ResetReadBits(tag);
865 while(--numshapes>=0) /* morph shapes define two shapes */
867 DEBUG_ENUMERATE printf("shape:%d\n", numshapes);
868 fillbits = swf_GetBits(tag, 4);
869 linebits = swf_GetBits(tag, 4);
870 DEBUG_ENUMERATE printf("fillbits=%d linebits=%d\n", fillbits, linebits);
871 swf_ResetReadBits(tag);
875 flags = swf_GetBits(tag, 1);
876 if(!flags) { //style change
877 flags = swf_GetBits(tag, 5);
881 int n = swf_GetBits(tag, 5);
882 x = swf_GetBits(tag, n); //x
883 y = swf_GetBits(tag, n); //y
884 DEBUG_ENUMERATE printf("moveTo %.2f %.2f\n",x/20.0,y/20.0);
886 if(flags&2) { //fill0
888 fill0 = swf_GetBits(tag, fillbits);
889 DEBUG_ENUMERATE printf("fill0 %d\n", fill0);
891 if(flags&4) { //fill1
893 fill1 = swf_GetBits(tag, fillbits);
894 DEBUG_ENUMERATE printf("fill1 %d\n", fill1);
896 if(flags&8) { //linestyle
898 line = swf_GetBits(tag, linebits);
899 DEBUG_ENUMERATE printf("linestyle %d\n",line);
902 DEBUG_ENUMERATE printf("more fillstyles\n");
903 enumerateUsedIDs_styles(tag, callback, callback_data, num, 0);
904 fillbits = swf_GetBits(tag, 4);
905 linebits = swf_GetBits(tag, 4);
908 flags = swf_GetBits(tag, 1);
909 if(flags) { //straight edge
910 int n = swf_GetBits(tag, 4) + 2;
911 if(swf_GetBits(tag, 1)) { //line flag
912 x += swf_GetSBits(tag, n); //delta x
913 y += swf_GetSBits(tag, n); //delta y
914 DEBUG_ENUMERATE printf("lineTo %.2f %.2f\n",x/20.0,y/20.0);
916 int v=swf_GetBits(tag, 1);
918 d = swf_GetSBits(tag, n); //vert/horz
923 DEBUG_ENUMERATE printf("lineTo %.2f %.2f (%s)\n",x/20.0,y/20.0, v?"vertical":"horizontal");
925 } else { //curved edge
926 int n = swf_GetBits(tag, 4) + 2;
928 x1 = swf_GetSBits(tag, n);
929 y1 = swf_GetSBits(tag, n);
930 x2 = swf_GetSBits(tag, n);
931 y2 = swf_GetSBits(tag, n);
932 DEBUG_ENUMERATE printf("splineTo %.2f %.2f %.2f %.2f\n", x1/20.0, y1/20.0, x2/20.0, y2/20.0);
944 void callbackCount(TAG * t,int pos, void*ptr)
947 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
950 void callbackFillin(TAG * t,int pos, void*ptr)
954 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
957 int swf_GetNumUsedIDs(TAG * t)
960 enumerateUsedIDs(t, 0, callbackCount, &num);
964 void swf_GetUsedIDs(TAG * t, int * positions)
966 int * ptr = positions;
967 enumerateUsedIDs(t, 0, callbackFillin, &ptr);
970 char swf_Relocate (SWF*swf, char*bitmap)
974 memset(slaveids, -1, sizeof(slaveids));
980 for(current_id++;current_id<65536;current_id++) { \
981 if(!bitmap[current_id]) { \
986 if(current_id==65536) { \
987 fprintf(stderr, "swf_Relocate: Couldn't relocate: Out of IDs\n"); \
996 if(swf_isDefiningTag(tag))
1001 id = swf_GetDefineID(tag); //own id
1003 if(!bitmap[id]) { //free
1005 } else if(slaveids[id]>0) {
1006 newid = slaveids[id];
1012 slaveids[id] = newid;
1014 swf_SetDefineID(tag, newid);
1017 num = swf_GetNumUsedIDs(tag);
1019 ptr = (int*)rfx_alloc(sizeof(int)*num);
1020 swf_GetUsedIDs(tag, ptr);
1022 for(t=0;t<num;t++) {
1023 int id = GET16(&tag->data[ptr[t]]);
1024 if(slaveids[id]<0) {
1025 if(!id && bitmap[id]) {
1026 /* id 0 is only used in SWF versions >=9. It's the ID of
1027 the main timeline. It's used in e.g. SYMBOLTAG tags, but
1028 never defined, so if we're asked to reallocate it, we have
1029 to allocate an ID for it on the fly. */
1033 slaveids[id] = newid;
1035 } else if(!bitmap[id]) {
1036 /* well- we don't know this id, but it's not reserved anyway, so just
1039 /* this actually happens with files created with Flash CS4 and never.
1040 Apparently e.g. DefineButton tags are able to use forward declarations of objects. */
1041 fprintf(stderr, "warning: Mapping id (%d) never encountered before in %s\n", id,
1042 swf_TagGetName(tag));
1045 id = slaveids[id] = newid;
1051 PUT16(&tag->data[ptr[t]], id);
1061 void swf_Relocate2(SWF*swf, int*id2id)
1064 tag = swf->firstTag;
1066 if(swf_isDefiningTag(tag)) {
1067 int id = swf_GetDefineID(tag);
1070 swf_SetDefineID(tag, id);
1073 int num = swf_GetNumUsedIDs(tag);
1077 ptr = (int*)rfx_alloc(sizeof(int)*num);
1078 swf_GetUsedIDs(tag, ptr);
1079 for(t=0;t<num;t++) {
1080 int id = GET16(&tag->data[ptr[t]]);
1083 PUT16(&tag->data[ptr[t]], id);
1091 void swf_RelocateDepth(SWF*swf, char*bitmap)
1095 tag = swf->firstTag;
1096 for(nr=65535;nr>=0;nr--) {
1100 // now nr is the highest used depth. So we start
1101 // assigning depths at nr+1
1107 /* TODO * clip depths
1110 if(tag->id == ST_PLACEOBJECT2) {
1112 swf_GetPlaceObject(tag, &obj);
1114 int newdepth = obj.clipdepth+nr;
1115 if(newdepth>65535) {
1116 fprintf(stderr, "Couldn't relocate depths: too large values\n");
1119 obj.clipdepth = newdepth;
1120 swf_ResetTag(tag, ST_PLACEOBJECT2);
1121 swf_SetPlaceObject(tag, &obj);
1123 swf_PlaceObjectFree(&obj);
1126 depth = swf_GetDepth(tag);
1128 int newdepth = depth+nr;
1129 if(newdepth>65535) {
1130 fprintf(stderr, "Couldn't relocate depths: too large values\n");
1133 swf_SetDepth(tag, newdepth);
1139 U8 swf_isShapeTag(TAG*tag)
1141 if(tag->id == ST_DEFINESHAPE ||
1142 tag->id == ST_DEFINESHAPE2 ||
1143 tag->id == ST_DEFINESHAPE3 ||
1144 tag->id == ST_DEFINESHAPE4)
1149 U8 swf_isPlaceTag(TAG*tag)
1151 if(tag->id == ST_PLACEOBJECT ||
1152 tag->id == ST_PLACEOBJECT2 ||
1153 tag->id == ST_PLACEOBJECT3)
1157 U8 swf_isTextTag(TAG*tag)
1159 if(tag->id == ST_DEFINETEXT ||
1160 tag->id == ST_DEFINETEXT2)
1165 U8 swf_isFontTag(TAG*tag)
1167 if(tag->id == ST_DEFINEFONT ||
1168 tag->id == ST_DEFINEFONT2 ||
1169 tag->id == ST_DEFINEFONT3 ||
1170 tag->id == ST_DEFINEFONTINFO)
1175 U8 swf_isImageTag(TAG*tag)
1177 if(tag->id == ST_DEFINEBITSJPEG ||
1178 tag->id == ST_DEFINEBITSJPEG2 ||
1179 tag->id == ST_DEFINEBITSJPEG3 ||
1180 tag->id == ST_DEFINEBITSLOSSLESS ||
1181 tag->id == ST_DEFINEBITSLOSSLESS2)
1186 TAG* swf_Concatenate (TAG*list1,TAG*list2)
1188 TAG*tag=0,*lasttag=0;
1190 char depthmap[65536];
1192 memset(bitmap, 0, sizeof(bitmap));
1193 memset(depthmap, 0, sizeof(depthmap));
1194 memset(&swf1, 0, sizeof(swf1));
1195 memset(&swf2, 0, sizeof(swf2));
1197 swf1.firstTag = list1;
1199 swf2.firstTag = list2;
1204 if(!swf_isDefiningTag(tag)) {
1205 int id = swf_GetDefineID(tag);
1208 if(tag->id == ST_PLACEOBJECT ||
1209 tag->id == ST_PLACEOBJECT2) {
1210 int depth = swf_GetDepth(tag);
1211 depthmap[depth] = 1;
1213 if(tag->id == ST_REMOVEOBJECT ||
1214 tag->id == ST_REMOVEOBJECT2) {
1215 int depth = swf_GetDepth(tag);
1216 depthmap[depth] = 0;
1221 swf_Relocate(&swf2, bitmap);
1222 swf_RelocateDepth(&swf2, depthmap);
1223 lasttag->next = swf2.firstTag;
1224 swf2.firstTag->prev = lasttag;
1226 return swf1.firstTag;
1229 static int tagHash(TAG*tag)
1232 unsigned int a = 0x6b973e5a;
1233 /* start at pos 2, as 0 and 1 are the id */
1234 for(t=2;t<tag->len;t++) {
1237 a += tag->data[t]*0xefbc35a5*b*(t+1);
1239 return a&0x7fffffff; //always return positive number
1242 void swf_Optimize(SWF*swf)
1244 const int hash_size = 131072;
1245 char* dontremap = (char*)rfx_calloc(sizeof(char)*65536);
1246 U16* remap = (U16*)rfx_alloc(sizeof(U16)*65536);
1247 TAG* id2tag = (TAG*)rfx_calloc(sizeof(TAG*)*65536);
1248 TAG** hashmap = (TAG**)rfx_calloc(sizeof(TAG*)*hash_size);
1251 for(t=0;t<65536;t++) {
1257 tag = swf->firstTag;
1259 /* make sure we don't remap to this tag,
1260 as it might have different "helper tags"
1261 FIXME: a better way would be to compare
1262 the helper tags, too.
1264 if(swf_isPseudoDefiningTag(tag) &&
1265 tag->id != ST_NAMECHARACTER) {
1266 dontremap[swf_GetDefineID(tag)] = 1;
1270 tag = swf->firstTag;
1272 TAG*next = tag->next;
1275 int num = swf_GetNumUsedIDs(tag);
1276 int*positions = (int*)rfx_alloc(sizeof(int)*num);
1278 swf_GetUsedIDs(tag, positions);
1279 for(t=0;t<num;t++) {
1280 int id = GET16(&tag->data[positions[t]]);
1282 PUT16(&tag->data[positions[t]], id);
1284 rfx_free(positions);
1286 /* now look for previous tags with the same
1288 if(swf_isDefiningTag(tag)) {
1290 int id = swf_GetDefineID(tag);
1291 int hash = tagHash(tag);
1294 while((tag2 = hashmap[hash%hash_size])) {
1295 if(tag2 != (TAG*)0 && tag->len == tag2->len) {
1296 if(memcmp(&tag->data[2],&tag2->data[2],tag->len-2) == 0) {
1304 while(hashmap[hash%hash_size]) hash++;
1305 hashmap[hash%hash_size] = tag;
1307 /* we found two identical tags- remap one
1309 remap[id] = swf_GetDefineID(tag2);
1310 swf_DeleteTag(swf, tag);
1312 } else if(swf_isPseudoDefiningTag(tag)) {
1313 int id = swf_GetDefineID(tag);
1315 /* if this tag was remapped, we don't
1316 need the helper tag anymore. Discard
1318 swf_DeleteTag(swf, tag);
1325 rfx_free(dontremap);
1331 void swf_SetDefineBBox(TAG * tag, SRECT newbbox)
1335 swf_SetTagPos(tag,0);
1337 switch (swf_GetTagID(tag))
1339 case ST_DEFINESHAPE:
1340 case ST_DEFINESHAPE2:
1341 case ST_DEFINESHAPE3:
1342 case ST_DEFINEEDITTEXT:
1344 case ST_DEFINETEXT2:
1345 case ST_DEFINEVIDEOSTREAM: {
1346 U32 after_bbox_offset = 0, len;
1348 id = swf_GetU16(tag);
1349 swf_GetRect(tag, &b1);
1350 swf_ResetReadBits(tag);
1351 after_bbox_offset = tag->pos;
1352 len = tag->len - after_bbox_offset;
1353 data = (U8*)malloc(len);
1354 memcpy(data, &tag->data[after_bbox_offset], len);
1357 swf_SetRect(tag, &newbbox);
1358 swf_SetBlock(tag, data, len);
1360 tag->pos = tag->readBit = 0;
1364 fprintf(stderr, "rfxswf: Tag %d (%s) has no bbox\n", tag->id, swf_TagGetName(tag));
1368 RGBA swf_GetSWFBackgroundColor(SWF*swf)
1370 TAG*t=swf->firstTag;
1372 color.r = color.b = color.g = 0;
1375 if(t->id == ST_SETBACKGROUNDCOLOR) {
1376 swf_SetTagPos(t, 0);
1377 color.r = swf_GetU8(t);
1378 color.g = swf_GetU8(t);
1379 color.b = swf_GetU8(t);