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);
587 swf_GetU16(tag); //button id
590 callback(tag, tag->pos + base, callback_data);
591 U16 sound_id = swf_GetU16(tag); //sound id
594 flags = swf_GetU8(tag);
596 swf_GetU32(tag); // in point
598 swf_GetU32(tag); // out points
600 swf_GetU16(tag); // loop count
603 int npoints = swf_GetU8(tag);
605 for(s=0;s<npoints;s++)
614 case ST_DEFINEBUTTONCXFORM:
615 callback(tag, tag->pos + base, callback_data); //button id
619 case ST_EXPORTASSETS: {
620 int num = swf_GetU16(tag);
623 callback(tag, tag->pos + base, callback_data); //button id
624 swf_GetU16(tag); //id
625 while(swf_GetU8(tag)); //name
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
637 callback(tag, tag->pos + base, callback_data); //button id
638 swf_GetU16(tag); //id
639 while(swf_GetU8(tag)); //name
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);
654 callback(tag, tag->pos + base, callback_data);
656 case ST_PLACEOBJECT2:
657 // only if placeflaghascharacter
658 if(!(tag->data[0]&2))
660 callback(tag, 3 + base, callback_data);
662 case ST_PLACEOBJECT3:
663 // only if placeflaghascharacter
664 if(!(tag->data[0]&2))
666 callback(tag, 4 + base, callback_data);
668 case ST_REMOVEOBJECT:
669 callback(tag, tag->pos + base, callback_data);
672 callback(tag, tag->pos + base, callback_data);
674 case ST_DEFINESPRITE: {
676 break; // sprite is expanded
678 swf_GetU16(tag); // id
679 swf_GetU16(tag); // framenum
682 U16 flags = swf_GetU16(tag);
685 TAG *tag2 = swf_InsertTag(NULL, id);
688 len = swf_GetU32(tag);
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);
702 case ST_DEFINEBUTTON2: // has some font ids in the button records
705 case ST_DEFINEBUTTON: {
706 swf_GetU16(tag); //button id
710 swf_GetU8(tag); //flag
711 offset = swf_GetU16(tag); //offset
715 U8 flags = swf_GetU8(tag);
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);
724 swf_ResetReadBits(tag);
725 swf_GetCXForm(tag, NULL, 1);
728 U8 num = swf_GetU8(tag);
731 swf_DeleteFilter(swf_GetFilter(tag));
735 U8 blendmode = swf_GetU8(tag);
741 case ST_DEFINEEDITTEXT: {
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);
749 callback(tag, tag->pos + base, callback_data);
754 case ST_DEFINETEXT: {
755 int glyphbits, advancebits;
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
767 swf_ResetReadBits(tag);
768 flags = swf_GetBits(tag, 8);
771 swf_ResetReadBits(tag);
772 if(flags & 8) { // hasfont
773 callback(tag, tag->pos + base, callback_data);
774 id = swf_GetU16(tag);
776 if(flags & 4) { // hascolor
777 if(num==1) swf_GetRGB(tag, NULL);
778 else swf_GetRGBA(tag, NULL);
780 if(flags & 2) { //has x offset
781 swf_ResetReadBits(tag);
784 if(flags & 1) { //has y offset
785 swf_ResetReadBits(tag);
788 if(flags & 8) { //has height
789 swf_ResetReadBits(tag);
793 flags = swf_GetBits(tag, 8);
795 swf_ResetReadBits(tag);
796 for(t=0;t<flags;t++) {
797 swf_GetBits(tag, glyphbits);
798 swf_GetBits(tag, advancebits);
803 case ST_DEFINEFONTALIGNZONES:
804 case ST_DEFINESCALINGGRID:
806 case ST_CSMTEXTSETTINGS:
807 case ST_DEFINEFONTINFO:
808 case ST_DEFINEFONTINFO2:
810 callback(tag, tag->pos + base, callback_data);
812 case ST_DEFINEVIDEOSTREAM:
815 case ST_DOINITACTION:
816 callback(tag, tag->pos + base, callback_data);
819 case ST_DEFINEMORPHSHAPE2:
820 case ST_DEFINESHAPE4:
822 case ST_DEFINEMORPHSHAPE:
823 case ST_DEFINESHAPE3:
825 case ST_DEFINESHAPE2:
827 case ST_DEFINESHAPE: {
833 if(tag->id == ST_DEFINEMORPHSHAPE || tag->id==ST_DEFINEMORPHSHAPE2) {
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
842 swf_ResetReadBits(tag);
843 swf_GetRect(tag, NULL); // shape bounds2
845 swf_ResetReadBits(tag);
846 swf_GetRect(tag, NULL); // edge bounds1
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);
856 swf_GetU32(tag); //offset to endedges
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);
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 */
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);
877 flags = swf_GetBits(tag, 1);
878 if(!flags) { //style change
879 flags = swf_GetBits(tag, 5);
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);
888 if(flags&2) { //fill0
890 fill0 = swf_GetBits(tag, fillbits);
891 DEBUG_ENUMERATE printf("fill0 %d\n", fill0);
893 if(flags&4) { //fill1
895 fill1 = swf_GetBits(tag, fillbits);
896 DEBUG_ENUMERATE printf("fill1 %d\n", fill1);
898 if(flags&8) { //linestyle
900 line = swf_GetBits(tag, linebits);
901 DEBUG_ENUMERATE printf("linestyle %d\n",line);
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);
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);
918 int v=swf_GetBits(tag, 1);
920 d = swf_GetSBits(tag, n); //vert/horz
925 DEBUG_ENUMERATE printf("lineTo %.2f %.2f (%s)\n",x/20.0,y/20.0, v?"vertical":"horizontal");
927 } else { //curved edge
928 int n = swf_GetBits(tag, 4) + 2;
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);
946 void callbackCount(TAG * t,int pos, void*ptr)
949 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
952 void callbackFillin(TAG * t,int pos, void*ptr)
956 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
959 int swf_GetNumUsedIDs(TAG * t)
962 enumerateUsedIDs(t, 0, callbackCount, &num);
966 void swf_GetUsedIDs(TAG * t, int * positions)
968 int * ptr = positions;
969 enumerateUsedIDs(t, 0, callbackFillin, &ptr);
972 char swf_Relocate (SWF*swf, char*bitmap)
976 memset(slaveids, -1, sizeof(slaveids));
982 for(current_id++;current_id<65536;current_id++) { \
983 if(!bitmap[current_id]) { \
988 if(current_id==65536) { \
989 fprintf(stderr, "swf_Relocate: Couldn't relocate: Out of IDs\n"); \
998 if(swf_isDefiningTag(tag))
1003 id = swf_GetDefineID(tag); //own id
1005 if(!bitmap[id]) { //free
1007 } else if(slaveids[id]>0) {
1008 newid = slaveids[id];
1014 slaveids[id] = newid;
1016 swf_SetDefineID(tag, newid);
1019 num = swf_GetNumUsedIDs(tag);
1021 ptr = (int*)rfx_alloc(sizeof(int)*num);
1022 swf_GetUsedIDs(tag, ptr);
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. */
1035 slaveids[id] = newid;
1037 } else if(!bitmap[id]) {
1038 /* well- we don't know this id, but it's not reserved anyway, so just
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));
1047 id = slaveids[id] = newid;
1053 PUT16(&tag->data[ptr[t]], id);
1063 void swf_Relocate2(SWF*swf, int*id2id)
1066 tag = swf->firstTag;
1068 if(swf_isDefiningTag(tag)) {
1069 int id = swf_GetDefineID(tag);
1072 swf_SetDefineID(tag, id);
1075 int num = swf_GetNumUsedIDs(tag);
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]]);
1085 PUT16(&tag->data[ptr[t]], id);
1093 void swf_RelocateDepth(SWF*swf, char*bitmap)
1097 tag = swf->firstTag;
1098 for(nr=65535;nr>=0;nr--) {
1102 // now nr is the highest used depth. So we start
1103 // assigning depths at nr+1
1109 /* TODO * clip depths
1112 if(tag->id == ST_PLACEOBJECT2) {
1114 swf_GetPlaceObject(tag, &obj);
1116 int newdepth = obj.clipdepth+nr;
1117 if(newdepth>65535) {
1118 fprintf(stderr, "Couldn't relocate depths: too large values\n");
1121 obj.clipdepth = newdepth;
1122 swf_ResetTag(tag, ST_PLACEOBJECT2);
1123 swf_SetPlaceObject(tag, &obj);
1125 swf_PlaceObjectFree(&obj);
1128 depth = swf_GetDepth(tag);
1130 int newdepth = depth+nr;
1131 if(newdepth>65535) {
1132 fprintf(stderr, "Couldn't relocate depths: too large values\n");
1135 swf_SetDepth(tag, newdepth);
1141 U8 swf_isShapeTag(TAG*tag)
1143 if(tag->id == ST_DEFINESHAPE ||
1144 tag->id == ST_DEFINESHAPE2 ||
1145 tag->id == ST_DEFINESHAPE3 ||
1146 tag->id == ST_DEFINESHAPE4)
1151 U8 swf_isPlaceTag(TAG*tag)
1153 if(tag->id == ST_PLACEOBJECT ||
1154 tag->id == ST_PLACEOBJECT2 ||
1155 tag->id == ST_PLACEOBJECT3)
1159 U8 swf_isTextTag(TAG*tag)
1161 if(tag->id == ST_DEFINETEXT ||
1162 tag->id == ST_DEFINETEXT2)
1167 U8 swf_isFontTag(TAG*tag)
1169 if(tag->id == ST_DEFINEFONT ||
1170 tag->id == ST_DEFINEFONT2 ||
1171 tag->id == ST_DEFINEFONT3 ||
1172 tag->id == ST_DEFINEFONTINFO)
1177 U8 swf_isImageTag(TAG*tag)
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)
1188 TAG* swf_Concatenate (TAG*list1,TAG*list2)
1190 TAG*tag=0,*lasttag=0;
1192 char depthmap[65536];
1194 memset(bitmap, 0, sizeof(bitmap));
1195 memset(depthmap, 0, sizeof(depthmap));
1196 memset(&swf1, 0, sizeof(swf1));
1197 memset(&swf2, 0, sizeof(swf2));
1199 swf1.firstTag = list1;
1201 swf2.firstTag = list2;
1206 if(!swf_isDefiningTag(tag)) {
1207 int id = swf_GetDefineID(tag);
1210 if(tag->id == ST_PLACEOBJECT ||
1211 tag->id == ST_PLACEOBJECT2) {
1212 int depth = swf_GetDepth(tag);
1213 depthmap[depth] = 1;
1215 if(tag->id == ST_REMOVEOBJECT ||
1216 tag->id == ST_REMOVEOBJECT2) {
1217 int depth = swf_GetDepth(tag);
1218 depthmap[depth] = 0;
1223 swf_Relocate(&swf2, bitmap);
1224 swf_RelocateDepth(&swf2, depthmap);
1225 lasttag->next = swf2.firstTag;
1226 swf2.firstTag->prev = lasttag;
1228 return swf1.firstTag;
1231 static int tagHash(TAG*tag)
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++) {
1239 a += tag->data[t]*0xefbc35a5*b*(t+1);
1241 return a&0x7fffffff; //always return positive number
1244 void swf_Optimize(SWF*swf)
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);
1253 for(t=0;t<65536;t++) {
1259 tag = swf->firstTag;
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.
1266 if(swf_isPseudoDefiningTag(tag) &&
1267 tag->id != ST_NAMECHARACTER) {
1268 dontremap[swf_GetDefineID(tag)] = 1;
1272 tag = swf->firstTag;
1274 TAG*next = tag->next;
1277 int num = swf_GetNumUsedIDs(tag);
1278 int*positions = (int*)rfx_alloc(sizeof(int)*num);
1280 swf_GetUsedIDs(tag, positions);
1281 for(t=0;t<num;t++) {
1282 int id = GET16(&tag->data[positions[t]]);
1284 PUT16(&tag->data[positions[t]], id);
1286 rfx_free(positions);
1288 /* now look for previous tags with the same
1290 if(swf_isDefiningTag(tag)) {
1292 int id = swf_GetDefineID(tag);
1293 int hash = tagHash(tag);
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) {
1306 while(hashmap[hash%hash_size]) hash++;
1307 hashmap[hash%hash_size] = tag;
1309 /* we found two identical tags- remap one
1311 remap[id] = swf_GetDefineID(tag2);
1312 swf_DeleteTag(swf, tag);
1314 } else if(swf_isPseudoDefiningTag(tag)) {
1315 int id = swf_GetDefineID(tag);
1317 /* if this tag was remapped, we don't
1318 need the helper tag anymore. Discard
1320 swf_DeleteTag(swf, tag);
1327 rfx_free(dontremap);
1333 void swf_SetDefineBBox(TAG * tag, SRECT newbbox)
1337 swf_SetTagPos(tag,0);
1339 switch (swf_GetTagID(tag))
1341 case ST_DEFINESHAPE:
1342 case ST_DEFINESHAPE2:
1343 case ST_DEFINESHAPE3:
1344 case ST_DEFINEEDITTEXT:
1346 case ST_DEFINETEXT2:
1347 case ST_DEFINEVIDEOSTREAM: {
1348 U32 after_bbox_offset = 0, len;
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);
1359 swf_SetRect(tag, &newbbox);
1360 swf_SetBlock(tag, data, len);
1362 tag->pos = tag->readBit = 0;
1366 fprintf(stderr, "rfxswf: Tag %d (%s) has no bbox\n", tag->id, swf_TagGetName(tag));
1370 RGBA swf_GetSWFBackgroundColor(SWF*swf)
1372 TAG*t=swf->firstTag;
1374 color.r = color.b = color.g = 0;
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);