2 Shows the structure of a swf file
4 Part of the swftools package.
6 Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
22 #include "../config.h"
24 #ifdef HAVE_SYS_STAT_H
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
40 #include "../lib/rfxswf.h"
41 #include "../lib/args.h"
43 static char * filename = 0;
45 /* idtab stores the ids which are defined in the file. This allows us
46 to detect errors in the file. (i.e. ids which are defined more than
48 static char idtab[65536];
49 static char * indent = " ";
51 static int placements = 0;
52 static int action = 0;
55 static int showtext = 0;
59 struct options_t options[] =
77 int args_callback_option(char*name,char*val)
79 if(!strcmp(name, "V")) {
80 printf("swfdump - part of %s %s\n", PACKAGE, VERSION);
83 else if(name[0]=='a') {
87 else if(name[0]=='p') {
91 else if(name[0]=='t') {
95 else if(name[0]=='e') {
99 else if(name[0]=='X') {
103 else if(name[0]=='Y') {
107 else if(name[0]=='r') {
111 else if(name[0]=='f') {
115 else if(name[0]=='d') {
119 else if(name[0]=='u') {
123 else if(name[0]=='D') {
124 action = placements = showtext = 1;
128 printf("Unknown option: -%s\n", name);
134 int args_callback_longoption(char*name,char*val)
136 return args_long2shortoption(options, name, val);
138 void args_callback_usage(char*name)
140 printf("Usage: %s [-at] file.swf\n", name);
141 printf("\t-h , --help\t\t Print help and exit\n");
142 printf("\t-D , --full\t\t Show everything. The same as -atMp\n");
143 printf("\t-e , --html\t\t Create html output embedding the file (simple, but useful)\n");
144 printf("\t-X , --width\t\t Prints out a string of the form \"-X width\"\n");
145 printf("\t-Y , --height\t\t Prints out a string of the form \"-Y height\"\n");
146 printf("\t-r , --rate\t\t Prints out a string of the form \"-r rate\"\n");
147 printf("\t-f , --frames\t\t Prints out a string of the form \"-f framenum\"\n");
148 printf("\t-a , --action\t\t Disassemble action tags\n");
149 printf("\t-p , --placements\t Show extra placement information\n");
150 printf("\t-t , --text\t\t Show text data\n");
151 printf("\t-d , --hex\t\t Print hex output of tag data, too\n");
152 printf("\t-u , --used\t\t Show referred IDs for each Tag\n");
153 printf("\t-V , --version\t\t Print program version and exit\n");
155 int args_callback_command(char*name,char*val)
158 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
166 char* testfunc(char*str)
168 printf("%s: %s\n", what, str);
172 void dumpButton2Actions(TAG*tag, char*prefix)
178 oldTagPos = swf_GetTagPos(tag);
180 // scan DefineButton2 Record
182 swf_GetU16(tag); // Character ID
183 swf_GetU8(tag); // Flags;
185 offsetpos = swf_GetTagPos(tag); // first offset
188 while (swf_GetU8(tag)) // state -> parse ButtonRecord
189 { swf_GetU16(tag); // id
190 swf_GetU16(tag); // layer
191 swf_GetMatrix(tag,NULL); // matrix
192 swf_GetCXForm(tag,NULL,1); // cxform
199 if(tag->pos >= tag->len)
202 offsetpos = swf_GetU16(tag);
203 condition = swf_GetU16(tag); // condition
205 actions = swf_ActionGet(tag);
206 printf("%s condition %04x\n", prefix, condition);
207 swf_DumpActions(actions, prefix);
210 swf_SetTagPos(tag,oldTagPos);
214 void dumpButtonActions(TAG*tag, char*prefix)
217 swf_GetU16(tag); // id
218 while (swf_GetU8(tag)) // state -> parse ButtonRecord
219 { swf_GetU16(tag); // id
220 swf_GetU16(tag); // layer
221 swf_GetMatrix(tag,NULL); // matrix
223 actions = swf_ActionGet(tag);
224 swf_DumpActions(actions, prefix);
227 #define ET_HASTEXT 32768
228 #define ET_WORDWRAP 16384
229 #define ET_MULTILINE 8192
230 #define ET_PASSWORD 4096
231 #define ET_READONLY 2048
232 #define ET_HASTEXTCOLOR 1024
233 #define ET_HASMAXLENGTH 512
234 #define ET_HASFONT 256
237 #define ET_HASLAYOUT 32
238 #define ET_NOSELECT 16
242 #define ET_USEOUTLINES 1
248 void textcallback(int*glyphs, int nr, int fontid)
251 printf(" <%2d glyphs in font %2d> ",nr, fontid);
252 for(t=0;t<fontnum;t++)
254 if(fonts[t]->id == fontid) {
264 if(glyphs[t] >= fonts[font]->numchars /*glyph is in range*/
265 || !fonts[font]->glyph2ascii /* font has ascii<->glyph mapping */
268 a = fonts[font]->glyph2ascii[glyphs[t]];
275 printf("\\x%x", (int)a);
280 void handleText(TAG*tag)
283 swf_FontExtract_DefineTextCallback(-1,0,tag,4, textcallback);
286 void handleDefineSound(TAG*tag)
288 U16 id = swf_GetU16(tag);
289 U8 flags = swf_GetU8(tag);
290 int compression = (flags>>4)&3;
291 int rate = (flags>>2)&3;
292 int bits = flags&2?16:8;
293 int stereo = flags&1;
295 if(compression == 0) printf("Raw ");
296 else if(compression == 1) printf("ADPCM ");
297 else if(compression == 2) printf("MP3 ");
299 if(rate == 0) printf("5.5Khz ");
300 if(rate == 1) printf("11Khz ");
301 if(rate == 2) printf("22Khz ");
302 if(rate == 3) printf("44Khz ");
303 printf("%dBit ", bits);
304 if(stereo) printf("stereo");
309 void handleDefineBits(TAG*tag)
315 id = swf_GetU16(tag);
316 mode = swf_GetU8(tag);
317 width = swf_GetU16(tag);
318 height = swf_GetU16(tag);
319 printf(" image %dx%d",width,height);
320 if(mode == 3) printf(" (8 bpp)");
321 else if(mode == 4) printf(" (16 bpp)");
322 else if(mode == 5) printf(" (32 bpp)");
323 else printf(" (? bpp)");
326 void handleEditText(TAG*tag)
331 id = swf_GetU16(tag);
333 //swf_ResetReadBits(tag);
338 flags = swf_GetBits(tag,16);
339 if(flags & ET_HASFONT) {
340 swf_GetU16(tag); //font
341 swf_GetU16(tag); //fontheight
343 if(flags & ET_HASTEXTCOLOR) {
344 swf_GetU8(tag); //rgba
349 if(flags & ET_HASMAXLENGTH) {
350 swf_GetU16(tag); //maxlength
352 if(flags & ET_HASLAYOUT) {
353 swf_GetU8(tag); //align
354 swf_GetU16(tag); //left margin
355 swf_GetU16(tag); //right margin
356 swf_GetU16(tag); //indent
357 swf_GetU16(tag); //leading
359 printf(" variable \"%s\"", &tag->data[tag->pos]);
361 if(flags & (ET_X1 | ET_X2 | ET_X3 | ET_X0))
363 printf(" undefined flags: %d%d%d%d",
370 while(tag->data[tag->pos++]);
371 if(flags & ET_HASTEXT)
372 // printf(" text \"%s\"\n", &tag->data[tag->pos])
375 void printhandlerflags(U16 handlerflags)
377 if(handlerflags&1) printf("[on load]");
378 if(handlerflags&2) printf("[enter frame]");
379 if(handlerflags&4) printf("[unload]");
380 if(handlerflags&8) printf("[mouse move]");
381 if(handlerflags&16) printf("[mouse down]");
382 if(handlerflags&32) printf("[mouse up]");
383 if(handlerflags&64) printf("[key down]");
384 if(handlerflags&128) printf("[key up]");
385 if(handlerflags&256) printf("[data]");
386 if(handlerflags&0xfe00) printf("[???]");
388 void handleVideoStream(TAG*tag, char*prefix)
390 U16 id = swf_GetU16(tag);
391 U16 frames = swf_GetU16(tag);
392 U16 width = swf_GetU16(tag);
393 U16 height = swf_GetU16(tag);
394 U8 flags = swf_GetU8(tag); //5-2(videopacket 01=off 10=on)-1(smoothing 1=on)
395 U8 codec = swf_GetU8(tag);
396 printf(" (%d frames, %dx%d", frames, width, height);
400 printf(" sorenson h.263)");
402 printf(" codec 0x%02x)", codec);
404 void handleVideoFrame(TAG*tag, char*prefix)
406 U32 code, version, reference, sizeflags;
409 U16 id = swf_GetU16(tag);
410 U16 frame = swf_GetU16(tag);
411 U8 deblock,flags, tmp, bit;
413 char*types[] = {"I-frame", "P-frame", "disposable P-frame", "<reserved>"};
414 printf(" (frame %d) ", frame);
416 /* video packet follows */
417 code = swf_GetBits(tag, 17);
418 version = swf_GetBits(tag, 5);
419 reference = swf_GetBits(tag, 8);
421 sizeflags = swf_GetBits(tag, 3);
424 case 0: width = swf_GetBits(tag, 8); height = swf_GetBits(tag, 8); break;
425 case 1: width = swf_GetBits(tag, 16); height = swf_GetBits(tag, 16); break;
426 case 2: width = 352; height = 288; break;
427 case 3: width = 176; height = 144; break;
428 case 4: width = 128; height = 96; break;
429 case 5: width = 320; height = 240; break;
430 case 6: width = 160; height = 120; break;
431 case 7: width = -1; height = -1;/*reserved*/ break;
433 printf("%dx%d ", width, height);
434 type = swf_GetBits(tag, 2);
435 printf("%s", types[type]);
437 deblock = swf_GetBits(tag, 1);
439 printf(" deblock ", deblock);
440 quantizer = swf_GetBits(tag, 5);
441 printf(" quant: %d ", quantizer);
444 void handlePlaceObject2(TAG*tag, char*prefix)
446 U8 flags = swf_GetU8(tag);
450 int ppos[3] = {0,0,0};
451 swf_GetU16(tag); //depth
453 if(flags&2) swf_GetU16(tag); //id
455 swf_GetMatrix(tag,&m);
457 ppos[0] += sprintf(pstr[0], "| Matrix ");
458 ppos[1] += sprintf(pstr[1], "| %5.3f %5.3f %6.2f ", m.sx/65536.0, m.r1/65536.0, m.tx/20.0);
459 ppos[2] += sprintf(pstr[2], "| %5.3f %5.3f %6.2f ", m.r0/65536.0, m.sy/65536.0, m.ty/20.0);
463 swf_GetCXForm(tag, &cx, 1);
465 ppos[0] += sprintf(pstr[0]+ppos[0], "| CXForm r g b a ");
466 ppos[1] += sprintf(pstr[1]+ppos[1], "| mul %4.1f %4.1f %4.1f %4.1f ", cx.r0/256.0, cx.g0/256.0, cx.b0/256.0, cx.a0/256.0);
467 ppos[2] += sprintf(pstr[2]+ppos[2], "| add %4d %4d %4d %4d ", cx.r1, cx.g1, cx.b1, cx.a1);
471 U16 ratio = swf_GetU16(tag); //ratio
473 ppos[0] += sprintf(pstr[0]+ppos[0], "| Ratio ");
474 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", ratio);
475 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
479 U16 clip = swf_GetU16(tag); //clip
481 ppos[0] += sprintf(pstr[0]+ppos[0], "| Clip ");
482 ppos[1] += sprintf(pstr[1]+ppos[1], "| %-5d ", clip);
483 ppos[2] += sprintf(pstr[2]+ppos[2], "| ");
486 if(flags&32) { while(swf_GetU8(tag)); }
487 if(placements && ppos[0]) {
489 printf("%s %s\n", prefix, pstr[0]);
490 printf("%s %s\n", prefix, pstr[1]);
491 printf("%s %s", prefix, pstr[2]);
500 unknown = swf_GetU16(tag);
501 globalflags = swf_GetU16(tag);
503 printf("Unknown parameter field not zero: %04x\n", unknown);
506 printf("global flags: %04x\n", globalflags);
507 handlerflags = swf_GetU16(tag);
509 handlerflags = swf_GetU32(tag);
512 while(handlerflags) {
517 globalflags &= ~handlerflags;
518 printf("%s flags %08x ",prefix, handlerflags);
519 printhandlerflags(handlerflags);
520 length = swf_GetU32(tag);
521 printf(", %d bytes actioncode\n",length);
522 a = swf_ActionGet(tag);
523 swf_DumpActions(a,prefix);
526 handlerflags = is32?swf_GetU32(tag):swf_GetU16(tag);
528 if(globalflags) // should go to sterr.
529 printf("ERROR: unsatisfied handlerflags: %02x\n", globalflags);
531 printf(" has action code\n");
536 void handlePlaceObject(TAG*tag, char*prefix)
541 void fontcallback1(U16 id,U8 * name)
545 void fontcallback2(U16 id,U8 * name)
547 swf_FontExtract(&swf,id,&fonts[fontnum]);
551 void hexdumpTag(TAG*tag, char* prefix)
554 printf(" %s-=> ",prefix);
555 for(t=0;t<tag->len;t++) {
556 printf("%02x ", tag->data[t]);
557 if((t && ((t&15)==15)) || (t==tag->len-1))
562 printf("\n %s-=> ",prefix);
567 void handleExportAssets(TAG*tag, char* prefix)
573 num = swf_GetU16(tag);
576 id = swf_GetU16(tag);
577 name = swf_GetString(tag);
578 printf("%sexports %04d as \"%s\"\n", prefix, id, name);
582 void dumperror(const char* format, ...)
587 va_start(arglist, format);
588 vsprintf(buf, format, arglist);
592 printf("==== Error: %s ====\n", buf);
595 static char strbuf[800];
598 char* timestring(double f)
600 int hours = (int)(f/3600);
601 int minutes = (int)((f-hours*3600)/60);
602 int seconds = (int)((f-hours*3600-minutes*60));
603 int useconds = (int)((f-(int)f)*1000+0.5);
606 sprintf(&strbuf[bufpos], "%02d:%02d:%02d,%03d",hours,minutes,seconds,useconds);
607 return &strbuf[bufpos];
610 int main (int argc,char ** argv)
618 char issprite = 0; // are we inside a sprite definition?
621 char* spriteframelabel = 0;
622 char* framelabel = 0;
626 memset(idtab,0,65536);
628 processargs(argc, argv);
632 fprintf(stderr, "You must supply a filename.\n");
636 f = open(filename,O_RDONLY|O_BINARY);
640 perror("Couldn't open file: ");
643 if FAILED(swf_ReadSWF(f,&swf))
645 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
652 if(statbuf.st_size != swf.fileSize && !swf.compressed)
653 dumperror("Real Filesize (%d) doesn't match header Filesize (%d)",
654 statbuf.st_size, swf.fileSize);
655 filesize = statbuf.st_size;
660 xsize = (swf.movieSize.xmax-swf.movieSize.xmin)/20;
661 ysize = (swf.movieSize.ymax-swf.movieSize.ymin)/20;
665 printf("-X %d", xsize);
671 printf("-Y %d", ysize);
677 printf("-r %d", swf.frameRate*100/256);
683 printf("-f %d", swf.frameCount);
690 char*fileversions[] = {"","1,0,0,0", "2,0,0,0","3,0,0,0","4,0,0,0",
691 "5,0,0,0","6,0,23,0","7,0,0,0","8,0,0,0"};
692 if(swf.fileVersion>8) {
693 fprintf(stderr, "Fileversion>8\n");
696 printf("<OBJECT CLASSID=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n"
698 //" BGCOLOR=#ffffffff\n"?
700 //http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,23,0?
701 " CODEBASE=\"http://active.macromedia.com/flash5/cabs/swflash.cab#version=%s\">\n"
702 " <PARAM NAME=\"MOVIE\" VALUE=\"%s\">\n"
703 " <PARAM NAME=\"PLAY\" VALUE=\"true\">\n"
704 " <PARAM NAME=\"LOOP\" VALUE=\"true\">\n"
705 " <PARAM NAME=\"QUALITY\" VALUE=\"high\">\n"
706 " <EMBED SRC=\"%s\" WIDTH=\"%d\" HEIGHT=\"%d\"\n" //bgcolor=#ffffff?
707 " PLAY=\"true\" ALIGN=\"\" LOOP=\"true\" QUALITY=\"high\"\n"
708 " TYPE=\"application/x-shockwave-flash\"\n"
709 " PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\">\n"
711 "</OBJECT>\n", xsize, ysize, fileversions[swf.fileVersion],
712 filename, filename, xsize, ysize);
715 printf("[HEADER] File version: %d\n", swf.fileVersion);
717 printf("[HEADER] File is zlib compressed.");
718 if(filesize && swf.fileSize)
719 printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
723 printf("[HEADER] File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
724 printf("[HEADER] Frame rate: %f\n",swf.frameRate/256.0);
725 printf("[HEADER] Frame count: %d\n",swf.frameCount);
726 printf("[HEADER] Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
727 if(swf.movieSize.xmin)
728 printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
731 printf("[HEADER] Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
732 if(swf.movieSize.ymin)
733 printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
741 swf_FontEnumerate(&swf,&fontcallback1);
742 fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
744 swf_FontEnumerate(&swf,&fontcallback2);
748 char*name = swf_TagGetName(tag);
751 dumperror("Unknown tag:0x%03x", tag->id);
755 printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
757 if(tag->id == ST_FREECHARACTER) {
758 U16 id = swf_GetU16(tag);
762 if(swf_isDefiningTag(tag)) {
763 U16 id = swf_GetDefineID(tag);
764 printf(" defines id %04d", id);
766 dumperror("Id %04d is defined more than once.", id);
769 else if(swf_isPseudoDefiningTag(tag)) {
770 U16 id = swf_GetDefineID(tag);
771 printf(" adds information to id %04d", id);
773 dumperror("Id %04d is not yet defined.\n", id);
775 else if(tag->id == ST_PLACEOBJECT) {
776 printf(" places id %04d at depth %04x", swf_GetPlaceID(tag), swf_GetDepth(tag));
778 printf(" name \"%s\"",swf_GetName(tag));
779 handlePlaceObject(tag, myprefix);
781 else if(tag->id == ST_PLACEOBJECT2) {
788 printf(" id %04d",swf_GetPlaceID(tag));
792 printf(" at depth %04d", swf_GetDepth(tag));
794 printf(" name \"%s\"",swf_GetName(tag));
796 else if(tag->id == ST_REMOVEOBJECT) {
797 printf(" removes id %04d from depth %04d", swf_GetPlaceID(tag), swf_GetDepth(tag));
799 else if(tag->id == ST_REMOVEOBJECT2) {
800 printf(" removes object from depth %04d", swf_GetDepth(tag));
802 else if(tag->id == ST_FREECHARACTER) {
803 printf(" frees object %04d", swf_GetPlaceID(tag));
805 else if(tag->id == ST_STARTSOUND) {
808 id = swf_GetU16(tag);
809 flags = swf_GetU8(tag);
811 printf(" stops sound with id %04d", id);
813 printf(" starts sound with id %04d", id);
815 printf(" (if not already playing)");
821 printf(" looping %d times", swf_GetU16(tag));
824 else if(tag->id == ST_FRAMELABEL) {
825 int l = strlen(tag->data);
826 printf(" \"%s\"", tag->data);
828 printf(" has %d extra bytes", tag->len-1-l);
829 if(tag ->len-1-l == 1 && tag->data[tag->len-1] == 1)
832 if((framelabel && !issprite) ||
833 (spriteframelabel && issprite)) {
834 dumperror("Frame %d has more than one label",
835 issprite?spriteframe:mainframe);
837 if(issprite) spriteframelabel = tag->data;
838 else framelabel = tag->data;
840 else if(tag->id == ST_SHOWFRAME) {
841 char*label = issprite?spriteframelabel:framelabel;
842 int frame = issprite?spriteframe:mainframe;
845 while(tag->next && tag->next->id == ST_SHOWFRAME && tag->next->len == 0) {
847 if(issprite) spriteframe++;
853 printf(" %d (%s)", frame, timestring(frame*(256.0/(swf.frameRate+0.1))));
855 printf(" %d-%d (%s-%s)", frame, nframe,
856 timestring(frame*(256.0/(swf.frameRate+0.1))),
857 timestring(nframe*(256.0/(swf.frameRate+0.1)))
860 printf(" (label \"%s\")", label);
861 if(issprite) {spriteframe++; spriteframelabel = 0;}
862 if(!issprite) {mainframe++; framelabel = 0;}
865 if(tag->id == ST_SETBACKGROUNDCOLOR) {
866 U8 r = swf_GetU8(tag);
867 U8 g = swf_GetU8(tag);
868 U8 b = swf_GetU8(tag);
869 printf(" (%02x/%02x/%02x)\n",r,g,b);
871 else if(tag->id == ST_DEFINEBITSLOSSLESS ||
872 tag->id == ST_DEFINEBITSLOSSLESS2) {
873 handleDefineBits(tag);
876 else if(tag->id == ST_DEFINESOUND) {
877 handleDefineSound(tag);
880 else if(tag->id == ST_VIDEOFRAME) {
881 handleVideoFrame(tag, myprefix);
884 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
885 handleVideoStream(tag, myprefix);
888 else if(tag->id == ST_DEFINEEDITTEXT) {
892 else if(tag->id == ST_DEFINEMOVIE) {
893 U16 id = swf_GetU16(tag);
894 char*s = swf_GetString(tag);
895 printf(" URL: %s\n", s);
897 else if(tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
903 else if(tag->id == ST_PLACEOBJECT2) {
905 else if(tag->id == ST_NAMECHARACTER) {
907 printf(" \"%s\"\n", swf_GetString(tag));
913 sprintf(myprefix, " %s", prefix);
915 if(tag->id == ST_DEFINESPRITE) {
916 sprintf(prefix, " ");
918 dumperror("Sprite definition inside a sprite definition");
922 spriteframelabel = 0;
924 else if(tag->id == ST_END) {
927 spriteframelabel = 0;
929 dumperror("End Tag not empty");
931 else if(tag->id == ST_EXPORTASSETS) {
932 handleExportAssets(tag, myprefix);
934 else if(tag->id == ST_DOACTION && action) {
936 actions = swf_ActionGet(tag);
937 swf_DumpActions(actions, myprefix);
939 else if(tag->id == ST_DEFINEBUTTON && action) {
940 dumpButtonActions(tag, myprefix);
942 else if(tag->id == ST_DEFINEBUTTON2 && action) {
943 dumpButton2Actions(tag, myprefix);
945 else if(tag->id == ST_PLACEOBJECT2) {
946 handlePlaceObject2(tag, myprefix);
949 if(tag->len && used) {
950 int num = swf_GetNumUsedIDs(tag);
954 used = (int*)malloc(sizeof(int)*num);
955 swf_GetUsedIDs(tag, used);
956 printf("%s%suses IDs: ", indent, prefix);
958 swf_SetTagPos(tag, used[t]);
959 printf("%d%s", swf_GetU16(tag), t<num-1?", ":"");
965 if(tag->len && hex) {
966 hexdumpTag(tag, prefix);