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_DEFINEMORPHSHAPE:
102 case ST_DEFINEEDITTEXT:
104 case ST_DEFINEBITSJPEG2:
105 case ST_DEFINEBITSJPEG3:
106 case ST_DEFINEBITSLOSSLESS:
107 case ST_DEFINEBITSLOSSLESS2:
108 case ST_DEFINEBUTTON:
109 case ST_DEFINEBUTTON2:
110 case ST_DEFINEBUTTONCXFORM: //pseudodefine
111 case ST_DEFINEBUTTONSOUND: //pseudodefine
114 case ST_DEFINEFONTINFO: //pseudodefine
115 case ST_DEFINEFONTINFO2: //pseudodefine
119 case ST_DEFINESPRITE:
121 case ST_DEFINEVIDEOSTREAM:
122 case ST_GLYPHNAMES: //pseudodefine
123 case ST_VIDEOFRAME: //pseudodefine
124 case ST_NAMECHARACTER: //pseudodefine
125 case ST_DOINITACTION: //pseudodefine
129 fprintf(stderr, "rfxswf: Error: tag %d (%s) has no id\n", t->id, swf_TagGetName(t));
132 swf_SetTagPos(t,oldTagPos);
137 SRECT swf_GetDefineBBox(TAG * t)
142 memset(&b1, 0, sizeof(b1));
144 oldTagPos = swf_GetTagPos(t);
149 switch (swf_GetTagID(t))
150 { case ST_DEFINESHAPE:
151 case ST_DEFINESHAPE2:
152 case ST_DEFINESHAPE3:
153 case ST_DEFINEEDITTEXT:
156 case ST_DEFINEVIDEOSTREAM:
160 case ST_DEFINEMORPHSHAPE:
164 swf_ExpandRect2(&b1, &b2);
166 case ST_DEFINEBITSLOSSLESS:
167 case ST_DEFINEBITSLOSSLESS2:
169 case ST_DEFINEBITSJPEG2:
170 case ST_DEFINEBITSJPEG3:
175 swf_SetTagPos(t,oldTagPos);
180 U16 swf_GetPlaceID(TAG * t)
185 oldTagPos = swf_GetTagPos(t);
188 switch (swf_GetTagID(t))
189 { case ST_PLACEOBJECT:
190 case ST_REMOVEOBJECT:
191 case ST_FREECHARACTER:
196 case ST_PLACEOBJECT2:
197 { U8 flags = swf_GetU8(t);
198 U16 d = swf_GetU16(t);
199 id = (flags&PF_CHAR)?swf_GetU16(t):id;
204 swf_SetTagPos(t,oldTagPos);
209 static int swf_definingtagids[] =
222 ST_DEFINEBITSLOSSLESS,
223 ST_DEFINEBITSLOSSLESS2,
229 ST_DEFINEVIDEOSTREAM,
233 // tags which may be used inside a sprite definition
234 static int swf_spritetagids[] =
239 ST_REMOVEOBJECT2, //?
250 static int swf_pseudodefiningtagids[] =
254 ST_DEFINEBUTTONCXFORM,
255 ST_DEFINEBUTTONSOUND,
263 U8 swf_isAllowedSpriteTag(TAG * tag)
267 while(swf_spritetagids[t]>=0)
269 if(swf_spritetagids[t] == id)
276 U8 swf_isDefiningTag(TAG * tag)
280 while(swf_definingtagids[t]>=0)
282 if(swf_definingtagids[t] == id)
289 U8 swf_isPseudoDefiningTag(TAG * tag)
293 while(swf_pseudodefiningtagids[t]>=0)
295 if(swf_pseudodefiningtagids[t] == id)
302 int swf_GetDepth(TAG * t)
306 oldTagPos = swf_GetTagPos(t);
309 switch (swf_GetTagID(t))
310 { case ST_PLACEOBJECT:
311 case ST_REMOVEOBJECT:
313 depth = swf_GetU16(t);
315 case ST_REMOVEOBJECT2:
316 depth = swf_GetU16(t);
318 case ST_PLACEOBJECT2:
319 { U8 flags = swf_GetU8(t);
320 depth = swf_GetU16(t);
324 depth = swf_GetU16(t);
327 swf_SetTagPos(t,oldTagPos);
331 void swf_SetDepth(TAG * t, U16 depth)
333 switch (swf_GetTagID(t))
334 { case ST_PLACEOBJECT:
335 case ST_REMOVEOBJECT:
336 PUT16(t->data, depth);
338 case ST_REMOVEOBJECT2:
339 PUT16(t->data, depth);
341 case ST_PLACEOBJECT2:
342 PUT16(&t->data[1], depth);
345 PUT16(t->data, depth);
348 fprintf(stderr, "rfxswf: Error: tag %d has no depth\n", t->id);
352 char* swf_GetName(TAG * t)
358 oldTagPos = swf_GetTagPos(t);
360 switch(swf_GetTagID(t))
363 name = &t->data[swf_GetTagPos(t)];
365 case ST_PLACEOBJECT2: {
366 U8 flags = swf_GetU8(t);
367 swf_GetU16(t); //depth;
371 swf_GetMatrix(t, &m);
373 swf_GetCXForm(t, &c, 1);
376 if(flags&PF_CLIPACTION)
379 swf_ResetReadBits(t);
380 name = &t->data[swf_GetTagPos(t)];
385 swf_SetTagPos(t,oldTagPos);
389 /* used in enumerateUsedIDs */
390 void swf_GetMorphGradient(TAG * tag, GRADIENT * gradient1, GRADIENT * gradient2)
400 gradient2->num = swf_GetU8(tag);
401 for(t=0;t<gradient1->num;t++)
406 gradient1->ratios[t] = swf_GetU8(tag);
407 swf_GetRGBA(tag, &gradient1->rgba[t]);
408 gradient2->ratios[t] = swf_GetU8(tag);
409 swf_GetRGBA(tag, &gradient2->rgba[t]);
413 #define DEBUG_ENUMERATE if(0)
415 void enumerateUsedIDs_styles(TAG * tag, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph)
419 count = swf_GetU8(tag);
420 if(count == 0xff && num>1) // defineshape2,3 only
421 count = swf_GetU16(tag);
427 swf_ResetReadBits(tag);
428 type = swf_GetU8(tag); //type
431 {swf_GetRGBA(tag, NULL);if(morph) swf_GetRGBA(tag, NULL);}
433 {swf_GetRGB(tag, NULL);if(morph) swf_GetRGB(tag, NULL);}
435 else if(type == 0x10 || type == 0x12)
437 swf_ResetReadBits(tag);
438 swf_GetMatrix(tag, NULL);
440 swf_GetMatrix(tag, NULL);
441 swf_ResetReadBits(tag);
443 swf_GetMorphGradient(tag, NULL, NULL);
445 swf_GetGradient(tag, NULL, /*alpha*/ num>=3?1:0);
447 else if(type == 0x40 || type == 0x41)
449 swf_ResetReadBits(tag);
451 if(tag->data[tag->pos] != 0xff ||
452 tag->data[tag->pos+1] != 0xff)
453 (callback)(tag, tag->pos, callback_data);
456 swf_ResetReadBits(tag);
457 swf_GetMatrix(tag, NULL);
459 swf_GetMatrix(tag, NULL);
462 fprintf(stderr, "rfxswf:swftools.c Unknown fillstyle:0x%02x\n",type);
465 swf_ResetReadBits(tag);
466 count = swf_GetU8(tag); // line style array
468 count = swf_GetU16(tag);
475 {swf_GetRGBA(tag, NULL);if(morph) swf_GetRGBA(tag, NULL);}
477 {swf_GetRGB(tag, NULL);if(morph) swf_GetRGB(tag, NULL);}
481 void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), void*callback_data)
484 swf_ResetReadBits(tag);
488 case ST_DEFINEBUTTONSOUND: {
490 callback(tag, tag->pos + base, callback_data);
493 callback(tag, tag->pos + base, callback_data);
494 swf_GetU16(tag); //sound id
495 flags = swf_GetU8(tag);
497 swf_GetU32(tag); // in point
499 swf_GetU32(tag); // out points
501 swf_GetU16(tag); // loop count
504 int npoints = swf_GetU8(tag);
506 for(s=0;s<npoints;s++)
515 case ST_DEFINEBUTTONCXFORM:
516 callback(tag, tag->pos + base, callback_data); //button id
519 case ST_EXPORTASSETS: {
520 int num = swf_GetU16(tag);
523 callback(tag, tag->pos + base, callback_data); //button id
524 swf_GetU16(tag); //id
525 while(swf_GetU8(tag)); //name
529 case ST_FREECHARACTER: /* unusual tags, which all start with an ID */
530 case ST_NAMECHARACTER:
531 case ST_GENERATORTEXT:
532 callback(tag, tag->pos + base, callback_data);
535 callback(tag, tag->pos + base, callback_data);
537 case ST_PLACEOBJECT2:
538 // only if placeflaghascharacter
539 if(!(tag->data[0]&2))
541 callback(tag, 3 + base, callback_data);
543 case ST_REMOVEOBJECT:
544 callback(tag, tag->pos + base, callback_data);
547 callback(tag, tag->pos + base, callback_data);
549 case ST_DEFINESPRITE: {
551 break; // sprite is expanded
553 swf_GetU16(tag); // id
554 swf_GetU16(tag); // framenum
557 U16 flags = swf_GetU16(tag);
560 TAG *tag2 = swf_InsertTag(NULL, id);
563 len = swf_GetU32(tag);
566 tag2->len = tag2->memsize = len;
567 tag2->data = rfx_alloc(len);
568 memcpy(tag2->data, &tag->data[tag->pos], len);
569 /* I never saw recursive sprites, but they are (theoretically)
570 possible, so better add base here again */
571 enumerateUsedIDs(tag2, tag->pos + base, callback, callback_data);
573 swf_GetBlock(tag, NULL, len);
577 case ST_DEFINEBUTTON2: // has some font ids in the button records
580 case ST_DEFINEBUTTON: {
581 swf_GetU16(tag); //button id
585 swf_GetU8(tag); //flag
586 offset = swf_GetU16(tag); //offset
591 if(!swf_GetU8(tag)) //flags
593 callback(tag, tag->pos + base, callback_data);
594 swf_GetU16(tag); //char
595 swf_GetU16(tag); //layer
596 swf_ResetReadBits(tag);
597 swf_GetMatrix(tag, NULL);
599 swf_ResetReadBits(tag);
600 swf_GetCXForm(tag, NULL, 1);
606 case ST_DEFINEEDITTEXT: {
608 swf_GetU16(tag); //id
609 swf_GetRect(tag, NULL); //bounding box
610 swf_ResetReadBits(tag);
611 flags1 = swf_GetU8(tag);
612 flags2 = swf_GetU8(tag);
614 callback(tag, tag->pos + base, callback_data);
619 case ST_DEFINETEXT: {
620 int glyphbits, advancebits;
622 id = swf_GetU16(tag); //id
623 swf_GetRect(tag, NULL); //bounding box
624 swf_ResetReadBits(tag);
625 swf_GetMatrix(tag, NULL); //matrix
626 swf_ResetReadBits(tag);
627 glyphbits = swf_GetU8(tag); //glyphbits
628 advancebits = swf_GetU8(tag); //advancebits
632 swf_ResetReadBits(tag);
633 flags = swf_GetBits(tag, 8);
636 swf_ResetReadBits(tag);
637 if(flags & 8) { // hasfont
638 callback(tag, tag->pos + base, callback_data);
639 id = swf_GetU16(tag);
641 if(flags & 4) { // hascolor
642 if(num==1) swf_GetRGB(tag, NULL);
643 else swf_GetRGBA(tag, NULL);
645 if(flags & 2) { //has x offset
646 swf_ResetReadBits(tag);
649 if(flags & 1) { //has y offset
650 swf_ResetReadBits(tag);
653 if(flags & 8) { //has height
654 swf_ResetReadBits(tag);
658 flags = swf_GetBits(tag, 8);
660 swf_ResetReadBits(tag);
661 for(t=0;t<flags;t++) {
662 swf_GetBits(tag, glyphbits);
663 swf_GetBits(tag, advancebits);
669 case ST_DEFINEFONTINFO:
670 case ST_DEFINEFONTINFO2:
672 callback(tag, tag->pos + base, callback_data);
674 case ST_DEFINEVIDEOSTREAM:
677 case ST_DOINITACTION:
678 callback(tag, tag->pos + base, callback_data);
681 case ST_DEFINEMORPHSHAPE:
682 case ST_DEFINESHAPE3:
684 case ST_DEFINESHAPE2:
686 case ST_DEFINESHAPE: {
692 if(tag->id == ST_DEFINEMORPHSHAPE) {
697 id = swf_GetU16(tag); // id;
698 swf_GetRect(tag, NULL); // bounds
700 swf_ResetReadBits(tag);
701 swf_GetRect(tag, NULL); // bounds2
702 swf_GetU32(tag); //offset to endedges
705 DEBUG_ENUMERATE printf("Tag:%d Name:%s ID:%d\n", tag->id, swf_TagGetName(tag), id);
707 enumerateUsedIDs_styles(tag, callback, callback_data, num, morph);
708 DEBUG_ENUMERATE printf("-------\n");
709 while(--numshapes>=0) /* morph shapes define two shapes */
711 DEBUG_ENUMERATE printf("shape:%d\n", numshapes);
712 fillbits = swf_GetBits(tag, 4);
713 linebits = swf_GetBits(tag, 4);
714 DEBUG_ENUMERATE printf("%d %d\n", fillbits, linebits);
715 swf_ResetReadBits(tag);
718 flags = swf_GetBits(tag, 1);
719 if(!flags) { //style change
720 flags = swf_GetBits(tag, 5);
724 int n = swf_GetBits(tag, 5);
726 x = swf_GetBits(tag, n); //x
727 y = swf_GetBits(tag, n); //y
728 DEBUG_ENUMERATE printf("move %f %f\n",x/20.0,y/20.0);
730 if(flags&2) { //fill0
732 fill0 = swf_GetBits(tag, fillbits);
733 DEBUG_ENUMERATE printf("fill0 %d\n", fill0);
735 if(flags&4) { //fill1
737 fill1 = swf_GetBits(tag, fillbits);
738 DEBUG_ENUMERATE printf("fill1 %d\n", fill1);
740 if(flags&8) { //linestyle
742 line = swf_GetBits(tag, linebits);
743 DEBUG_ENUMERATE printf("linestyle %d\n",line);
746 DEBUG_ENUMERATE printf("more fillstyles\n");
747 enumerateUsedIDs_styles(tag, callback, callback_data, num, 0);
748 fillbits = swf_GetBits(tag, 4);
749 linebits = swf_GetBits(tag, 4);
752 flags = swf_GetBits(tag, 1);
753 if(flags) { //straight edge
754 int n = swf_GetBits(tag, 4) + 2;
755 if(swf_GetBits(tag, 1)) { //line flag
757 x = swf_GetSBits(tag, n); //delta x
758 y = swf_GetSBits(tag, n); //delta y
759 DEBUG_ENUMERATE printf("line %f %f\n",x/20.0,y/20.0);
761 int v=swf_GetBits(tag, 1);
763 d = swf_GetSBits(tag, n); //vert/horz
764 DEBUG_ENUMERATE printf("%s %f\n",v?"vertical":"horizontal", d/20.0);
766 } else { //curved edge
767 int n = swf_GetBits(tag, 4) + 2;
769 x1 = swf_GetSBits(tag, n);
770 y1 = swf_GetSBits(tag, n);
771 x2 = swf_GetSBits(tag, n);
772 y2 = swf_GetSBits(tag, n);
773 DEBUG_ENUMERATE printf("curve %f %f %f %f\n", x1/20.0, y1/20.0, x2/20.0, y2/20.0);
785 void callbackCount(TAG * t,int pos, void*ptr)
788 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
791 void callbackFillin(TAG * t,int pos, void*ptr)
795 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
798 int swf_GetNumUsedIDs(TAG * t)
801 enumerateUsedIDs(t, 0, callbackCount, &num);
805 void swf_GetUsedIDs(TAG * t, int * positions)
807 int * ptr = positions;
808 enumerateUsedIDs(t, 0, callbackFillin, &ptr);
811 void swf_Relocate (SWF*swf, char*bitmap)
815 memset(slaveids, -1, sizeof(slaveids));
823 if(swf_isDefiningTag(tag))
828 id = swf_GetDefineID(tag); //own id
830 if(!bitmap[id]) { //free
835 for (t=1;t<65536;t++)
845 slaveids[id] = newid;
847 swf_SetDefineID(tag, newid);
850 num = swf_GetNumUsedIDs(tag);
852 ptr = rfx_alloc(sizeof(int)*num);
853 swf_GetUsedIDs(tag, ptr);
856 int id = GET16(&tag->data[ptr[t]]);
858 fprintf(stderr, "swf_Relocate: Mapping id (%d) never encountered before in %s\n", id,
859 swf_TagGetName(tag));
863 PUT16(&tag->data[ptr[t]], id);
871 void swf_Relocate2(SWF*swf, int*id2id)
876 if(swf_isDefiningTag(tag)) {
877 int id = swf_GetDefineID(tag);
880 swf_SetDefineID(tag, id);
883 int num = swf_GetNumUsedIDs(tag);
887 ptr = rfx_alloc(sizeof(int)*num);
888 swf_GetUsedIDs(tag, ptr);
890 int id = GET16(&tag->data[ptr[t]]);
893 PUT16(&tag->data[ptr[t]], id);
900 void swf_RelocateDepth(SWF*swf, char*bitmap)
905 for(nr=65535;nr>=0;nr--) {
909 // now nr is the highest used depth. So we start
910 // assigning depths at nr+1
916 /* TODO * clip depths
919 if(tag->id == ST_PLACEOBJECT2) {
921 swf_GetPlaceObject(tag, &obj);
923 int newdepth = obj.clipdepth+nr;
925 fprintf(stderr, "Couldn't relocate depths: too large values\n");
928 obj.clipdepth = newdepth;
929 swf_ResetTag(tag, ST_PLACEOBJECT2);
930 swf_SetPlaceObject(tag, &obj);
932 swf_PlaceObjectFree(&obj);
935 depth = swf_GetDepth(tag);
937 int newdepth = depth+nr;
939 fprintf(stderr, "Couldn't relocate depths: too large values\n");
942 swf_SetDepth(tag, newdepth);
948 U8 swf_isShapeTag(TAG*tag)
950 if(tag->id == ST_DEFINESHAPE ||
951 tag->id == ST_DEFINESHAPE2 ||
952 tag->id == ST_DEFINESHAPE3)
957 U8 swf_isPlaceTag(TAG*tag)
959 if(tag->id == ST_PLACEOBJECT ||
960 tag->id == ST_PLACEOBJECT2)
964 U8 swf_isTextTag(TAG*tag)
966 if(tag->id == ST_DEFINETEXT ||
967 tag->id == ST_DEFINETEXT2)
972 U8 swf_isFontTag(TAG*tag)
974 if(tag->id == ST_DEFINEFONT ||
975 tag->id == ST_DEFINEFONT2 ||
976 tag->id == ST_DEFINEFONTINFO)
981 U8 swf_isImageTag(TAG*tag)
983 if(tag->id == ST_DEFINEBITSJPEG ||
984 tag->id == ST_DEFINEBITSJPEG2 ||
985 tag->id == ST_DEFINEBITSJPEG3 ||
986 tag->id == ST_DEFINEBITSLOSSLESS ||
987 tag->id == ST_DEFINEBITSLOSSLESS2)
992 TAG* swf_Concatenate (TAG*list1,TAG*list2)
994 TAG*tag=0,*lasttag=0;
996 char depthmap[65536];
998 memset(bitmap, 0, sizeof(bitmap));
999 memset(depthmap, 0, sizeof(depthmap));
1000 memset(&swf1, 0, sizeof(swf1));
1001 memset(&swf2, 0, sizeof(swf2));
1003 swf1.firstTag = list1;
1005 swf2.firstTag = list2;
1010 if(!swf_isDefiningTag(tag)) {
1011 int id = swf_GetDefineID(tag);
1014 if(tag->id == ST_PLACEOBJECT ||
1015 tag->id == ST_PLACEOBJECT2) {
1016 int depth = swf_GetDepth(tag);
1017 depthmap[depth] = 1;
1019 if(tag->id == ST_REMOVEOBJECT ||
1020 tag->id == ST_REMOVEOBJECT2) {
1021 int depth = swf_GetDepth(tag);
1022 depthmap[depth] = 0;
1027 swf_Relocate(&swf2, bitmap);
1028 swf_RelocateDepth(&swf2, depthmap);
1029 lasttag->next = swf2.firstTag;
1030 swf2.firstTag->prev = lasttag;
1032 return swf1.firstTag;
1035 static int tagHash(TAG*tag)
1038 unsigned int a = 0x6b973e5a;
1039 /* start at pos 2, as 0 and 1 are the id */
1040 for(t=2;t<tag->len;t++) {
1043 a += tag->data[t]*0xefbc35a5*b*(t+1);
1045 return a&0x7fffffff; //always return positive number
1048 void swf_Optimize(SWF*swf)
1050 const int hash_size = 131072;
1051 char* dontremap = rfx_calloc(sizeof(char)*65536);
1052 U16* remap = rfx_alloc(sizeof(U16)*65536);
1053 TAG* id2tag = rfx_calloc(sizeof(TAG*)*65536);
1054 TAG** hashmap = rfx_calloc(sizeof(TAG*)*hash_size);
1057 for(t=0;t<65536;t++) {
1063 tag = swf->firstTag;
1065 /* make sure we don't remap to this tag,
1066 as it might have different "helper tags"
1067 FIXME: a better way would be to compare
1068 the helper tags, too.
1070 if(swf_isPseudoDefiningTag(tag) &&
1071 tag->id != ST_NAMECHARACTER) {
1072 dontremap[swf_GetDefineID(tag)] = 1;
1076 tag = swf->firstTag;
1078 TAG*next = tag->next;
1081 int num = swf_GetNumUsedIDs(tag);
1082 int*positions = rfx_alloc(sizeof(int)*num);
1084 swf_GetUsedIDs(tag, positions);
1085 for(t=0;t<num;t++) {
1086 int id = GET16(&tag->data[positions[t]]);
1088 PUT16(&tag->data[positions[t]], id);
1090 rfx_free(positions);
1092 /* now look for previous tags with the same
1094 if(swf_isDefiningTag(tag)) {
1096 int id = swf_GetDefineID(tag);
1097 int hash = tagHash(tag);
1100 while((tag2 = hashmap[hash%hash_size])) {
1101 if(tag2 != (TAG*)0 && tag->len == tag2->len) {
1102 if(memcmp(&tag->data[2],&tag2->data[2],tag->len-2) == 0) {
1110 while(hashmap[hash%hash_size]) hash++;
1111 hashmap[hash%hash_size] = tag;
1113 /* we found two identical tags- remap one
1115 remap[id] = swf_GetDefineID(tag2);
1117 if(tag == swf->firstTag)
1118 swf->firstTag = next;
1120 } else if(swf_isPseudoDefiningTag(tag)) {
1121 int id = swf_GetDefineID(tag);
1123 /* if this tag was remapped, we don't
1124 need the helper tag anymore. Discard
1127 if(tag == swf->firstTag)
1128 swf->firstTag = next;
1135 rfx_free(dontremap);
1141 void swf_SetDefineBBox(TAG * tag, SRECT newbbox)
1145 swf_SetTagPos(tag,0);
1147 switch (swf_GetTagID(tag))
1149 case ST_DEFINESHAPE:
1150 case ST_DEFINESHAPE2:
1151 case ST_DEFINESHAPE3:
1152 case ST_DEFINEEDITTEXT:
1154 case ST_DEFINETEXT2:
1155 case ST_DEFINEVIDEOSTREAM: {
1156 U32 after_bbox_offset = 0, len;
1158 id = swf_GetU16(tag);
1159 swf_GetRect(tag, &b1);
1160 swf_ResetReadBits(tag);
1161 after_bbox_offset = tag->pos;
1162 len = tag->len - after_bbox_offset;
1164 memcpy(data, &tag->data[after_bbox_offset], len);
1167 swf_SetRect(tag, &newbbox);
1168 swf_SetBlock(tag, data, len);
1170 tag->pos = tag->readBit = 0;
1174 fprintf(stderr, "rfxswf: Tag %d (%s) has no bbox\n", tag->id, swf_TagGetName(tag));
1178 RGBA swf_GetSWFBackgroundColor(SWF*swf)
1180 TAG*t=swf->firstTag;
1182 color.r = color.b = color.g = 0;
1185 if(t->id == ST_SETBACKGROUNDCOLOR) {
1186 swf_SetTagPos(t, 0);
1187 color.r = swf_GetU8(t);
1188 color.g = swf_GetU8(t);
1189 color.b = swf_GetU8(t);