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_DEFINEMORPHSHAPE2:
104 case ST_DEFINEEDITTEXT:
106 case ST_DEFINEBITSJPEG2:
107 case ST_DEFINEBITSJPEG3:
108 case ST_DEFINEBITSLOSSLESS:
109 case ST_DEFINEBITSLOSSLESS2:
110 case ST_DEFINESCALINGGRID: //pseudodefine
111 case ST_DEFINEBUTTON:
112 case ST_DEFINEBUTTON2:
113 case ST_DEFINEBUTTONCXFORM: //pseudodefine
114 case ST_DEFINEBUTTONSOUND: //pseudodefine
115 case ST_CSMTEXTSETTINGS: //pseudodefine
119 case ST_DEFINEFONTINFO: //pseudodefine
120 case ST_DEFINEFONTINFO2: //pseudodefine
121 case ST_DEFINEFONTALIGNZONES: //pseudodefine
122 case ST_DEFINEFONTNAME: //pseudodefine
126 case ST_DEFINESPRITE:
128 case ST_DEFINEVIDEOSTREAM:
129 case ST_GLYPHNAMES: //pseudodefine
130 case ST_VIDEOFRAME: //pseudodefine
131 case ST_NAMECHARACTER: //pseudodefine
132 case ST_DOINITACTION: //pseudodefine
136 fprintf(stderr, "rfxswf: Error: tag %d (%s) has no id\n", t->id, swf_TagGetName(t));
139 swf_SetTagPos(t,oldTagPos);
144 SRECT swf_GetDefineBBox(TAG * t)
149 memset(&b1, 0, sizeof(b1));
151 oldTagPos = swf_GetTagPos(t);
156 switch (swf_GetTagID(t))
157 { case ST_DEFINESHAPE:
158 case ST_DEFINESHAPE2:
159 case ST_DEFINESHAPE3:
160 case ST_DEFINESHAPE4:
161 case ST_DEFINEEDITTEXT:
164 case ST_DEFINEVIDEOSTREAM:
168 case ST_DEFINEMORPHSHAPE:
172 swf_ExpandRect2(&b1, &b2);
174 case ST_DEFINEBITSLOSSLESS:
175 case ST_DEFINEBITSLOSSLESS2:
177 case ST_DEFINEBITSJPEG2:
178 case ST_DEFINEBITSJPEG3:
183 swf_SetTagPos(t,oldTagPos);
188 U16 swf_GetPlaceID(TAG * t)
193 oldTagPos = swf_GetTagPos(t);
196 switch (swf_GetTagID(t))
197 { case ST_PLACEOBJECT:
198 case ST_REMOVEOBJECT:
199 case ST_FREECHARACTER:
204 case ST_PLACEOBJECT2:
205 { U8 flags = swf_GetU8(t);
206 U16 d = swf_GetU16(t);
207 id = (flags&PF_CHAR)?swf_GetU16(t):id;
209 case ST_PLACEOBJECT3:
210 { U8 flags = swf_GetU8(t);
211 U8 flags2 = swf_GetU8(t);
212 U16 d = swf_GetU16(t);
213 id = (flags&PF_CHAR)?swf_GetU16(t):id;
218 swf_SetTagPos(t,oldTagPos);
223 static int swf_definingtagids[] =
229 ST_DEFINEMORPHSHAPE2,
239 ST_DEFINEBITSLOSSLESS,
240 ST_DEFINEBITSLOSSLESS2,
246 ST_DEFINEVIDEOSTREAM,
251 // tags which may be used inside a sprite definition
252 static int swf_spritetagids[] =
270 /* tags which add content or information to a character with a given ID */
271 static int swf_pseudodefiningtagids[] =
275 ST_DEFINEFONTALIGNZONES,
277 ST_DEFINEBUTTONCXFORM,
278 ST_DEFINEBUTTONSOUND,
279 ST_DEFINESCALINGGRID,
288 U8 swf_isAllowedSpriteTag(TAG * tag)
292 while(swf_spritetagids[t]>=0)
294 if(swf_spritetagids[t] == id)
301 U8 swf_isDefiningTag(TAG * tag)
305 while(swf_definingtagids[t]>=0)
307 if(swf_definingtagids[t] == id)
314 U8 swf_isPseudoDefiningTag(TAG * tag)
318 while(swf_pseudodefiningtagids[t]>=0)
320 if(swf_pseudodefiningtagids[t] == id)
327 int swf_GetDepth(TAG * t)
331 oldTagPos = swf_GetTagPos(t);
334 switch (swf_GetTagID(t))
335 { case ST_PLACEOBJECT:
336 case ST_REMOVEOBJECT:
338 depth = swf_GetU16(t);
340 case ST_REMOVEOBJECT2:
341 depth = swf_GetU16(t);
343 case ST_PLACEOBJECT2:
344 { U8 flags = swf_GetU8(t);
345 depth = swf_GetU16(t);
347 case ST_PLACEOBJECT3:
348 { U8 flags = swf_GetU8(t);
349 U8 flags2 = swf_GetU8(t);
350 depth = swf_GetU16(t);
354 depth = swf_GetU16(t);
357 swf_SetTagPos(t,oldTagPos);
361 void swf_SetDepth(TAG * t, U16 depth)
363 switch (swf_GetTagID(t))
364 { case ST_PLACEOBJECT:
365 case ST_REMOVEOBJECT:
366 PUT16(t->data, depth);
368 case ST_REMOVEOBJECT2:
369 PUT16(t->data, depth);
371 case ST_PLACEOBJECT2:
372 PUT16(&t->data[1], depth);
375 PUT16(t->data, depth);
378 fprintf(stderr, "rfxswf: Error: tag %d has no depth\n", t->id);
382 char* swf_GetName(TAG * t)
388 oldTagPos = swf_GetTagPos(t);
390 switch(swf_GetTagID(t))
393 name = (char*)&t->data[swf_GetTagPos(t)];
395 case ST_PLACEOBJECT3:
396 case ST_PLACEOBJECT2: {
397 U8 flags = swf_GetU8(t);
398 if(t->id == ST_PLACEOBJECT3)
400 swf_GetU16(t); //depth;
404 swf_GetMatrix(t, &m);
406 swf_GetCXForm(t, &c, 1);
409 if(flags&PF_CLIPDEPTH)
412 swf_ResetReadBits(t);
413 name = (char*)&t->data[swf_GetTagPos(t)];
418 swf_SetTagPos(t,oldTagPos);
422 /* used in enumerateUsedIDs */
423 void swf_GetMorphGradient(TAG * tag, GRADIENT * gradient1, GRADIENT * gradient2)
426 int num = swf_GetU8(tag) & 15;
427 if(gradient1) gradient1->num = num;
428 if(gradient2) gradient2->num = num;
431 gradient1->num = num;
432 gradient1->rgba = (RGBA*)rfx_calloc(sizeof(RGBA)*gradient1->num);
433 gradient1->ratios = (U8*)rfx_calloc(sizeof(gradient1->ratios[0])*gradient1->num);
436 gradient2->num = num;
437 gradient2->rgba = (RGBA*)rfx_calloc(sizeof(RGBA)*gradient2->num);
438 gradient2->ratios = (U8*)rfx_calloc(sizeof(gradient2->ratios[0])*gradient2->num);
445 ratio = swf_GetU8(tag);
446 swf_GetRGBA(tag, &color);
448 gradient1->ratios[t] = ratio;
449 gradient1->rgba[t] = color;
452 ratio = swf_GetU8(tag);
453 swf_GetRGBA(tag, &color);
455 gradient2->ratios[t] = ratio;
456 gradient2->rgba[t] = color;
461 #define DEBUG_ENUMERATE if(0)
462 //#define DEBUG_ENUMERATE
464 void enumerateUsedIDs_styles(TAG * tag, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph)
468 count = swf_GetU8(tag);
469 if(count == 0xff && num>1) // defineshape2,3,4 only
470 count = swf_GetU16(tag);
472 DEBUG_ENUMERATE printf("%d fill styles\n", count);
476 type = swf_GetU8(tag); //type
477 DEBUG_ENUMERATE printf("fill style %d) %02x (tagpos=%d)\n", t, type, tag->pos);
480 {swf_GetRGBA(tag, NULL);if(morph) swf_GetRGBA(tag, NULL);}
482 {swf_GetRGB(tag, NULL);if(morph) swf_GetRGB(tag, NULL);}
484 else if(type == 0x10 || type == 0x12 || type == 0x13)
486 swf_ResetReadBits(tag);
488 swf_GetMatrix(tag, &m);
489 DEBUG_ENUMERATE swf_DumpMatrix(stdout, &m);
491 swf_GetMatrix(tag, NULL);
492 swf_ResetReadBits(tag);
494 swf_GetMorphGradient(tag, NULL, NULL);
497 swf_GetGradient(tag, &g, /*alpha*/ num>=3?1:0);
498 DEBUG_ENUMERATE swf_DumpGradient(stdout, &g);
503 else if(type == 0x40 || type == 0x41 || type == 0x42 || type == 0x43)
505 swf_ResetReadBits(tag);
506 if(tag->data[tag->pos] != 0xff ||
507 tag->data[tag->pos+1] != 0xff)
508 (callback)(tag, tag->pos, callback_data);
511 swf_ResetReadBits(tag);
512 swf_GetMatrix(tag, NULL);
514 swf_GetMatrix(tag, NULL);
517 fprintf(stderr, "rfxswf:swftools.c Unknown fillstyle:0x%02x in tag %02x\n",type, tag->id);
520 swf_ResetReadBits(tag);
521 count = swf_GetU8(tag); // line style array
523 count = swf_GetU16(tag);
524 DEBUG_ENUMERATE printf("%d line styles\n", count);
529 width = swf_GetU16(tag);
533 U16 flags = swf_GetU16(tag);
535 swf_GetU16(tag); // miter limit
537 fprintf(stderr, "Filled strokes parsing not yet supported\n");
541 {swf_GetRGBA(tag, &color);if(morph) swf_GetRGBA(tag, NULL);}
543 {swf_GetRGB(tag, &color);if(morph) swf_GetRGB(tag, NULL);}
544 DEBUG_ENUMERATE printf("line style %d: %02x%02x%02x%02x \n", t, color.r,color.g,color.b,color.a);
548 void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), void*callback_data)
551 swf_ResetReadBits(tag);
555 case ST_DEFINEBUTTONSOUND: {
557 callback(tag, tag->pos + base, callback_data);
560 callback(tag, tag->pos + base, callback_data);
561 swf_GetU16(tag); //sound id
562 flags = swf_GetU8(tag);
564 swf_GetU32(tag); // in point
566 swf_GetU32(tag); // out points
568 swf_GetU16(tag); // loop count
571 int npoints = swf_GetU8(tag);
573 for(s=0;s<npoints;s++)
582 case ST_DEFINEBUTTONCXFORM:
583 callback(tag, tag->pos + base, callback_data); //button id
586 case ST_EXPORTASSETS: {
587 int num = swf_GetU16(tag);
590 callback(tag, tag->pos + base, callback_data); //button id
591 swf_GetU16(tag); //id
592 while(swf_GetU8(tag)); //name
596 case ST_IMPORTASSETS:
597 case ST_IMPORTASSETS2: {
598 swf_GetString(tag); //count
599 swf_GetU8(tag); //reserved
600 swf_GetU8(tag); //reserved
601 int num = swf_GetU16(tag); //url
604 callback(tag, tag->pos + base, callback_data); //button id
605 swf_GetU16(tag); //id
606 while(swf_GetU8(tag)); //name
610 case ST_FREECHARACTER: /* unusual tags, which all start with an ID */
611 case ST_NAMECHARACTER:
612 case ST_DEFINEBINARY:
613 case ST_DEFINEFONTNAME:
614 case ST_GENERATORTEXT:
615 callback(tag, tag->pos + base, callback_data);
618 callback(tag, tag->pos + base, callback_data);
620 case ST_PLACEOBJECT2:
621 // only if placeflaghascharacter
622 if(!(tag->data[0]&2))
624 callback(tag, 3 + base, callback_data);
626 case ST_PLACEOBJECT3:
627 // only if placeflaghascharacter
628 if(!(tag->data[0]&2))
630 callback(tag, 4 + base, callback_data);
632 case ST_REMOVEOBJECT:
633 callback(tag, tag->pos + base, callback_data);
636 callback(tag, tag->pos + base, callback_data);
638 case ST_DEFINESPRITE: {
640 break; // sprite is expanded
642 swf_GetU16(tag); // id
643 swf_GetU16(tag); // framenum
646 U16 flags = swf_GetU16(tag);
649 TAG *tag2 = swf_InsertTag(NULL, id);
652 len = swf_GetU32(tag);
655 tag2->len = tag2->memsize = len;
656 tag2->data = (U8*)rfx_alloc(len);
657 memcpy(tag2->data, &tag->data[tag->pos], len);
658 /* I never saw recursive sprites, but they are (theoretically)
659 possible, so better add base here again */
660 enumerateUsedIDs(tag2, tag->pos + base, callback, callback_data);
662 swf_GetBlock(tag, NULL, len);
666 case ST_DEFINEBUTTON2: // has some font ids in the button records
669 case ST_DEFINEBUTTON: {
670 swf_GetU16(tag); //button id
674 swf_GetU8(tag); //flag
675 offset = swf_GetU16(tag); //offset
679 if(!swf_GetU8(tag)) //flags
681 callback(tag, tag->pos + base, callback_data);
682 swf_GetU16(tag); //char
683 swf_GetU16(tag); //layer
684 swf_ResetReadBits(tag);
685 swf_GetMatrix(tag, NULL);
687 swf_ResetReadBits(tag);
688 swf_GetCXForm(tag, NULL, 1);
694 case ST_DEFINEEDITTEXT: {
696 swf_GetU16(tag); //id
697 swf_GetRect(tag, NULL); //bounding box
698 swf_ResetReadBits(tag);
699 flags1 = swf_GetU8(tag);
700 flags2 = swf_GetU8(tag);
702 callback(tag, tag->pos + base, callback_data);
707 case ST_DEFINETEXT: {
708 int glyphbits, advancebits;
710 id = swf_GetU16(tag); //id
711 swf_GetRect(tag, NULL); //bounding box
712 swf_ResetReadBits(tag);
713 swf_GetMatrix(tag, NULL); //matrix
714 swf_ResetReadBits(tag);
715 glyphbits = swf_GetU8(tag); //glyphbits
716 advancebits = swf_GetU8(tag); //advancebits
720 swf_ResetReadBits(tag);
721 flags = swf_GetBits(tag, 8);
724 swf_ResetReadBits(tag);
725 if(flags & 8) { // hasfont
726 callback(tag, tag->pos + base, callback_data);
727 id = swf_GetU16(tag);
729 if(flags & 4) { // hascolor
730 if(num==1) swf_GetRGB(tag, NULL);
731 else swf_GetRGBA(tag, NULL);
733 if(flags & 2) { //has x offset
734 swf_ResetReadBits(tag);
737 if(flags & 1) { //has y offset
738 swf_ResetReadBits(tag);
741 if(flags & 8) { //has height
742 swf_ResetReadBits(tag);
746 flags = swf_GetBits(tag, 8);
748 swf_ResetReadBits(tag);
749 for(t=0;t<flags;t++) {
750 swf_GetBits(tag, glyphbits);
751 swf_GetBits(tag, advancebits);
756 case ST_DEFINEFONTALIGNZONES:
757 case ST_DEFINESCALINGGRID:
759 case ST_CSMTEXTSETTINGS:
760 case ST_DEFINEFONTINFO:
761 case ST_DEFINEFONTINFO2:
763 callback(tag, tag->pos + base, callback_data);
765 case ST_DEFINEVIDEOSTREAM:
768 case ST_DOINITACTION:
769 callback(tag, tag->pos + base, callback_data);
772 case ST_DEFINEMORPHSHAPE2:
773 case ST_DEFINESHAPE4:
775 case ST_DEFINEMORPHSHAPE:
776 case ST_DEFINESHAPE3:
778 case ST_DEFINESHAPE2:
780 case ST_DEFINESHAPE: {
786 if(tag->id == ST_DEFINEMORPHSHAPE || tag->id==ST_DEFINEMORPHSHAPE2) {
791 id = swf_GetU16(tag); // id;
792 SRECT r={0,0,0,0},r2={0,0,0,0};
793 swf_GetRect(tag, &r); // shape bounds
795 swf_ResetReadBits(tag);
796 swf_GetRect(tag, NULL); // shape bounds2
798 swf_ResetReadBits(tag);
799 swf_GetRect(tag, NULL); // edge bounds1
803 swf_ResetReadBits(tag);
804 swf_GetRect(tag, &r2); // edge bounds
805 U8 flags = swf_GetU8(tag); // flags, &1: contains scaling stroke, &2: contains non-scaling stroke
806 DEBUG_ENUMERATE printf("flags: %02x (1=scaling strokes, 2=non-scaling strokes)\n", flags);
809 swf_GetU32(tag); //offset to endedges
812 DEBUG_ENUMERATE printf("Tag:%d Name:%s ID:%d\n", tag->id, swf_TagGetName(tag), id);
813 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);
814 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);
816 DEBUG_ENUMERATE printf("style tag pos: %d\n", tag->pos);
817 enumerateUsedIDs_styles(tag, callback, callback_data, num, morph);
818 DEBUG_ENUMERATE printf("-------\n");
819 swf_ResetReadBits(tag);
820 while(--numshapes>=0) /* morph shapes define two shapes */
822 DEBUG_ENUMERATE printf("shape:%d\n", numshapes);
823 fillbits = swf_GetBits(tag, 4);
824 linebits = swf_GetBits(tag, 4);
825 DEBUG_ENUMERATE printf("fillbits=%d linebits=%d\n", fillbits, linebits);
826 swf_ResetReadBits(tag);
829 flags = swf_GetBits(tag, 1);
830 if(!flags) { //style change
831 flags = swf_GetBits(tag, 5);
835 int n = swf_GetBits(tag, 5);
837 x = swf_GetBits(tag, n); //x
838 y = swf_GetBits(tag, n); //y
839 DEBUG_ENUMERATE printf("move %f %f\n",x/20.0,y/20.0);
841 if(flags&2) { //fill0
843 fill0 = swf_GetBits(tag, fillbits);
844 DEBUG_ENUMERATE printf("fill0 %d\n", fill0);
846 if(flags&4) { //fill1
848 fill1 = swf_GetBits(tag, fillbits);
849 DEBUG_ENUMERATE printf("fill1 %d\n", fill1);
851 if(flags&8) { //linestyle
853 line = swf_GetBits(tag, linebits);
854 DEBUG_ENUMERATE printf("linestyle %d\n",line);
857 DEBUG_ENUMERATE printf("more fillstyles\n");
858 enumerateUsedIDs_styles(tag, callback, callback_data, num, 0);
859 fillbits = swf_GetBits(tag, 4);
860 linebits = swf_GetBits(tag, 4);
863 flags = swf_GetBits(tag, 1);
864 if(flags) { //straight edge
865 int n = swf_GetBits(tag, 4) + 2;
866 if(swf_GetBits(tag, 1)) { //line flag
868 x = swf_GetSBits(tag, n); //delta x
869 y = swf_GetSBits(tag, n); //delta y
870 DEBUG_ENUMERATE printf("line %f %f\n",x/20.0,y/20.0);
872 int v=swf_GetBits(tag, 1);
874 d = swf_GetSBits(tag, n); //vert/horz
875 DEBUG_ENUMERATE printf("%s %f\n",v?"vertical":"horizontal", d/20.0);
877 } else { //curved edge
878 int n = swf_GetBits(tag, 4) + 2;
880 x1 = swf_GetSBits(tag, n);
881 y1 = swf_GetSBits(tag, n);
882 x2 = swf_GetSBits(tag, n);
883 y2 = swf_GetSBits(tag, n);
884 DEBUG_ENUMERATE printf("curve %f %f %f %f\n", x1/20.0, y1/20.0, x2/20.0, y2/20.0);
896 void callbackCount(TAG * t,int pos, void*ptr)
899 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
902 void callbackFillin(TAG * t,int pos, void*ptr)
906 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
909 int swf_GetNumUsedIDs(TAG * t)
912 enumerateUsedIDs(t, 0, callbackCount, &num);
916 void swf_GetUsedIDs(TAG * t, int * positions)
918 int * ptr = positions;
919 enumerateUsedIDs(t, 0, callbackFillin, &ptr);
922 void swf_Relocate (SWF*swf, char*bitmap)
926 memset(slaveids, -1, sizeof(slaveids));
934 if(swf_isDefiningTag(tag))
939 id = swf_GetDefineID(tag); //own id
941 if(!bitmap[id]) { //free
946 for (t=1;t<65536;t++)
956 slaveids[id] = newid;
958 swf_SetDefineID(tag, newid);
961 num = swf_GetNumUsedIDs(tag);
963 ptr = (int*)rfx_alloc(sizeof(int)*num);
964 swf_GetUsedIDs(tag, ptr);
967 int id = GET16(&tag->data[ptr[t]]);
969 fprintf(stderr, "swf_Relocate: Mapping id (%d) never encountered before in %s\n", id,
970 swf_TagGetName(tag));
973 PUT16(&tag->data[ptr[t]], id);
982 void swf_Relocate2(SWF*swf, int*id2id)
987 if(swf_isDefiningTag(tag)) {
988 int id = swf_GetDefineID(tag);
991 swf_SetDefineID(tag, id);
994 int num = swf_GetNumUsedIDs(tag);
998 ptr = (int*)rfx_alloc(sizeof(int)*num);
999 swf_GetUsedIDs(tag, ptr);
1000 for(t=0;t<num;t++) {
1001 int id = GET16(&tag->data[ptr[t]]);
1004 PUT16(&tag->data[ptr[t]], id);
1011 void swf_RelocateDepth(SWF*swf, char*bitmap)
1015 tag = swf->firstTag;
1016 for(nr=65535;nr>=0;nr--) {
1020 // now nr is the highest used depth. So we start
1021 // assigning depths at nr+1
1027 /* TODO * clip depths
1030 if(tag->id == ST_PLACEOBJECT2) {
1032 swf_GetPlaceObject(tag, &obj);
1034 int newdepth = obj.clipdepth+nr;
1035 if(newdepth>65535) {
1036 fprintf(stderr, "Couldn't relocate depths: too large values\n");
1039 obj.clipdepth = newdepth;
1040 swf_ResetTag(tag, ST_PLACEOBJECT2);
1041 swf_SetPlaceObject(tag, &obj);
1043 swf_PlaceObjectFree(&obj);
1046 depth = swf_GetDepth(tag);
1048 int newdepth = depth+nr;
1049 if(newdepth>65535) {
1050 fprintf(stderr, "Couldn't relocate depths: too large values\n");
1053 swf_SetDepth(tag, newdepth);
1059 U8 swf_isShapeTag(TAG*tag)
1061 if(tag->id == ST_DEFINESHAPE ||
1062 tag->id == ST_DEFINESHAPE2 ||
1063 tag->id == ST_DEFINESHAPE3 ||
1064 tag->id == ST_DEFINESHAPE4)
1069 U8 swf_isPlaceTag(TAG*tag)
1071 if(tag->id == ST_PLACEOBJECT ||
1072 tag->id == ST_PLACEOBJECT2 ||
1073 tag->id == ST_PLACEOBJECT3)
1077 U8 swf_isTextTag(TAG*tag)
1079 if(tag->id == ST_DEFINETEXT ||
1080 tag->id == ST_DEFINETEXT2)
1085 U8 swf_isFontTag(TAG*tag)
1087 if(tag->id == ST_DEFINEFONT ||
1088 tag->id == ST_DEFINEFONT2 ||
1089 tag->id == ST_DEFINEFONTINFO)
1094 U8 swf_isImageTag(TAG*tag)
1096 if(tag->id == ST_DEFINEBITSJPEG ||
1097 tag->id == ST_DEFINEBITSJPEG2 ||
1098 tag->id == ST_DEFINEBITSJPEG3 ||
1099 tag->id == ST_DEFINEBITSLOSSLESS ||
1100 tag->id == ST_DEFINEBITSLOSSLESS2)
1105 TAG* swf_Concatenate (TAG*list1,TAG*list2)
1107 TAG*tag=0,*lasttag=0;
1109 char depthmap[65536];
1111 memset(bitmap, 0, sizeof(bitmap));
1112 memset(depthmap, 0, sizeof(depthmap));
1113 memset(&swf1, 0, sizeof(swf1));
1114 memset(&swf2, 0, sizeof(swf2));
1116 swf1.firstTag = list1;
1118 swf2.firstTag = list2;
1123 if(!swf_isDefiningTag(tag)) {
1124 int id = swf_GetDefineID(tag);
1127 if(tag->id == ST_PLACEOBJECT ||
1128 tag->id == ST_PLACEOBJECT2) {
1129 int depth = swf_GetDepth(tag);
1130 depthmap[depth] = 1;
1132 if(tag->id == ST_REMOVEOBJECT ||
1133 tag->id == ST_REMOVEOBJECT2) {
1134 int depth = swf_GetDepth(tag);
1135 depthmap[depth] = 0;
1140 swf_Relocate(&swf2, bitmap);
1141 swf_RelocateDepth(&swf2, depthmap);
1142 lasttag->next = swf2.firstTag;
1143 swf2.firstTag->prev = lasttag;
1145 return swf1.firstTag;
1148 static int tagHash(TAG*tag)
1151 unsigned int a = 0x6b973e5a;
1152 /* start at pos 2, as 0 and 1 are the id */
1153 for(t=2;t<tag->len;t++) {
1156 a += tag->data[t]*0xefbc35a5*b*(t+1);
1158 return a&0x7fffffff; //always return positive number
1161 void swf_Optimize(SWF*swf)
1163 const int hash_size = 131072;
1164 char* dontremap = (char*)rfx_calloc(sizeof(char)*65536);
1165 U16* remap = (U16*)rfx_alloc(sizeof(U16)*65536);
1166 TAG* id2tag = (TAG*)rfx_calloc(sizeof(TAG*)*65536);
1167 TAG** hashmap = (TAG**)rfx_calloc(sizeof(TAG*)*hash_size);
1170 for(t=0;t<65536;t++) {
1176 tag = swf->firstTag;
1178 /* make sure we don't remap to this tag,
1179 as it might have different "helper tags"
1180 FIXME: a better way would be to compare
1181 the helper tags, too.
1183 if(swf_isPseudoDefiningTag(tag) &&
1184 tag->id != ST_NAMECHARACTER) {
1185 dontremap[swf_GetDefineID(tag)] = 1;
1189 tag = swf->firstTag;
1191 TAG*next = tag->next;
1194 int num = swf_GetNumUsedIDs(tag);
1195 int*positions = (int*)rfx_alloc(sizeof(int)*num);
1197 swf_GetUsedIDs(tag, positions);
1198 for(t=0;t<num;t++) {
1199 int id = GET16(&tag->data[positions[t]]);
1201 PUT16(&tag->data[positions[t]], id);
1203 rfx_free(positions);
1205 /* now look for previous tags with the same
1207 if(swf_isDefiningTag(tag)) {
1209 int id = swf_GetDefineID(tag);
1210 int hash = tagHash(tag);
1213 while((tag2 = hashmap[hash%hash_size])) {
1214 if(tag2 != (TAG*)0 && tag->len == tag2->len) {
1215 if(memcmp(&tag->data[2],&tag2->data[2],tag->len-2) == 0) {
1223 while(hashmap[hash%hash_size]) hash++;
1224 hashmap[hash%hash_size] = tag;
1226 /* we found two identical tags- remap one
1228 remap[id] = swf_GetDefineID(tag2);
1230 if(tag == swf->firstTag)
1231 swf->firstTag = next;
1233 } else if(swf_isPseudoDefiningTag(tag)) {
1234 int id = swf_GetDefineID(tag);
1236 /* if this tag was remapped, we don't
1237 need the helper tag anymore. Discard
1240 if(tag == swf->firstTag)
1241 swf->firstTag = next;
1248 rfx_free(dontremap);
1254 void swf_SetDefineBBox(TAG * tag, SRECT newbbox)
1258 swf_SetTagPos(tag,0);
1260 switch (swf_GetTagID(tag))
1262 case ST_DEFINESHAPE:
1263 case ST_DEFINESHAPE2:
1264 case ST_DEFINESHAPE3:
1265 case ST_DEFINEEDITTEXT:
1267 case ST_DEFINETEXT2:
1268 case ST_DEFINEVIDEOSTREAM: {
1269 U32 after_bbox_offset = 0, len;
1271 id = swf_GetU16(tag);
1272 swf_GetRect(tag, &b1);
1273 swf_ResetReadBits(tag);
1274 after_bbox_offset = tag->pos;
1275 len = tag->len - after_bbox_offset;
1276 data = (U8*)malloc(len);
1277 memcpy(data, &tag->data[after_bbox_offset], len);
1280 swf_SetRect(tag, &newbbox);
1281 swf_SetBlock(tag, data, len);
1283 tag->pos = tag->readBit = 0;
1287 fprintf(stderr, "rfxswf: Tag %d (%s) has no bbox\n", tag->id, swf_TagGetName(tag));
1291 RGBA swf_GetSWFBackgroundColor(SWF*swf)
1293 TAG*t=swf->firstTag;
1295 color.r = color.b = color.g = 0;
1298 if(t->id == ST_SETBACKGROUNDCOLOR) {
1299 swf_SetTagPos(t, 0);
1300 color.r = swf_GetU8(t);
1301 color.g = swf_GetU8(t);
1302 color.b = swf_GetU8(t);