2 Allows to extract parts of the swf into a new 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 */
25 #include "../lib/rfxswf.h"
26 #include "../lib/args.h"
27 #include "../lib/log.h"
31 #define _ZLIB_INCLUDED_
36 char * destfilename = "output.swf";
40 char* extractframes = 0;
41 char* extractjpegids = 0;
42 char* extractfontids = 0;
43 char* extractpngids = 0;
44 char* extractsoundids = 0;
45 char* extractbinaryids = 0;
46 char* extractanyids = 0;
49 char* extractname = 0;
52 char originalplaceobjects = 0;
56 char *outputformat = NULL;
58 struct options_t options[] =
81 int args_callback_option(char*name,char*val)
83 if(!strcmp(name, "V")) {
84 printf("swfextract - part of %s %s\n", PACKAGE, VERSION);
87 else if(!strcmp(name, "o")) {
91 else if(!strcmp(name, "i")) {
95 fprintf(stderr, "You can only supply either name or id\n");
100 else if(!strcmp(name, "n")) {
104 fprintf(stderr, "You can only supply either name or id\n");
109 else if(!strcmp(name, "v")) {
113 else if(!strcmp(name, "m")) {
118 else if(!strcmp(name, "j")) {
120 fprintf(stderr, "Only one --jpegs argument is allowed. (Try to use a range, e.g. -j 1,2,3)\n");
123 /* TODO: count number of IDs in val range */
125 extractjpegids = val;
128 else if(!strcmp(name, "F")) {
130 fprintf(stderr, "Only one --font argument is allowed. (Try to use a range, e.g. -s 1,2,3)\n");
134 extractfontids = val;
137 else if(!strcmp(name, "s")) {
138 if(extractsoundids) {
139 fprintf(stderr, "Only one --sound argument is allowed. (Try to use a range, e.g. -s 1,2,3)\n");
143 extractsoundids = val;
146 else if(!strcmp(name, "b")) {
147 if(extractbinaryids) {
148 fprintf(stderr, "Only one --binary argument is allowed. (Try to use a range, e.g. -s 1,2,3)\n");
152 extractbinaryids = val;
155 #ifdef _ZLIB_INCLUDED_
156 else if(!strcmp(name, "p")) {
158 fprintf(stderr, "Only one --png argument is allowed. (Try to use a range, e.g. -p 1,2,3)\n");
166 else if(!strcmp(name, "a")) {
171 else if(!strcmp(name, "f")) {
176 else if(!strcmp(name, "P")) {
177 originalplaceobjects = 1;
180 else if(!strcmp(name, "0")) {
184 else if(!strcmp(name, "w")) {
188 else if (!strcmp(name, "O")) {
193 printf("Unknown option: -%s\n", name);
199 int args_callback_longoption(char*name,char*val)
201 return args_long2shortoption(options, name, val);
203 void args_callback_usage(char*name)
205 printf("Usage: %s [-v] [-n name] [-ijf ids] file.swf\n", name);
206 printf("\t-v , --verbose\t\t\t Be more verbose\n");
207 printf("\t-o , --output filename\t\t set output filename\n");
208 printf("\t-V , --version\t\t\t Print program version and exit\n\n");
209 printf("SWF Subelement extraction:\n");
210 printf("\t-n , --name name\t\t instance name of the object (SWF Define) to extract\n");
211 printf("\t-i , --id ID\t\t\t ID of the object, shape or movieclip to extract\n");
212 printf("\t-f , --frame frames\t\t frame numbers to extract\n");
213 printf("\t-w , --hollow\t\t\t hollow mode: don't remove empty frames\n");
214 printf("\t \t\t\t (use with -f)\n");
215 printf("\t-P , --placeobject\t\t\t Insert original placeobject into output file\n");
216 printf("\t \t\t\t (use with -i)\n");
217 printf("SWF Font/Text extraction:\n");
218 printf("\t-F , --font ID\t\t\t Extract font(s)\n");
219 printf("Picture extraction:\n");
220 printf("\t-j , --jpeg ID\t\t\t Extract JPEG picture(s)\n");
221 #ifdef _ZLIB_INCLUDED_
222 printf("\t-p , --pngs ID\t\t\t Extract PNG picture(s)\n");
225 printf("Sound extraction:\n");
226 printf("\t-m , --mp3\t\t\t Extract main mp3 stream\n");
227 printf("\t-s , --sound ID\t\t\t Extract Sound(s)\n");
229 int args_callback_command(char*name,char*val)
232 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
239 void prepare_name(char *buf, size_t len, const char *prefix,
240 const char *suffix, int idx) {
241 if (outputformat!=NULL) {
242 // override default file name formatting
243 // make sure single-file behavior is not used
245 // Other parts of codebase use vsnprintf, so I assume snprintf
246 // is available on all platforms that swftools currently works on.
247 // We need to check for buffer overflows now that the user is
248 // supplying the format string.
249 snprintf(buf,len,outputformat,idx,suffix);
251 // use default file name formatting, unchanged
252 sprintf(buf,"%s%d.%s",prefix,idx,suffix);
256 U8 mainr,maing,mainb;
257 /* 1 = used, not expanded,
259 5 = wanted, not expanded
266 int extractname_id = -1;
268 void idcallback(void*data)
270 if(!(used[GET16(data)]&1)) {
272 used[GET16(data)] |= 1;
276 void enumerateIDs(TAG*tag, void(*callback)(void*))
282 data = (U8*)malloc(len);
283 PUT16(data, (tag->id<<6)+63);
284 *(U8*)&data[2] = tag->len;
285 *(U8*)&data[3] = tag->len>>8;
286 *(U8*)&data[4] = tag->len>>16;
287 *(U8*)&data[5] = tag->len>>24;
288 memcpy(&data[6], tag->data, tag->len);
291 data = (U8*)malloc(len);
292 PUT16(data, (tag->id<<6)+tag->len);
293 memcpy(&data[2], tag->data, tag->len);
295 map_ids_mem(data, len, callback);
297 int num = swf_GetNumUsedIDs(tag);
298 int *ptr = malloc(sizeof(int)*num);
300 swf_GetUsedIDs(tag, ptr);
302 callback(&tag->data[ptr[t]]);
305 void moveToZero(TAG*tag)
307 if(!swf_isPlaceTag(tag))
310 swf_GetPlaceObject(tag, &obj);
313 swf_ResetTag(tag, tag->id);
314 swf_SetPlaceObject(tag, &obj);
317 void extractTag(SWF*swf, char*filename)
329 memset(&newswf,0x00,sizeof(SWF)); // set global movie parameters
331 newswf.fileVersion = swf->fileVersion;
332 newswf.frameRate = swf->frameRate;
333 newswf.movieSize = swf->movieSize;
334 if(movetozero && originalplaceobjects) {
335 newswf.movieSize.xmax = swf->movieSize.xmax - swf->movieSize.xmin;
336 newswf.movieSize.ymax = swf->movieSize.ymax - swf->movieSize.ymin;
337 newswf.movieSize.xmin = 0;
338 newswf.movieSize.ymin = 0;
341 newswf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
342 desttag = newswf.firstTag;
346 swf_SetRGB(desttag,&rgb);
348 swf_GetRect(0, &objectbbox);
352 for(t=0;t<65536;t++) {
353 if(used[t] && !(used[t]&2)) {
355 msg("<warning> ID %d is referenced, but never defined.", t);
356 } else if(tags[t]->id==ST_DEFINESPRITE) {
358 while(tag->id != ST_END)
360 enumerateIDs(tag, idcallback);
365 enumerateIDs(tags[t], idcallback);
372 srctag = swf->firstTag;
375 while(srctag && (srctag->id || sprite)) {
380 if(srctag->id == ST_END) {
383 if(srctag->id == ST_DEFINESPRITE)
385 if(srctag->id == ST_JPEGTABLES)
387 if(swf_isDefiningTag(srctag)) {
388 int id = swf_GetDefineID(srctag);
392 b = swf_GetDefineBBox(srctag);
393 swf_ExpandRect2(&objectbbox, &b);
396 if ((((swf_isPlaceTag(srctag) && originalplaceobjects)
397 || srctag->id == ST_STARTSOUND) && (used[swf_GetPlaceID(srctag)]&4) ) ||
398 (swf_isPseudoDefiningTag(srctag) && used[swf_GetDefineID(srctag)]) ||
405 if(srctag->id == ST_REMOVEOBJECT) {
406 if(!used[swf_GetPlaceID(srctag)])
411 TAG*ttag = (TAG*)malloc(sizeof(TAG));
412 desttag = swf_InsertTag(desttag, srctag->id);
413 desttag->len = desttag->memsize = srctag->len;
414 desttag->data = malloc(srctag->len);
415 memcpy(desttag->data, srctag->data, srctag->len);
416 if(movetozero && swf_isPlaceTag(desttag)) {
423 srctag = srctag->next;
426 if(!extractframes && !hollow) {
427 if(!originalplaceobjects && (extractids||extractname_id>=0)) {
433 memset(&bbox, 0, sizeof(SRECT));
435 for(t=0;t<65536;t++) {
436 if(is_in_range(t, extractids)) {
443 printf("warning! You should use the -P when extracting multiple objects\n");
447 /* if there is only one object, we will scale it.
448 So let's figure out its bounding box */
449 TAG*tag = swf->firstTag;
451 if(swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) {
452 if(swf_GetDefineID(tag) == id)
453 bbox = swf_GetDefineBBox(tag);
458 newswf.movieSize.xmin = 0;
459 newswf.movieSize.ymin = 0;
460 newswf.movieSize.xmax = 512*20;
461 newswf.movieSize.ymax = 512*20;
463 if((objectbbox.xmin|objectbbox.ymin|objectbbox.xmax|objectbbox.ymax)!=0)
464 newswf.movieSize = objectbbox;
467 if(extractname_id>=0) {
468 desttag = swf_InsertTag(desttag, ST_PLACEOBJECT2);
469 swf_ObjectPlace(desttag, extractname_id, extractname_id, 0,0,extractname);
471 for(t=0;t<65536;t++) {
472 if(is_in_range(t, extractids)) {
474 desttag = swf_InsertTag(desttag, ST_PLACEOBJECT2);
475 swf_GetMatrix(0, &m);
477 int width = bbox.xmax - bbox.xmin;
478 int height = bbox.ymax - bbox.ymin;
479 int max = width>height?width:height;
483 m.sx = (512*20*65536)/max;
484 m.sy = (512*20*65536)/max;
486 //newswf.movieSize = swf_TurnRect(newswf.movieSize, &m);
488 swf_ObjectPlace(desttag, t, t, &m,0,0);
493 desttag = swf_InsertTag(desttag,ST_SHOWFRAME);
495 desttag = swf_InsertTag(desttag,ST_END);
497 f = open(filename, O_TRUNC|O_WRONLY|O_CREAT|O_BINARY, 0644);
498 if FAILED(swf_WriteSWF(f,&newswf)) fprintf(stderr,"WriteSWF() failed.\n");
501 swf_FreeTags(&newswf); // cleanup
504 int isOfType(int t, TAG*tag)
507 if(t == 0 && (tag->id == ST_DEFINESHAPE ||
508 tag->id == ST_DEFINESHAPE2 ||
509 tag->id == ST_DEFINESHAPE3)) {
512 if(t==1 && tag->id == ST_DEFINESPRITE) {
515 if(t == 2 && (tag->id == ST_DEFINEBITS ||
516 tag->id == ST_DEFINEBITSJPEG2 ||
517 tag->id == ST_DEFINEBITSJPEG3)) {
520 if(t == 3 && (tag->id == ST_DEFINEBITSLOSSLESS ||
521 tag->id == ST_DEFINEBITSLOSSLESS2)) {
524 if(t == 4 && (tag->id == ST_DEFINESOUND)) {
527 if(t == 5 && (tag->id == ST_DEFINEFONT || tag->id == ST_DEFINEFONT2 || tag->id == ST_DEFINEFONT3)) {
530 if (t== 6 && (tag->id == ST_DEFINEBINARY)) {
536 void listObjects(SWF*swf)
542 char*names[] = {"Shape", "MovieClip", "JPEG", "PNG", "Sound", "Font", "Binary"};
543 char*options[] = {"-i", "-i", "-j", "-p", "-s", "-F","-b"};
545 printf("Objects in file %s:\n",filename);
547 for(t=0;t<sizeof(names)/sizeof(names[0]);t++) {
549 int lastid = -2, lastprint=-1;
554 if(tag->id == ST_SOUNDSTREAMHEAD || tag->id == ST_SOUNDSTREAMHEAD2)
563 printf(" [%s] %d %s%s: ID(s) ", options[t], nr, names[t], nr>1?"s":"");
568 char show = isOfType(t,tag);
574 id = swf_GetDefineID(tag);
579 if(first || !follow) {
584 if(lastprint + 1 == lastid)
585 printf(", %d, %d", lastid, id);
587 printf("-%d, %d", lastid, id);
597 if(lastprint + 1 == lastid)
598 printf(", %d", lastid);
600 printf("-%d", lastid);
606 printf(" [-f] %d Frames: ID(s) 0-%d\n", frame, frame);
608 printf(" [-f] 1 Frame: ID(s) 0\n");
611 printf(" [-m] 1 MP3 Soundstream\n");
614 int handlefont(SWF*swf, TAG*tag)
619 char*filename = name;
622 id = swf_GetDefineID(tag);
623 prepare_name(name, sizeof(name), "font", "swf", id);
625 filename = destfilename;
628 swf_FontExtract(swf, id, &f);
630 if (!extractanyids) {
631 printf("Couldn't extract font %d\n", id);
636 swf_WriteFont(f, filename);
641 static char has_jpegtables=0;
642 static U8*jpegtables = 0;
643 static int jpegtablessize = 0;
645 void handlejpegtables(TAG*tag)
647 if(tag->id == ST_JPEGTABLES) {
648 jpegtables = tag->data;
649 jpegtablessize = tag->len;
654 FILE* save_fopen(char* name, char* mode)
656 FILE*fi = fopen(name, mode);
658 fprintf(stderr, "Error: Couldn't open %s\n", name);
664 int findjpegboundary(U8*data, int len)
668 for(t=0;t<len-4;t++) {
679 /* extract jpeg data out of a tag */
680 int handlejpeg(TAG*tag)
683 char*filename = name;
686 prepare_name(name, sizeof(name), "pic", "jpg", GET16(tag->data));
688 filename = destfilename;
689 if(!strcmp(filename,"output.swf"))
690 filename = "output.jpg";
692 /* swf jpeg images have two streams, which both start with ff d8 and
693 end with ff d9. The following code handles sorting the middle
694 <ff d9 ff d8> bytes out, so that one stream remains */
695 if(tag->id == ST_DEFINEBITSJPEG && tag->len>2 && has_jpegtables) {
696 fi = save_fopen(filename, "wb");
697 if(jpegtablessize>=2) {
698 fwrite(jpegtables, 1, jpegtablessize-2, fi); //don't write end tag (ff,d8)
699 fwrite(&tag->data[2+2], tag->len-2-2, 1, fi); //don't write start tag (ff,d9)
701 fwrite(tag->data+2, tag->len-2, 1, fi);
705 else if(tag->id == ST_DEFINEBITSJPEG2 && tag->len>2) {
707 int pos = findjpegboundary(&tag->data[2], tag->len-2);
710 fi = save_fopen(filename, "wb");
711 fwrite(&tag->data[2], pos-2, 1, fi);
712 fwrite(&tag->data[pos+4], end-(pos+4), 1, fi);
715 fi = save_fopen(filename, "wb");
716 fwrite(&tag->data[2], end-2, 1, fi);
720 else if(tag->id == ST_DEFINEBITSJPEG3 && tag->len>6) {
721 U32 end = GET32(&tag->data[2])+6;
722 int pos = findjpegboundary(&tag->data[6], tag->len-6);
724 fi = save_fopen(filename, "wb");
725 fwrite(&tag->data[6], end-6, 1, fi);
729 fi = save_fopen(filename, "wb");
730 fwrite(&tag->data[6], pos-6, 1, fi);
731 fwrite(&tag->data[pos+4], end-(pos+4), 1, fi);
736 int id = GET16(tag->data);
737 if (!extractanyids) {
738 fprintf(stderr, "Object %d is not a JPEG picture!\n", id);
746 #ifdef _ZLIB_INCLUDED_
749 static U32*crc32_table = 0;
750 static void make_crc32_table(void)
755 crc32_table = (U32*)malloc(1024);
757 for (t = 0; t < 256; t++) {
760 for (s = 0; s < 8; s++) {
761 c = (0xedb88320L*(c&1)) ^ (c >> 1);
766 static inline void png_write_byte(FILE*fi, U8 byte)
768 fwrite(&byte,1,1,fi);
769 mycrc32 = crc32_table[(mycrc32 ^ byte) & 0xff] ^ (mycrc32 >> 8);
771 static void png_start_chunk(FILE*fi, char*type, int len)
773 U8 mytype[4]={0,0,0,0};
774 U32 mylen = REVERSESWAP32(len);
775 memcpy(mytype,type,strlen(type));
776 fwrite(&mylen, 4, 1, fi);
778 png_write_byte(fi,mytype[0]);
779 png_write_byte(fi,mytype[1]);
780 png_write_byte(fi,mytype[2]);
781 png_write_byte(fi,mytype[3]);
783 static void png_write_bytes(FILE*fi, U8*bytes, int len)
787 png_write_byte(fi,bytes[t]);
789 static void png_write_dword(FILE*fi, U32 dword)
791 png_write_byte(fi,dword>>24);
792 png_write_byte(fi,dword>>16);
793 png_write_byte(fi,dword>>8);
794 png_write_byte(fi,dword);
796 static void png_end_chunk(FILE*fi)
798 U32 tmp = REVERSESWAP32((mycrc32^0xffffffff));
803 /* extract a lossless image (png) out of a tag
804 This routine was originally meant to be a one-pager. I just
805 didn't know png is _that_ much fun. :) -mk
807 int handlelossless(TAG*tag)
810 char*filename = name;
825 U8 head[] = {137,80,78,71,13,10,26,10};
827 char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
835 if(tag->id != ST_DEFINEBITSLOSSLESS &&
836 tag->id != ST_DEFINEBITSLOSSLESS2) {
837 int id = GET16(tag->data);
838 if (!extractanyids) {
839 fprintf(stderr, "Object %d is not a PNG picture!\n",id);
846 format = swf_GetU8(tag);
847 if(format == 3) bpp = 8;
848 if(format == 4) bpp = 16;
849 if(format == 5) bpp = 32;
850 if(format!=3 && format!=5) {
852 fprintf(stderr, "Can't handle 16-bit palette images yet (image %d)\n",id);
854 fprintf(stderr, "Unknown image type %d in image %d\n", format, id);
857 width = swf_GetU16(tag);
858 height = swf_GetU16(tag);
859 if(format == 3) cols = swf_GetU8(tag) + 1;
860 // this is what format means according to the flash specification. (which is
862 // if(format == 4) cols = swf_GetU16(tag) + 1;
863 // if(format == 5) cols = swf_GetU32(tag) + 1;
866 msg("<verbose> Width %d", width);
867 msg("<verbose> Height %d", height);
868 msg("<verbose> Format %d", format);
869 msg("<verbose> Cols %d", cols);
870 msg("<verbose> Bpp %d", bpp);
872 datalen = (width*height*bpp/8+cols*8);
877 data = malloc(datalen);
878 error = uncompress (data, &datalen, &tag->data[tag->pos], tag->len-tag->pos);
879 } while(error == Z_BUF_ERROR);
881 fprintf(stderr, "Zlib error %d (image %d)\n", error, id);
884 msg("<verbose> Uncompressed image is %d bytes (%d colormap)", datalen, (3+alpha)*cols);
886 datalen2 = datalen+16;
887 data2 = malloc(datalen2);
888 palette = (RGBA*)malloc(cols*sizeof(RGBA));
890 for(t=0;t<cols;t++) {
891 palette[t].r = data[pos++];
892 palette[t].g = data[pos++];
893 palette[t].b = data[pos++];
895 palette[t].a = data[pos++];
899 prepare_name(name, sizeof(name), "pic", "png", id);
901 filename = destfilename;
902 if(!strcmp(filename,"output.swf"))
903 filename = "output.png";
905 fi = save_fopen(filename, "wb");
906 fwrite(head,sizeof(head),1,fi);
908 png_start_chunk(fi, "IHDR", 13);
909 png_write_dword(fi,width);
910 png_write_dword(fi,height);
911 png_write_byte(fi,8);
913 png_write_byte(fi,3); //indexed
914 else if(format == 5 && alpha==0)
915 png_write_byte(fi,2); //rgb
916 else if(format == 5 && alpha==1)
917 png_write_byte(fi,6); //rgba
920 png_write_byte(fi,0); //compression mode
921 png_write_byte(fi,0); //filter mode
922 png_write_byte(fi,0); //interlace mode
926 png_start_chunk(fi, "PLTE", 768);
929 png_write_byte(fi,palette[t].r);
930 png_write_byte(fi,palette[t].g);
931 png_write_byte(fi,palette[t].b);
936 /* write alpha palette */
937 png_start_chunk(fi, "tRNS", 256);
939 png_write_byte(fi,palette[t].a);
947 int srcwidth = width * (bpp/8);
948 datalen3 = (width*4+5)*height;
949 data3 = (U8*)malloc(datalen3);
950 for(y=0;y<height;y++)
952 data3[pos2++]=0; //filter type
955 // 32 bit to 24 bit "conversion"
956 for(x=0;x<width;x++) {
957 data3[pos2++]=data[pos+1];
958 data3[pos2++]=data[pos+2];
959 data3[pos2++]=data[pos+3];
960 pos+=4; //ignore padding byte
963 for(x=0;x<width;x++) {
964 data3[pos2++]=data[pos+1];
965 data3[pos2++]=data[pos+2];
966 data3[pos2++]=data[pos+3];
967 data3[pos2++]=data[pos+0]; //alpha
973 for(x=0;x<srcwidth;x++)
974 data3[pos2++]=data[pos++];
977 pos+=((srcwidth+3)&~3)-srcwidth; //align
982 if(compress (data2, &datalen2, data3, datalen3) != Z_OK) {
983 fprintf(stderr, "zlib error in pic %d\n", id);
986 msg("<verbose> Compressed data is %d bytes", datalen2);
987 png_start_chunk(fi, "IDAT", datalen2);
988 png_write_bytes(fi,data2,datalen2);
990 png_start_chunk(fi, "IEND", 0);
1000 static FILE*mp3file=0;
1001 void handlesoundstream(TAG*tag)
1003 char*filename = "output.mp3";
1004 if(numextracts==1) {
1005 filename = destfilename;
1006 if(!strcmp(filename,"output.swf"))
1007 filename = "output.mp3";
1010 case ST_SOUNDSTREAMHEAD:
1011 if((tag->data[1]&0x30) == 0x20) { //mp3 compression
1012 mp3file = fopen(filename, "wb");
1013 msg("<notice> Writing mp3 data to %s",filename);
1016 msg("<error> Soundstream is not mp3");
1018 case ST_SOUNDSTREAMHEAD2:
1019 if((tag->data[1]&0x30) == 0x20) {//mp3 compression
1020 mp3file = fopen(filename, "wb");
1021 msg("<notice> Writing mp3 data to %s",filename);
1024 msg("<error> Soundstream is not mp3 (2)");
1026 case ST_SOUNDSTREAMBLOCK:
1028 fwrite(&tag->data[4],tag->len-4,1,mp3file);
1033 int handledefinesound(TAG*tag)
1038 char*filename = buf;
1043 int rate,bits,stereo;
1044 char*rates[] = {"5500","11025","22050","44100"};
1045 id = swf_GetU16(tag); //id
1047 flags = swf_GetU8(tag);
1049 rate = (flags>>2)&3;
1050 bits = flags&2?16:8;
1053 samples = swf_GetU32(tag);
1057 if(format == 2) { // mp3
1058 swf_GetU16(tag); //numsamples_seek
1060 } else if(format == 0) { // raw
1061 printf("Sound is RAW, format: %s samples/sec, %d bit, %s\n", rates[rate], bits, stereo?"stereo":"mono");
1062 // TODO: convert to WAV
1064 } else if(format == 1) { // adpcm
1065 printf("Sound is ADPCM, format: %s samples/sec, %d bit, %s\n", rates[rate], bits, stereo?"stereo":"mono");
1066 extension = "adpcm";
1070 prepare_name(buf, sizeof(buf), "sound", extension, id);
1071 if(numextracts==1) {
1072 filename = destfilename;
1073 if(!strcmp(filename,"output.swf")) {
1074 sprintf(buf, "output.%s", extension);
1078 fi = save_fopen(filename, "wb");
1079 fwrite(&tag->data[tag->pos], tag->len - tag->pos, 1, fi);
1084 int handlebinary(TAG*tag) {
1087 char *filename = buf;
1088 int len = tag->memsize;
1089 int dx = 6; // offset to binary data
1090 if (tag->id!=ST_DEFINEBINARY) {
1091 if (!extractanyids) {
1092 fprintf(stderr, "Object %d is not a binary entity!\n",
1097 prepare_name(buf, sizeof(buf), "binary", "bin", GET16(tag->data));
1098 if(numextracts==1) {
1099 filename = destfilename;
1100 if(!strcmp(filename,"output.swf")) {
1101 sprintf(buf, "output.bin");
1105 fout = fopen(filename, "wb");
1106 fwrite(tag->data+dx,len-dx,1,fout);
1111 int main (int argc,char ** argv)
1120 char listavailable = 0;
1121 processargs(argc, argv);
1123 if(!extractframes && !extractids && ! extractname && !extractjpegids && !extractpngids
1124 && !extractmp3 && !extractsoundids && !extractfontids && !extractbinaryids && !extractanyids)
1127 if(!originalplaceobjects && movetozero) {
1128 fprintf(stderr, "Error: -0 (--movetozero) can only be used in conjunction with -P (--placeobject)\n");
1134 fprintf(stderr, "You must supply a filename.\n");
1137 initLog(0,-1,0,0,-1, verbose);
1139 f = open(filename,O_RDONLY|O_BINARY);
1143 perror("Couldn't open file: ");
1146 if (swf_ReadSWF(f,&swf) < 0)
1148 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
1167 tagused = (char*)malloc(tagnum);
1168 memset(tagused, 0, tagnum);
1169 memset(used, 0, 65536);
1170 memset(depths, 0, 65536);
1175 if(swf_isAllowedSpriteTag(tag)) {
1177 if(extractframes && is_in_range(frame, extractframes)) {
1179 if(tag->id == ST_PLACEOBJECT || tag->id == ST_PLACEOBJECT2) {
1180 depths[swf_GetDepth(tag)] = 1;
1182 if(tag->id == ST_REMOVEOBJECT || tag->id == ST_REMOVEOBJECT2) {
1183 int depth = swf_GetDepth(tag);
1186 depths[swf_GetDepth(tag)] = 0;
1189 if((tag->id == ST_REMOVEOBJECT || tag->id == ST_REMOVEOBJECT2) &&
1190 (depths[swf_GetDepth(tag)]) && hollow) {
1192 depths[swf_GetDepth(tag)] = 0;
1196 enumerateIDs(tag, idcallback);
1198 tagused[tagnum] = 1;
1202 if(tag->id == ST_SOUNDSTREAMHEAD ||
1203 tag->id == ST_SOUNDSTREAMHEAD2 ||
1204 tag->id == ST_SOUNDSTREAMBLOCK) {
1206 handlesoundstream(tag);
1209 if(tag->id == ST_JPEGTABLES) {
1210 handlejpegtables(tag);
1213 if(swf_isDefiningTag(tag)) {
1214 int id = swf_GetDefineID(tag);
1216 if(extractids && is_in_range(id, extractids)) {
1220 if(extractfontids && is_in_range(id, extractfontids)) {
1221 handlefont(&swf, tag);
1223 if(extractjpegids && is_in_range(id, extractjpegids)) {
1226 if(extractsoundids && is_in_range(id, extractsoundids)) {
1227 handledefinesound(tag);
1229 if(extractbinaryids && is_in_range(id, extractbinaryids)) {
1232 #ifdef _ZLIB_INCLUDED_
1233 if(extractpngids && is_in_range(id, extractpngids)) {
1234 handlelossless(tag);
1237 if(extractanyids && is_in_range(id, extractanyids)) {
1238 if (handlefont(&swf,tag)) {
1240 } else if (handlejpeg(tag)) {
1242 } else if (handlebinary(tag)) {
1244 #ifdef _ZLIB_INCLUDED_
1245 } else if (handlelossless(tag)) {
1248 } else if (handledefinesound(tag)) {
1249 // Not sure if sound code checks carefully for type.
1252 printf("#%d not processed\n", id);
1256 else if (tag->id == ST_SETBACKGROUNDCOLOR) {
1257 mainr = tag->data[0];
1258 maing = tag->data[1];
1259 mainb = tag->data[2];
1261 else if(swf_isPlaceTag(tag) && tag->id != ST_PLACEOBJECT ) {
1262 char*name = swf_GetName(tag);
1263 if(name && extractname && !strcmp(name, extractname)) {
1264 int id = swf_GetPlaceID(tag);
1267 if(originalplaceobjects) {
1268 tagused[tagnum] = 1;
1270 depths[swf_GetDepth(tag)] = 1;
1271 extractname_id = id;
1274 else if(tag->id == ST_SHOWFRAME) {
1277 tagused[tagnum] = 1;
1282 if(tag->id == ST_DEFINESPRITE) {
1283 while(tag->id != ST_END) {
1292 extractTag(&swf, destfilename);
1298 msg("<error> Didn't find a soundstream in file");