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_DEFINESHAPE4:
159 case ST_DEFINEEDITTEXT:
162 case ST_DEFINEVIDEOSTREAM:
166 case ST_DEFINEMORPHSHAPE:
170 swf_ExpandRect2(&b1, &b2);
172 case ST_DEFINEBITSLOSSLESS:
173 case ST_DEFINEBITSLOSSLESS2:
175 case ST_DEFINEBITSJPEG2:
176 case ST_DEFINEBITSJPEG3:
181 swf_SetTagPos(t,oldTagPos);
186 U16 swf_GetPlaceID(TAG * t)
191 oldTagPos = swf_GetTagPos(t);
194 switch (swf_GetTagID(t))
195 { case ST_PLACEOBJECT:
196 case ST_REMOVEOBJECT:
197 case ST_FREECHARACTER:
202 case ST_PLACEOBJECT2:
203 { U8 flags = swf_GetU8(t);
204 U16 d = swf_GetU16(t);
205 id = (flags&PF_CHAR)?swf_GetU16(t):id;
207 case ST_PLACEOBJECT3:
208 { U8 flags = swf_GetU8(t);
209 U8 flags2 = swf_GetU8(t);
210 U16 d = swf_GetU16(t);
211 id = (flags&PF_CHAR)?swf_GetU16(t):id;
216 swf_SetTagPos(t,oldTagPos);
221 static int swf_definingtagids[] =
236 ST_DEFINEBITSLOSSLESS,
237 ST_DEFINEBITSLOSSLESS2,
243 ST_DEFINEVIDEOSTREAM,
247 // tags which may be used inside a sprite definition
248 static int swf_spritetagids[] =
265 /* tags which add content or information to a character with a given ID */
266 static int swf_pseudodefiningtagids[] =
270 ST_DEFINEFONTALIGNZONES,
271 ST_DEFINEBUTTONCXFORM,
272 ST_DEFINEBUTTONSOUND,
273 ST_DEFINESCALINGGRID,
282 U8 swf_isAllowedSpriteTag(TAG * tag)
286 while(swf_spritetagids[t]>=0)
288 if(swf_spritetagids[t] == id)
295 U8 swf_isDefiningTag(TAG * tag)
299 while(swf_definingtagids[t]>=0)
301 if(swf_definingtagids[t] == id)
308 U8 swf_isPseudoDefiningTag(TAG * tag)
312 while(swf_pseudodefiningtagids[t]>=0)
314 if(swf_pseudodefiningtagids[t] == id)
321 int swf_GetDepth(TAG * t)
325 oldTagPos = swf_GetTagPos(t);
328 switch (swf_GetTagID(t))
329 { case ST_PLACEOBJECT:
330 case ST_REMOVEOBJECT:
332 depth = swf_GetU16(t);
334 case ST_REMOVEOBJECT2:
335 depth = swf_GetU16(t);
337 case ST_PLACEOBJECT2:
338 { U8 flags = swf_GetU8(t);
339 depth = swf_GetU16(t);
341 case ST_PLACEOBJECT3:
342 { U8 flags = swf_GetU8(t);
343 U8 flags2 = swf_GetU8(t);
344 depth = swf_GetU16(t);
348 depth = swf_GetU16(t);
351 swf_SetTagPos(t,oldTagPos);
355 void swf_SetDepth(TAG * t, U16 depth)
357 switch (swf_GetTagID(t))
358 { case ST_PLACEOBJECT:
359 case ST_REMOVEOBJECT:
360 PUT16(t->data, depth);
362 case ST_REMOVEOBJECT2:
363 PUT16(t->data, depth);
365 case ST_PLACEOBJECT2:
366 PUT16(&t->data[1], depth);
369 PUT16(t->data, depth);
372 fprintf(stderr, "rfxswf: Error: tag %d has no depth\n", t->id);
376 char* swf_GetName(TAG * t)
382 oldTagPos = swf_GetTagPos(t);
384 switch(swf_GetTagID(t))
387 name = &t->data[swf_GetTagPos(t)];
389 case ST_PLACEOBJECT3:
390 case ST_PLACEOBJECT2: {
391 U8 flags = swf_GetU8(t);
392 if(t->id == ST_PLACEOBJECT3)
394 swf_GetU16(t); //depth;
398 swf_GetMatrix(t, &m);
400 swf_GetCXForm(t, &c, 1);
403 if(flags&PF_CLIPDEPTH)
406 swf_ResetReadBits(t);
407 name = &t->data[swf_GetTagPos(t)];
412 swf_SetTagPos(t,oldTagPos);
416 /* used in enumerateUsedIDs */
417 void swf_GetMorphGradient(TAG * tag, GRADIENT * gradient1, GRADIENT * gradient2)
420 int num = swf_GetU8(tag) & 15;
421 if(gradient1) gradient1->num = num;
422 if(gradient2) gradient2->num = num;
425 gradient1->num = num;
426 gradient1->rgba = rfx_calloc(sizeof(RGBA)*gradient1->num);
427 gradient1->ratios = rfx_calloc(sizeof(gradient1->ratios[0])*gradient1->num);
430 gradient2->num = num;
431 gradient2->rgba = rfx_calloc(sizeof(RGBA)*gradient2->num);
432 gradient2->ratios = rfx_calloc(sizeof(gradient2->ratios[0])*gradient2->num);
439 ratio = swf_GetU8(tag);
440 swf_GetRGBA(tag, &color);
442 gradient1->ratios[t] = ratio;
443 gradient1->rgba[t] = color;
446 ratio = swf_GetU8(tag);
447 swf_GetRGBA(tag, &color);
449 gradient2->ratios[t] = ratio;
450 gradient2->rgba[t] = color;
455 #define DEBUG_ENUMERATE if(0)
456 //#define DEBUG_ENUMERATE
458 void enumerateUsedIDs_styles(TAG * tag, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph)
462 count = swf_GetU8(tag);
463 if(count == 0xff && num>1) // defineshape2,3,4 only
464 count = swf_GetU16(tag);
466 DEBUG_ENUMERATE printf("%d fill styles\n", count);
471 type = swf_GetU8(tag); //type
472 DEBUG_ENUMERATE printf("fill style %d) %02x (tagpos=%d)\n", t, type, tag->pos);
475 {swf_GetRGBA(tag, NULL);if(morph) swf_GetRGBA(tag, NULL);}
477 {swf_GetRGB(tag, NULL);if(morph) swf_GetRGB(tag, NULL);}
479 else if(type == 0x10 || type == 0x12 || type == 0x13)
481 swf_ResetReadBits(tag);
483 swf_GetMatrix(tag, &m);
484 DEBUG_ENUMERATE swf_DumpMatrix(stdout, &m);
486 swf_GetMatrix(tag, NULL);
487 swf_ResetReadBits(tag);
489 swf_GetMorphGradient(tag, NULL, NULL);
492 swf_GetGradient(tag, &g, /*alpha*/ num>=3?1:0);
493 DEBUG_ENUMERATE swf_DumpGradient(stdout, &g);
498 else if(type == 0x40 || type == 0x41 || type == 0x42 || type == 0x43)
500 swf_ResetReadBits(tag);
501 if(tag->data[tag->pos] != 0xff ||
502 tag->data[tag->pos+1] != 0xff)
503 (callback)(tag, tag->pos, callback_data);
506 swf_ResetReadBits(tag);
507 swf_GetMatrix(tag, NULL);
509 swf_GetMatrix(tag, NULL);
512 fprintf(stderr, "rfxswf:swftools.c Unknown fillstyle:0x%02x in tag %02x\n",type, tag->id);
515 swf_ResetReadBits(tag);
516 count = swf_GetU8(tag); // line style array
518 count = swf_GetU16(tag);
519 DEBUG_ENUMERATE printf("%d line styles\n", count);
524 width = swf_GetU16(tag);
528 U16 flags = swf_GetU16(tag);
530 swf_GetU16(tag); // miter limit
532 fprintf(stderr, "Filled strokes parsing not yet supported\n");
536 {swf_GetRGBA(tag, &color);if(morph) swf_GetRGBA(tag, NULL);}
538 {swf_GetRGB(tag, &color);if(morph) swf_GetRGB(tag, NULL);}
539 DEBUG_ENUMERATE printf("line style %d: %02x%02x%02x%02x \n", t, color.r,color.g,color.b,color.a);
543 void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), void*callback_data)
546 swf_ResetReadBits(tag);
550 case ST_DEFINEBUTTONSOUND: {
552 callback(tag, tag->pos + base, callback_data);
555 callback(tag, tag->pos + base, callback_data);
556 swf_GetU16(tag); //sound id
557 flags = swf_GetU8(tag);
559 swf_GetU32(tag); // in point
561 swf_GetU32(tag); // out points
563 swf_GetU16(tag); // loop count
566 int npoints = swf_GetU8(tag);
568 for(s=0;s<npoints;s++)
577 case ST_DEFINEBUTTONCXFORM:
578 callback(tag, tag->pos + base, callback_data); //button id
581 case ST_EXPORTASSETS: {
582 int num = swf_GetU16(tag);
585 callback(tag, tag->pos + base, callback_data); //button id
586 swf_GetU16(tag); //id
587 while(swf_GetU8(tag)); //name
591 case ST_IMPORTASSETS:
592 case ST_IMPORTASSETS2: {
593 swf_GetString(tag); //count
594 swf_GetU8(tag); //reserved
595 swf_GetU8(tag); //reserved
596 int num = swf_GetU16(tag); //url
599 callback(tag, tag->pos + base, callback_data); //button id
600 swf_GetU16(tag); //id
601 while(swf_GetU8(tag)); //name
605 case ST_FREECHARACTER: /* unusual tags, which all start with an ID */
606 case ST_NAMECHARACTER:
607 case ST_GENERATORTEXT:
608 callback(tag, tag->pos + base, callback_data);
611 callback(tag, tag->pos + base, callback_data);
613 case ST_PLACEOBJECT2:
614 // only if placeflaghascharacter
615 if(!(tag->data[0]&2))
617 callback(tag, 3 + base, callback_data);
619 case ST_PLACEOBJECT3:
620 // only if placeflaghascharacter
621 if(!(tag->data[0]&2))
623 callback(tag, 4 + base, callback_data);
625 case ST_REMOVEOBJECT:
626 callback(tag, tag->pos + base, callback_data);
629 callback(tag, tag->pos + base, callback_data);
631 case ST_DEFINESPRITE: {
633 break; // sprite is expanded
635 swf_GetU16(tag); // id
636 swf_GetU16(tag); // framenum
639 U16 flags = swf_GetU16(tag);
642 TAG *tag2 = swf_InsertTag(NULL, id);
645 len = swf_GetU32(tag);
648 tag2->len = tag2->memsize = len;
649 tag2->data = rfx_alloc(len);
650 memcpy(tag2->data, &tag->data[tag->pos], len);
651 /* I never saw recursive sprites, but they are (theoretically)
652 possible, so better add base here again */
653 enumerateUsedIDs(tag2, tag->pos + base, callback, callback_data);
655 swf_GetBlock(tag, NULL, len);
659 case ST_DEFINEBUTTON2: // has some font ids in the button records
662 case ST_DEFINEBUTTON: {
663 swf_GetU16(tag); //button id
667 swf_GetU8(tag); //flag
668 offset = swf_GetU16(tag); //offset
673 if(!swf_GetU8(tag)) //flags
675 callback(tag, tag->pos + base, callback_data);
676 swf_GetU16(tag); //char
677 swf_GetU16(tag); //layer
678 swf_ResetReadBits(tag);
679 swf_GetMatrix(tag, NULL);
681 swf_ResetReadBits(tag);
682 swf_GetCXForm(tag, NULL, 1);
688 case ST_DEFINEEDITTEXT: {
690 swf_GetU16(tag); //id
691 swf_GetRect(tag, NULL); //bounding box
692 swf_ResetReadBits(tag);
693 flags1 = swf_GetU8(tag);
694 flags2 = swf_GetU8(tag);
696 callback(tag, tag->pos + base, callback_data);
701 case ST_DEFINETEXT: {
702 int glyphbits, advancebits;
704 id = swf_GetU16(tag); //id
705 swf_GetRect(tag, NULL); //bounding box
706 swf_ResetReadBits(tag);
707 swf_GetMatrix(tag, NULL); //matrix
708 swf_ResetReadBits(tag);
709 glyphbits = swf_GetU8(tag); //glyphbits
710 advancebits = swf_GetU8(tag); //advancebits
714 swf_ResetReadBits(tag);
715 flags = swf_GetBits(tag, 8);
718 swf_ResetReadBits(tag);
719 if(flags & 8) { // hasfont
720 callback(tag, tag->pos + base, callback_data);
721 id = swf_GetU16(tag);
723 if(flags & 4) { // hascolor
724 if(num==1) swf_GetRGB(tag, NULL);
725 else swf_GetRGBA(tag, NULL);
727 if(flags & 2) { //has x offset
728 swf_ResetReadBits(tag);
731 if(flags & 1) { //has y offset
732 swf_ResetReadBits(tag);
735 if(flags & 8) { //has height
736 swf_ResetReadBits(tag);
740 flags = swf_GetBits(tag, 8);
742 swf_ResetReadBits(tag);
743 for(t=0;t<flags;t++) {
744 swf_GetBits(tag, glyphbits);
745 swf_GetBits(tag, advancebits);
750 case ST_DEFINEFONTALIGNZONES:
751 case ST_DEFINESCALINGGRID:
753 case ST_CSMTEXTSETTINGS:
754 case ST_DEFINEFONTINFO:
755 case ST_DEFINEFONTINFO2:
757 callback(tag, tag->pos + base, callback_data);
759 case ST_DEFINEVIDEOSTREAM:
762 case ST_DOINITACTION:
763 callback(tag, tag->pos + base, callback_data);
766 case ST_DEFINEMORPHSHAPE2:
767 case ST_DEFINESHAPE4:
769 case ST_DEFINEMORPHSHAPE:
770 case ST_DEFINESHAPE3:
772 case ST_DEFINESHAPE2:
774 case ST_DEFINESHAPE: {
780 if(tag->id == ST_DEFINEMORPHSHAPE || tag->id==ST_DEFINEMORPHSHAPE2) {
785 id = swf_GetU16(tag); // id;
786 SRECT r={0,0,0,0},r2={0,0,0,0};
787 swf_GetRect(tag, &r); // shape bounds
789 swf_ResetReadBits(tag);
790 swf_GetRect(tag, NULL); // shape bounds2
792 swf_ResetReadBits(tag);
793 swf_GetRect(tag, NULL); // edge bounds1
797 swf_ResetReadBits(tag);
798 swf_GetRect(tag, &r2); // edge bounds
799 U8 flags = swf_GetU8(tag); // flags, &1: contains scaling stroke, &2: contains non-scaling stroke
800 DEBUG_ENUMERATE printf("flags: %02x (1=scaling strokes, 2=non-scaling strokes)\n", flags);
803 swf_GetU32(tag); //offset to endedges
806 DEBUG_ENUMERATE printf("Tag:%d Name:%s ID:%d\n", tag->id, swf_TagGetName(tag), id);
807 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);
808 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);
810 DEBUG_ENUMERATE printf("style tag pos: %d\n", tag->pos);
811 enumerateUsedIDs_styles(tag, callback, callback_data, num, morph);
812 DEBUG_ENUMERATE printf("-------\n");
813 swf_ResetReadBits(tag);
814 while(--numshapes>=0) /* morph shapes define two shapes */
816 DEBUG_ENUMERATE printf("shape:%d\n", numshapes);
817 fillbits = swf_GetBits(tag, 4);
818 linebits = swf_GetBits(tag, 4);
819 DEBUG_ENUMERATE printf("fillbits=%d linebits=%d\n", fillbits, linebits);
820 swf_ResetReadBits(tag);
823 flags = swf_GetBits(tag, 1);
824 if(!flags) { //style change
825 flags = swf_GetBits(tag, 5);
829 int n = swf_GetBits(tag, 5);
831 x = swf_GetBits(tag, n); //x
832 y = swf_GetBits(tag, n); //y
833 DEBUG_ENUMERATE printf("move %f %f\n",x/20.0,y/20.0);
835 if(flags&2) { //fill0
837 fill0 = swf_GetBits(tag, fillbits);
838 DEBUG_ENUMERATE printf("fill0 %d\n", fill0);
840 if(flags&4) { //fill1
842 fill1 = swf_GetBits(tag, fillbits);
843 DEBUG_ENUMERATE printf("fill1 %d\n", fill1);
845 if(flags&8) { //linestyle
847 line = swf_GetBits(tag, linebits);
848 DEBUG_ENUMERATE printf("linestyle %d\n",line);
851 DEBUG_ENUMERATE printf("more fillstyles\n");
852 enumerateUsedIDs_styles(tag, callback, callback_data, num, 0);
853 fillbits = swf_GetBits(tag, 4);
854 linebits = swf_GetBits(tag, 4);
857 flags = swf_GetBits(tag, 1);
858 if(flags) { //straight edge
859 int n = swf_GetBits(tag, 4) + 2;
860 if(swf_GetBits(tag, 1)) { //line flag
862 x = swf_GetSBits(tag, n); //delta x
863 y = swf_GetSBits(tag, n); //delta y
864 DEBUG_ENUMERATE printf("line %f %f\n",x/20.0,y/20.0);
866 int v=swf_GetBits(tag, 1);
868 d = swf_GetSBits(tag, n); //vert/horz
869 DEBUG_ENUMERATE printf("%s %f\n",v?"vertical":"horizontal", d/20.0);
871 } else { //curved edge
872 int n = swf_GetBits(tag, 4) + 2;
874 x1 = swf_GetSBits(tag, n);
875 y1 = swf_GetSBits(tag, n);
876 x2 = swf_GetSBits(tag, n);
877 y2 = swf_GetSBits(tag, n);
878 DEBUG_ENUMERATE printf("curve %f %f %f %f\n", x1/20.0, y1/20.0, x2/20.0, y2/20.0);
890 void callbackCount(TAG * t,int pos, void*ptr)
893 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
896 void callbackFillin(TAG * t,int pos, void*ptr)
900 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
903 int swf_GetNumUsedIDs(TAG * t)
906 enumerateUsedIDs(t, 0, callbackCount, &num);
910 void swf_GetUsedIDs(TAG * t, int * positions)
912 int * ptr = positions;
913 enumerateUsedIDs(t, 0, callbackFillin, &ptr);
916 void swf_Relocate (SWF*swf, char*bitmap)
920 memset(slaveids, -1, sizeof(slaveids));
928 if(swf_isDefiningTag(tag))
933 id = swf_GetDefineID(tag); //own id
935 if(!bitmap[id]) { //free
940 for (t=1;t<65536;t++)
950 slaveids[id] = newid;
952 swf_SetDefineID(tag, newid);
955 num = swf_GetNumUsedIDs(tag);
957 ptr = rfx_alloc(sizeof(int)*num);
958 swf_GetUsedIDs(tag, ptr);
961 int id = GET16(&tag->data[ptr[t]]);
963 fprintf(stderr, "swf_Relocate: Mapping id (%d) never encountered before in %s\n", id,
964 swf_TagGetName(tag));
967 PUT16(&tag->data[ptr[t]], id);
976 void swf_Relocate2(SWF*swf, int*id2id)
981 if(swf_isDefiningTag(tag)) {
982 int id = swf_GetDefineID(tag);
985 swf_SetDefineID(tag, id);
988 int num = swf_GetNumUsedIDs(tag);
992 ptr = rfx_alloc(sizeof(int)*num);
993 swf_GetUsedIDs(tag, ptr);
995 int id = GET16(&tag->data[ptr[t]]);
998 PUT16(&tag->data[ptr[t]], id);
1005 void swf_RelocateDepth(SWF*swf, char*bitmap)
1009 tag = swf->firstTag;
1010 for(nr=65535;nr>=0;nr--) {
1014 // now nr is the highest used depth. So we start
1015 // assigning depths at nr+1
1021 /* TODO * clip depths
1024 if(tag->id == ST_PLACEOBJECT2) {
1026 swf_GetPlaceObject(tag, &obj);
1028 int newdepth = obj.clipdepth+nr;
1029 if(newdepth>65535) {
1030 fprintf(stderr, "Couldn't relocate depths: too large values\n");
1033 obj.clipdepth = newdepth;
1034 swf_ResetTag(tag, ST_PLACEOBJECT2);
1035 swf_SetPlaceObject(tag, &obj);
1037 swf_PlaceObjectFree(&obj);
1040 depth = swf_GetDepth(tag);
1042 int newdepth = depth+nr;
1043 if(newdepth>65535) {
1044 fprintf(stderr, "Couldn't relocate depths: too large values\n");
1047 swf_SetDepth(tag, newdepth);
1053 U8 swf_isShapeTag(TAG*tag)
1055 if(tag->id == ST_DEFINESHAPE ||
1056 tag->id == ST_DEFINESHAPE2 ||
1057 tag->id == ST_DEFINESHAPE3 ||
1058 tag->id == ST_DEFINESHAPE4)
1063 U8 swf_isPlaceTag(TAG*tag)
1065 if(tag->id == ST_PLACEOBJECT ||
1066 tag->id == ST_PLACEOBJECT2 ||
1067 tag->id == ST_PLACEOBJECT3)
1071 U8 swf_isTextTag(TAG*tag)
1073 if(tag->id == ST_DEFINETEXT ||
1074 tag->id == ST_DEFINETEXT2)
1079 U8 swf_isFontTag(TAG*tag)
1081 if(tag->id == ST_DEFINEFONT ||
1082 tag->id == ST_DEFINEFONT2 ||
1083 tag->id == ST_DEFINEFONTINFO)
1088 U8 swf_isImageTag(TAG*tag)
1090 if(tag->id == ST_DEFINEBITSJPEG ||
1091 tag->id == ST_DEFINEBITSJPEG2 ||
1092 tag->id == ST_DEFINEBITSJPEG3 ||
1093 tag->id == ST_DEFINEBITSLOSSLESS ||
1094 tag->id == ST_DEFINEBITSLOSSLESS2)
1099 TAG* swf_Concatenate (TAG*list1,TAG*list2)
1101 TAG*tag=0,*lasttag=0;
1103 char depthmap[65536];
1105 memset(bitmap, 0, sizeof(bitmap));
1106 memset(depthmap, 0, sizeof(depthmap));
1107 memset(&swf1, 0, sizeof(swf1));
1108 memset(&swf2, 0, sizeof(swf2));
1110 swf1.firstTag = list1;
1112 swf2.firstTag = list2;
1117 if(!swf_isDefiningTag(tag)) {
1118 int id = swf_GetDefineID(tag);
1121 if(tag->id == ST_PLACEOBJECT ||
1122 tag->id == ST_PLACEOBJECT2) {
1123 int depth = swf_GetDepth(tag);
1124 depthmap[depth] = 1;
1126 if(tag->id == ST_REMOVEOBJECT ||
1127 tag->id == ST_REMOVEOBJECT2) {
1128 int depth = swf_GetDepth(tag);
1129 depthmap[depth] = 0;
1134 swf_Relocate(&swf2, bitmap);
1135 swf_RelocateDepth(&swf2, depthmap);
1136 lasttag->next = swf2.firstTag;
1137 swf2.firstTag->prev = lasttag;
1139 return swf1.firstTag;
1142 static int tagHash(TAG*tag)
1145 unsigned int a = 0x6b973e5a;
1146 /* start at pos 2, as 0 and 1 are the id */
1147 for(t=2;t<tag->len;t++) {
1150 a += tag->data[t]*0xefbc35a5*b*(t+1);
1152 return a&0x7fffffff; //always return positive number
1155 void swf_Optimize(SWF*swf)
1157 const int hash_size = 131072;
1158 char* dontremap = rfx_calloc(sizeof(char)*65536);
1159 U16* remap = rfx_alloc(sizeof(U16)*65536);
1160 TAG* id2tag = rfx_calloc(sizeof(TAG*)*65536);
1161 TAG** hashmap = rfx_calloc(sizeof(TAG*)*hash_size);
1164 for(t=0;t<65536;t++) {
1170 tag = swf->firstTag;
1172 /* make sure we don't remap to this tag,
1173 as it might have different "helper tags"
1174 FIXME: a better way would be to compare
1175 the helper tags, too.
1177 if(swf_isPseudoDefiningTag(tag) &&
1178 tag->id != ST_NAMECHARACTER) {
1179 dontremap[swf_GetDefineID(tag)] = 1;
1183 tag = swf->firstTag;
1185 TAG*next = tag->next;
1188 int num = swf_GetNumUsedIDs(tag);
1189 int*positions = rfx_alloc(sizeof(int)*num);
1191 swf_GetUsedIDs(tag, positions);
1192 for(t=0;t<num;t++) {
1193 int id = GET16(&tag->data[positions[t]]);
1195 PUT16(&tag->data[positions[t]], id);
1197 rfx_free(positions);
1199 /* now look for previous tags with the same
1201 if(swf_isDefiningTag(tag)) {
1203 int id = swf_GetDefineID(tag);
1204 int hash = tagHash(tag);
1207 while((tag2 = hashmap[hash%hash_size])) {
1208 if(tag2 != (TAG*)0 && tag->len == tag2->len) {
1209 if(memcmp(&tag->data[2],&tag2->data[2],tag->len-2) == 0) {
1217 while(hashmap[hash%hash_size]) hash++;
1218 hashmap[hash%hash_size] = tag;
1220 /* we found two identical tags- remap one
1222 remap[id] = swf_GetDefineID(tag2);
1224 if(tag == swf->firstTag)
1225 swf->firstTag = next;
1227 } else if(swf_isPseudoDefiningTag(tag)) {
1228 int id = swf_GetDefineID(tag);
1230 /* if this tag was remapped, we don't
1231 need the helper tag anymore. Discard
1234 if(tag == swf->firstTag)
1235 swf->firstTag = next;
1242 rfx_free(dontremap);
1248 void swf_SetDefineBBox(TAG * tag, SRECT newbbox)
1252 swf_SetTagPos(tag,0);
1254 switch (swf_GetTagID(tag))
1256 case ST_DEFINESHAPE:
1257 case ST_DEFINESHAPE2:
1258 case ST_DEFINESHAPE3:
1259 case ST_DEFINEEDITTEXT:
1261 case ST_DEFINETEXT2:
1262 case ST_DEFINEVIDEOSTREAM: {
1263 U32 after_bbox_offset = 0, len;
1265 id = swf_GetU16(tag);
1266 swf_GetRect(tag, &b1);
1267 swf_ResetReadBits(tag);
1268 after_bbox_offset = tag->pos;
1269 len = tag->len - after_bbox_offset;
1271 memcpy(data, &tag->data[after_bbox_offset], len);
1274 swf_SetRect(tag, &newbbox);
1275 swf_SetBlock(tag, data, len);
1277 tag->pos = tag->readBit = 0;
1281 fprintf(stderr, "rfxswf: Tag %d (%s) has no bbox\n", tag->id, swf_TagGetName(tag));
1285 RGBA swf_GetSWFBackgroundColor(SWF*swf)
1287 TAG*t=swf->firstTag;
1289 color.r = color.b = color.g = 0;
1292 if(t->id == ST_SETBACKGROUNDCOLOR) {
1293 swf_SetTagPos(t, 0);
1294 color.r = swf_GetU8(t);
1295 color.g = swf_GetU8(t);
1296 color.b = swf_GetU8(t);