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
27 SFIXED RFXSWF_SP(SFIXED a1,SFIXED a2,SFIXED b1,SFIXED b2)
28 { S64 a = ((S64)a1*(S64)b1+(S64)a2*(S64)b2)>>16;
29 SFIXED result = (SFIXED)(a);
31 fprintf(stderr, "Warning: overflow in matrix multiplication");
34 SFIXED RFXSWF_QFIX(int zaehler,int nenner) // bildet Quotient von zwei INTs in SFIXED
35 { S64 z = zaehler<<16;
36 S64 a = z/(S64)nenner;
41 MATRIX * swf_MatrixJoin(MATRIX * d,MATRIX * s1,MATRIX * s2)
44 if (!s1) return (s2)?(MATRIX *)memcpy(d,s2,sizeof(MATRIX)):NULL;
45 if (!s2) return (MATRIX *)memcpy(d,s1,sizeof(MATRIX));
47 d->tx = s1->tx + RFXSWF_SP(s1->sx,s1->r1,s2->tx,s2->ty);
48 d->ty = s1->ty + RFXSWF_SP(s1->r0,s1->sy,s2->tx,s2->ty);
50 d->sx = RFXSWF_SP(s1->sx,s1->r1,s2->sx,s2->r0);
51 d->r0 = RFXSWF_SP(s1->r0,s1->sy,s2->sx,s2->r0);
53 d->r1 = RFXSWF_SP(s1->sx,s1->r1,s2->r1,s2->sy);
54 d->sy = RFXSWF_SP(s1->r0,s1->sy,s2->r1,s2->sy);
61 MATRIX * swf_MatrixMapTriangle(MATRIX * m,int dx,int dy,int x0,int y0,
62 int x1,int y1,int x2,int y2)
69 if ((!dx)||(!dy)) return NULL; // check DIV by zero
73 m->sx = RFXSWF_QFIX(dx1,dx);
74 m->sy = RFXSWF_QFIX(dy2,dy);
75 m->r0 = RFXSWF_QFIX(dy1,dx);
76 m->r1 = RFXSWF_QFIX(dx2,dy);
81 void swf_SetDefineID(TAG * tag, U16 newid)
83 int oldlen = tag->len;
85 swf_SetU16(tag, newid); /* set defining ID */
89 U16 swf_GetDefineID(TAG * t)
94 oldTagPos = swf_GetTagPos(t);
97 switch (swf_GetTagID(t))
98 { case ST_DEFINESHAPE:
100 case ST_DEFINESHAPE3:
101 case ST_DEFINESHAPE4:
102 case ST_DEFINEMORPHSHAPE:
103 case ST_DEFINEEDITTEXT:
105 case ST_DEFINEBITSJPEG2:
106 case ST_DEFINEBITSJPEG3:
107 case ST_DEFINEBITSLOSSLESS:
108 case ST_DEFINEBITSLOSSLESS2:
109 case ST_DEFINESCALINGGRID: //pseudodefine
110 case ST_DEFINEBUTTON:
111 case ST_DEFINEBUTTON2:
112 case ST_DEFINEBUTTONCXFORM: //pseudodefine
113 case ST_DEFINEBUTTONSOUND: //pseudodefine
114 case ST_CSMTEXTSETTINGS: //pseudodefine
118 case ST_DEFINEFONTINFO: //pseudodefine
119 case ST_DEFINEFONTINFO2: //pseudodefine
120 case ST_DEFINEFONTALIGNZONES: //pseudodefine
124 case ST_DEFINESPRITE:
126 case ST_DEFINEVIDEOSTREAM:
127 case ST_GLYPHNAMES: //pseudodefine
128 case ST_VIDEOFRAME: //pseudodefine
129 case ST_NAMECHARACTER: //pseudodefine
130 case ST_DOINITACTION: //pseudodefine
134 fprintf(stderr, "rfxswf: Error: tag %d (%s) has no id\n", t->id, swf_TagGetName(t));
137 swf_SetTagPos(t,oldTagPos);
142 SRECT swf_GetDefineBBox(TAG * t)
147 memset(&b1, 0, sizeof(b1));
149 oldTagPos = swf_GetTagPos(t);
154 switch (swf_GetTagID(t))
155 { case ST_DEFINESHAPE:
156 case ST_DEFINESHAPE2:
157 case ST_DEFINESHAPE3:
158 case ST_DEFINEEDITTEXT:
161 case ST_DEFINEVIDEOSTREAM:
165 case ST_DEFINEMORPHSHAPE:
169 swf_ExpandRect2(&b1, &b2);
171 case ST_DEFINEBITSLOSSLESS:
172 case ST_DEFINEBITSLOSSLESS2:
174 case ST_DEFINEBITSJPEG2:
175 case ST_DEFINEBITSJPEG3:
180 swf_SetTagPos(t,oldTagPos);
185 U16 swf_GetPlaceID(TAG * t)
190 oldTagPos = swf_GetTagPos(t);
193 switch (swf_GetTagID(t))
194 { case ST_PLACEOBJECT:
195 case ST_REMOVEOBJECT:
196 case ST_FREECHARACTER:
201 case ST_PLACEOBJECT2:
202 { U8 flags = swf_GetU8(t);
203 U16 d = swf_GetU16(t);
204 id = (flags&PF_CHAR)?swf_GetU16(t):id;
206 case ST_PLACEOBJECT3:
207 { U8 flags = swf_GetU8(t);
208 U8 flags2 = swf_GetU8(t);
209 U16 d = swf_GetU16(t);
210 id = (flags&PF_CHAR)?swf_GetU16(t):id;
215 swf_SetTagPos(t,oldTagPos);
220 static int swf_definingtagids[] =
235 ST_DEFINEBITSLOSSLESS,
236 ST_DEFINEBITSLOSSLESS2,
242 ST_DEFINEVIDEOSTREAM,
246 // tags which may be used inside a sprite definition
247 static int swf_spritetagids[] =
252 ST_REMOVEOBJECT2, //?
263 /* tags which add content or information to a character with a given ID */
264 static int swf_pseudodefiningtagids[] =
268 ST_DEFINEFONTALIGNZONES,
269 ST_DEFINEBUTTONCXFORM,
270 ST_DEFINEBUTTONSOUND,
271 ST_DEFINESCALINGGRID,
280 U8 swf_isAllowedSpriteTag(TAG * tag)
284 while(swf_spritetagids[t]>=0)
286 if(swf_spritetagids[t] == id)
293 U8 swf_isDefiningTag(TAG * tag)
297 while(swf_definingtagids[t]>=0)
299 if(swf_definingtagids[t] == id)
306 U8 swf_isPseudoDefiningTag(TAG * tag)
310 while(swf_pseudodefiningtagids[t]>=0)
312 if(swf_pseudodefiningtagids[t] == id)
319 int swf_GetDepth(TAG * t)
323 oldTagPos = swf_GetTagPos(t);
326 switch (swf_GetTagID(t))
327 { case ST_PLACEOBJECT:
328 case ST_REMOVEOBJECT:
330 depth = swf_GetU16(t);
332 case ST_REMOVEOBJECT2:
333 depth = swf_GetU16(t);
335 case ST_PLACEOBJECT2:
336 { U8 flags = swf_GetU8(t);
337 depth = swf_GetU16(t);
339 case ST_PLACEOBJECT3:
340 { U8 flags = swf_GetU8(t);
341 U8 flags2 = swf_GetU8(t);
342 depth = swf_GetU16(t);
346 depth = swf_GetU16(t);
349 swf_SetTagPos(t,oldTagPos);
353 void swf_SetDepth(TAG * t, U16 depth)
355 switch (swf_GetTagID(t))
356 { case ST_PLACEOBJECT:
357 case ST_REMOVEOBJECT:
358 PUT16(t->data, depth);
360 case ST_REMOVEOBJECT2:
361 PUT16(t->data, depth);
363 case ST_PLACEOBJECT2:
364 PUT16(&t->data[1], depth);
367 PUT16(t->data, depth);
370 fprintf(stderr, "rfxswf: Error: tag %d has no depth\n", t->id);
374 char* swf_GetName(TAG * t)
380 oldTagPos = swf_GetTagPos(t);
382 switch(swf_GetTagID(t))
385 name = &t->data[swf_GetTagPos(t)];
387 case ST_PLACEOBJECT3:
388 case ST_PLACEOBJECT2: {
389 U8 flags = swf_GetU8(t);
390 if(t->id == ST_PLACEOBJECT3)
392 swf_GetU16(t); //depth;
396 swf_GetMatrix(t, &m);
398 swf_GetCXForm(t, &c, 1);
401 if(flags&PF_CLIPDEPTH)
404 swf_ResetReadBits(t);
405 name = &t->data[swf_GetTagPos(t)];
410 swf_SetTagPos(t,oldTagPos);
414 /* used in enumerateUsedIDs */
415 void swf_GetMorphGradient(TAG * tag, GRADIENT * gradient1, GRADIENT * gradient2)
425 gradient2->num = swf_GetU8(tag);
426 for(t=0;t<gradient1->num;t++)
431 gradient1->ratios[t] = swf_GetU8(tag);
432 swf_GetRGBA(tag, &gradient1->rgba[t]);
433 gradient2->ratios[t] = swf_GetU8(tag);
434 swf_GetRGBA(tag, &gradient2->rgba[t]);
438 #define DEBUG_ENUMERATE if(0)
440 void enumerateUsedIDs_styles(TAG * tag, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph)
444 count = swf_GetU8(tag);
445 if(count == 0xff && num>1) // defineshape2,3 only
446 count = swf_GetU16(tag);
452 swf_ResetReadBits(tag);
453 type = swf_GetU8(tag); //type
456 {swf_GetRGBA(tag, NULL);if(morph) swf_GetRGBA(tag, NULL);}
458 {swf_GetRGB(tag, NULL);if(morph) swf_GetRGB(tag, NULL);}
460 else if(type == 0x10 || type == 0x12 || type == 0x13)
462 swf_ResetReadBits(tag);
463 swf_GetMatrix(tag, NULL);
465 swf_GetMatrix(tag, NULL);
466 swf_ResetReadBits(tag);
468 swf_GetMorphGradient(tag, NULL, NULL);
470 swf_GetGradient(tag, NULL, /*alpha*/ num>=3?1:0);
472 else if(type == 0x40 || type == 0x41 || type == 0x42 || type == 0x43)
474 swf_ResetReadBits(tag);
476 if(tag->data[tag->pos] != 0xff ||
477 tag->data[tag->pos+1] != 0xff)
478 (callback)(tag, tag->pos, callback_data);
481 swf_ResetReadBits(tag);
482 swf_GetMatrix(tag, NULL);
484 swf_GetMatrix(tag, NULL);
487 fprintf(stderr, "rfxswf:swftools.c Unknown fillstyle:0x%02x\n",type);
490 swf_ResetReadBits(tag);
491 count = swf_GetU8(tag); // line style array
493 count = swf_GetU16(tag);
500 {swf_GetRGBA(tag, NULL);if(morph) swf_GetRGBA(tag, NULL);}
502 {swf_GetRGB(tag, NULL);if(morph) swf_GetRGB(tag, NULL);}
506 void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), void*callback_data)
509 swf_ResetReadBits(tag);
513 case ST_DEFINEBUTTONSOUND: {
515 callback(tag, tag->pos + base, callback_data);
518 callback(tag, tag->pos + base, callback_data);
519 swf_GetU16(tag); //sound id
520 flags = swf_GetU8(tag);
522 swf_GetU32(tag); // in point
524 swf_GetU32(tag); // out points
526 swf_GetU16(tag); // loop count
529 int npoints = swf_GetU8(tag);
531 for(s=0;s<npoints;s++)
540 case ST_DEFINEBUTTONCXFORM:
541 callback(tag, tag->pos + base, callback_data); //button id
544 case ST_EXPORTASSETS: {
545 int num = swf_GetU16(tag);
548 callback(tag, tag->pos + base, callback_data); //button id
549 swf_GetU16(tag); //id
550 while(swf_GetU8(tag)); //name
554 case ST_IMPORTASSETS:
555 case ST_IMPORTASSETS2: {
556 swf_GetString(tag); //count
557 swf_GetU8(tag); //reserved
558 swf_GetU8(tag); //reserved
559 int num = swf_GetU16(tag); //url
562 callback(tag, tag->pos + base, callback_data); //button id
563 swf_GetU16(tag); //id
564 while(swf_GetU8(tag)); //name
568 case ST_FREECHARACTER: /* unusual tags, which all start with an ID */
569 case ST_NAMECHARACTER:
570 case ST_GENERATORTEXT:
571 callback(tag, tag->pos + base, callback_data);
574 callback(tag, tag->pos + base, callback_data);
576 case ST_PLACEOBJECT2:
577 // only if placeflaghascharacter
578 if(!(tag->data[0]&2))
580 callback(tag, 3 + base, callback_data);
582 case ST_PLACEOBJECT3:
583 // only if placeflaghascharacter
584 if(!(tag->data[0]&2))
586 callback(tag, 4 + base, callback_data);
588 case ST_REMOVEOBJECT:
589 callback(tag, tag->pos + base, callback_data);
592 callback(tag, tag->pos + base, callback_data);
594 case ST_DEFINESPRITE: {
596 break; // sprite is expanded
598 swf_GetU16(tag); // id
599 swf_GetU16(tag); // framenum
602 U16 flags = swf_GetU16(tag);
605 TAG *tag2 = swf_InsertTag(NULL, id);
608 len = swf_GetU32(tag);
611 tag2->len = tag2->memsize = len;
612 tag2->data = rfx_alloc(len);
613 memcpy(tag2->data, &tag->data[tag->pos], len);
614 /* I never saw recursive sprites, but they are (theoretically)
615 possible, so better add base here again */
616 enumerateUsedIDs(tag2, tag->pos + base, callback, callback_data);
618 swf_GetBlock(tag, NULL, len);
622 case ST_DEFINEBUTTON2: // has some font ids in the button records
625 case ST_DEFINEBUTTON: {
626 swf_GetU16(tag); //button id
630 swf_GetU8(tag); //flag
631 offset = swf_GetU16(tag); //offset
636 if(!swf_GetU8(tag)) //flags
638 callback(tag, tag->pos + base, callback_data);
639 swf_GetU16(tag); //char
640 swf_GetU16(tag); //layer
641 swf_ResetReadBits(tag);
642 swf_GetMatrix(tag, NULL);
644 swf_ResetReadBits(tag);
645 swf_GetCXForm(tag, NULL, 1);
651 case ST_DEFINEEDITTEXT: {
653 swf_GetU16(tag); //id
654 swf_GetRect(tag, NULL); //bounding box
655 swf_ResetReadBits(tag);
656 flags1 = swf_GetU8(tag);
657 flags2 = swf_GetU8(tag);
659 callback(tag, tag->pos + base, callback_data);
664 case ST_DEFINETEXT: {
665 int glyphbits, advancebits;
667 id = swf_GetU16(tag); //id
668 swf_GetRect(tag, NULL); //bounding box
669 swf_ResetReadBits(tag);
670 swf_GetMatrix(tag, NULL); //matrix
671 swf_ResetReadBits(tag);
672 glyphbits = swf_GetU8(tag); //glyphbits
673 advancebits = swf_GetU8(tag); //advancebits
677 swf_ResetReadBits(tag);
678 flags = swf_GetBits(tag, 8);
681 swf_ResetReadBits(tag);
682 if(flags & 8) { // hasfont
683 callback(tag, tag->pos + base, callback_data);
684 id = swf_GetU16(tag);
686 if(flags & 4) { // hascolor
687 if(num==1) swf_GetRGB(tag, NULL);
688 else swf_GetRGBA(tag, NULL);
690 if(flags & 2) { //has x offset
691 swf_ResetReadBits(tag);
694 if(flags & 1) { //has y offset
695 swf_ResetReadBits(tag);
698 if(flags & 8) { //has height
699 swf_ResetReadBits(tag);
703 flags = swf_GetBits(tag, 8);
705 swf_ResetReadBits(tag);
706 for(t=0;t<flags;t++) {
707 swf_GetBits(tag, glyphbits);
708 swf_GetBits(tag, advancebits);
713 case ST_DEFINEFONTALIGNZONES:
714 case ST_DEFINESCALINGGRID:
716 case ST_CSMTEXTSETTINGS:
717 case ST_DEFINEFONTINFO:
718 case ST_DEFINEFONTINFO2:
720 callback(tag, tag->pos + base, callback_data);
722 case ST_DEFINEVIDEOSTREAM:
725 case ST_DOINITACTION:
726 callback(tag, tag->pos + base, callback_data);
729 case ST_DEFINEMORPHSHAPE:
730 case ST_DEFINESHAPE4:
732 case ST_DEFINESHAPE3:
734 case ST_DEFINESHAPE2:
736 case ST_DEFINESHAPE: {
742 if(tag->id == ST_DEFINEMORPHSHAPE) {
747 id = swf_GetU16(tag); // id;
748 swf_GetRect(tag, NULL); // shape bounds
750 swf_ResetReadBits(tag);
751 swf_GetRect(tag, NULL); // shape bounds2
753 swf_GetRect(tag, NULL); // edge bounds1
756 swf_GetRect(tag, NULL); // edge bounds
757 swf_GetU8(tag); // flags, &1: contains scaling stroke, &2: contains non-scaling stroke
760 swf_GetU32(tag); //offset to endedges
763 DEBUG_ENUMERATE printf("Tag:%d Name:%s ID:%d\n", tag->id, swf_TagGetName(tag), id);
765 enumerateUsedIDs_styles(tag, callback, callback_data, num, morph);
766 DEBUG_ENUMERATE printf("-------\n");
767 while(--numshapes>=0) /* morph shapes define two shapes */
769 DEBUG_ENUMERATE printf("shape:%d\n", numshapes);
770 fillbits = swf_GetBits(tag, 4);
771 linebits = swf_GetBits(tag, 4);
772 DEBUG_ENUMERATE printf("%d %d\n", fillbits, linebits);
773 swf_ResetReadBits(tag);
776 flags = swf_GetBits(tag, 1);
777 if(!flags) { //style change
778 flags = swf_GetBits(tag, 5);
782 int n = swf_GetBits(tag, 5);
784 x = swf_GetBits(tag, n); //x
785 y = swf_GetBits(tag, n); //y
786 DEBUG_ENUMERATE printf("move %f %f\n",x/20.0,y/20.0);
788 if(flags&2) { //fill0
790 fill0 = swf_GetBits(tag, fillbits);
791 DEBUG_ENUMERATE printf("fill0 %d\n", fill0);
793 if(flags&4) { //fill1
795 fill1 = swf_GetBits(tag, fillbits);
796 DEBUG_ENUMERATE printf("fill1 %d\n", fill1);
798 if(flags&8) { //linestyle
800 line = swf_GetBits(tag, linebits);
801 DEBUG_ENUMERATE printf("linestyle %d\n",line);
804 DEBUG_ENUMERATE printf("more fillstyles\n");
805 enumerateUsedIDs_styles(tag, callback, callback_data, num, 0);
806 fillbits = swf_GetBits(tag, 4);
807 linebits = swf_GetBits(tag, 4);
810 flags = swf_GetBits(tag, 1);
811 if(flags) { //straight edge
812 int n = swf_GetBits(tag, 4) + 2;
813 if(swf_GetBits(tag, 1)) { //line flag
815 x = swf_GetSBits(tag, n); //delta x
816 y = swf_GetSBits(tag, n); //delta y
817 DEBUG_ENUMERATE printf("line %f %f\n",x/20.0,y/20.0);
819 int v=swf_GetBits(tag, 1);
821 d = swf_GetSBits(tag, n); //vert/horz
822 DEBUG_ENUMERATE printf("%s %f\n",v?"vertical":"horizontal", d/20.0);
824 } else { //curved edge
825 int n = swf_GetBits(tag, 4) + 2;
827 x1 = swf_GetSBits(tag, n);
828 y1 = swf_GetSBits(tag, n);
829 x2 = swf_GetSBits(tag, n);
830 y2 = swf_GetSBits(tag, n);
831 DEBUG_ENUMERATE printf("curve %f %f %f %f\n", x1/20.0, y1/20.0, x2/20.0, y2/20.0);
843 void callbackCount(TAG * t,int pos, void*ptr)
846 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
849 void callbackFillin(TAG * t,int pos, void*ptr)
853 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
856 int swf_GetNumUsedIDs(TAG * t)
859 enumerateUsedIDs(t, 0, callbackCount, &num);
863 void swf_GetUsedIDs(TAG * t, int * positions)
865 int * ptr = positions;
866 enumerateUsedIDs(t, 0, callbackFillin, &ptr);
869 void swf_Relocate (SWF*swf, char*bitmap)
873 memset(slaveids, -1, sizeof(slaveids));
881 if(swf_isDefiningTag(tag))
886 id = swf_GetDefineID(tag); //own id
888 if(!bitmap[id]) { //free
893 for (t=1;t<65536;t++)
903 slaveids[id] = newid;
905 swf_SetDefineID(tag, newid);
908 num = swf_GetNumUsedIDs(tag);
910 ptr = rfx_alloc(sizeof(int)*num);
911 swf_GetUsedIDs(tag, ptr);
914 int id = GET16(&tag->data[ptr[t]]);
916 fprintf(stderr, "swf_Relocate: Mapping id (%d) never encountered before in %s\n", id,
917 swf_TagGetName(tag));
921 PUT16(&tag->data[ptr[t]], id);
929 void swf_Relocate2(SWF*swf, int*id2id)
934 if(swf_isDefiningTag(tag)) {
935 int id = swf_GetDefineID(tag);
938 swf_SetDefineID(tag, id);
941 int num = swf_GetNumUsedIDs(tag);
945 ptr = rfx_alloc(sizeof(int)*num);
946 swf_GetUsedIDs(tag, ptr);
948 int id = GET16(&tag->data[ptr[t]]);
951 PUT16(&tag->data[ptr[t]], id);
958 void swf_RelocateDepth(SWF*swf, char*bitmap)
963 for(nr=65535;nr>=0;nr--) {
967 // now nr is the highest used depth. So we start
968 // assigning depths at nr+1
974 /* TODO * clip depths
977 if(tag->id == ST_PLACEOBJECT2) {
979 swf_GetPlaceObject(tag, &obj);
981 int newdepth = obj.clipdepth+nr;
983 fprintf(stderr, "Couldn't relocate depths: too large values\n");
986 obj.clipdepth = newdepth;
987 swf_ResetTag(tag, ST_PLACEOBJECT2);
988 swf_SetPlaceObject(tag, &obj);
990 swf_PlaceObjectFree(&obj);
993 depth = swf_GetDepth(tag);
995 int newdepth = depth+nr;
997 fprintf(stderr, "Couldn't relocate depths: too large values\n");
1000 swf_SetDepth(tag, newdepth);
1006 U8 swf_isShapeTag(TAG*tag)
1008 if(tag->id == ST_DEFINESHAPE ||
1009 tag->id == ST_DEFINESHAPE2 ||
1010 tag->id == ST_DEFINESHAPE3 ||
1011 tag->id == ST_DEFINESHAPE4)
1016 U8 swf_isPlaceTag(TAG*tag)
1018 if(tag->id == ST_PLACEOBJECT ||
1019 tag->id == ST_PLACEOBJECT2 ||
1020 tag->id == ST_PLACEOBJECT3)
1024 U8 swf_isTextTag(TAG*tag)
1026 if(tag->id == ST_DEFINETEXT ||
1027 tag->id == ST_DEFINETEXT2)
1032 U8 swf_isFontTag(TAG*tag)
1034 if(tag->id == ST_DEFINEFONT ||
1035 tag->id == ST_DEFINEFONT2 ||
1036 tag->id == ST_DEFINEFONTINFO)
1041 U8 swf_isImageTag(TAG*tag)
1043 if(tag->id == ST_DEFINEBITSJPEG ||
1044 tag->id == ST_DEFINEBITSJPEG2 ||
1045 tag->id == ST_DEFINEBITSJPEG3 ||
1046 tag->id == ST_DEFINEBITSLOSSLESS ||
1047 tag->id == ST_DEFINEBITSLOSSLESS2)
1052 TAG* swf_Concatenate (TAG*list1,TAG*list2)
1054 TAG*tag=0,*lasttag=0;
1056 char depthmap[65536];
1058 memset(bitmap, 0, sizeof(bitmap));
1059 memset(depthmap, 0, sizeof(depthmap));
1060 memset(&swf1, 0, sizeof(swf1));
1061 memset(&swf2, 0, sizeof(swf2));
1063 swf1.firstTag = list1;
1065 swf2.firstTag = list2;
1070 if(!swf_isDefiningTag(tag)) {
1071 int id = swf_GetDefineID(tag);
1074 if(tag->id == ST_PLACEOBJECT ||
1075 tag->id == ST_PLACEOBJECT2) {
1076 int depth = swf_GetDepth(tag);
1077 depthmap[depth] = 1;
1079 if(tag->id == ST_REMOVEOBJECT ||
1080 tag->id == ST_REMOVEOBJECT2) {
1081 int depth = swf_GetDepth(tag);
1082 depthmap[depth] = 0;
1087 swf_Relocate(&swf2, bitmap);
1088 swf_RelocateDepth(&swf2, depthmap);
1089 lasttag->next = swf2.firstTag;
1090 swf2.firstTag->prev = lasttag;
1092 return swf1.firstTag;
1095 static int tagHash(TAG*tag)
1098 unsigned int a = 0x6b973e5a;
1099 /* start at pos 2, as 0 and 1 are the id */
1100 for(t=2;t<tag->len;t++) {
1103 a += tag->data[t]*0xefbc35a5*b*(t+1);
1105 return a&0x7fffffff; //always return positive number
1108 void swf_Optimize(SWF*swf)
1110 const int hash_size = 131072;
1111 char* dontremap = rfx_calloc(sizeof(char)*65536);
1112 U16* remap = rfx_alloc(sizeof(U16)*65536);
1113 TAG* id2tag = rfx_calloc(sizeof(TAG*)*65536);
1114 TAG** hashmap = rfx_calloc(sizeof(TAG*)*hash_size);
1117 for(t=0;t<65536;t++) {
1123 tag = swf->firstTag;
1125 /* make sure we don't remap to this tag,
1126 as it might have different "helper tags"
1127 FIXME: a better way would be to compare
1128 the helper tags, too.
1130 if(swf_isPseudoDefiningTag(tag) &&
1131 tag->id != ST_NAMECHARACTER) {
1132 dontremap[swf_GetDefineID(tag)] = 1;
1136 tag = swf->firstTag;
1138 TAG*next = tag->next;
1141 int num = swf_GetNumUsedIDs(tag);
1142 int*positions = rfx_alloc(sizeof(int)*num);
1144 swf_GetUsedIDs(tag, positions);
1145 for(t=0;t<num;t++) {
1146 int id = GET16(&tag->data[positions[t]]);
1148 PUT16(&tag->data[positions[t]], id);
1150 rfx_free(positions);
1152 /* now look for previous tags with the same
1154 if(swf_isDefiningTag(tag)) {
1156 int id = swf_GetDefineID(tag);
1157 int hash = tagHash(tag);
1160 while((tag2 = hashmap[hash%hash_size])) {
1161 if(tag2 != (TAG*)0 && tag->len == tag2->len) {
1162 if(memcmp(&tag->data[2],&tag2->data[2],tag->len-2) == 0) {
1170 while(hashmap[hash%hash_size]) hash++;
1171 hashmap[hash%hash_size] = tag;
1173 /* we found two identical tags- remap one
1175 remap[id] = swf_GetDefineID(tag2);
1177 if(tag == swf->firstTag)
1178 swf->firstTag = next;
1180 } else if(swf_isPseudoDefiningTag(tag)) {
1181 int id = swf_GetDefineID(tag);
1183 /* if this tag was remapped, we don't
1184 need the helper tag anymore. Discard
1187 if(tag == swf->firstTag)
1188 swf->firstTag = next;
1195 rfx_free(dontremap);
1201 void swf_SetDefineBBox(TAG * tag, SRECT newbbox)
1205 swf_SetTagPos(tag,0);
1207 switch (swf_GetTagID(tag))
1209 case ST_DEFINESHAPE:
1210 case ST_DEFINESHAPE2:
1211 case ST_DEFINESHAPE3:
1212 case ST_DEFINEEDITTEXT:
1214 case ST_DEFINETEXT2:
1215 case ST_DEFINEVIDEOSTREAM: {
1216 U32 after_bbox_offset = 0, len;
1218 id = swf_GetU16(tag);
1219 swf_GetRect(tag, &b1);
1220 swf_ResetReadBits(tag);
1221 after_bbox_offset = tag->pos;
1222 len = tag->len - after_bbox_offset;
1224 memcpy(data, &tag->data[after_bbox_offset], len);
1227 swf_SetRect(tag, &newbbox);
1228 swf_SetBlock(tag, data, len);
1230 tag->pos = tag->readBit = 0;
1234 fprintf(stderr, "rfxswf: Tag %d (%s) has no bbox\n", tag->id, swf_TagGetName(tag));
1238 RGBA swf_GetSWFBackgroundColor(SWF*swf)
1240 TAG*t=swf->firstTag;
1242 color.r = color.b = color.g = 0;
1245 if(t->id == ST_SETBACKGROUNDCOLOR) {
1246 swf_SetTagPos(t, 0);
1247 color.r = swf_GetU8(t);
1248 color.g = swf_GetU8(t);
1249 color.b = swf_GetU8(t);