X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=blobdiff_plain;f=src%2Fswfextract.c;h=e385f1f1accd12941ffdc4ae53111c1580677e4a;hp=a9e60e948e47a54d6bed123df428b5167ee3dc08;hb=2391d7ae5d8a145a250a8b80ab8c93ba74eba030;hpb=d24ed5e463e559fd245f16856acc34c28c7aaf09 diff --git a/src/swfextract.c b/src/swfextract.c index a9e60e9..e385f1f 100644 --- a/src/swfextract.c +++ b/src/swfextract.c @@ -4,8 +4,20 @@ Part of the swftools package. Copyright (c) 2001 Matthias Kramm + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. - This file is distributed under the GPL, see file COPYING for details */ + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include @@ -27,12 +39,17 @@ int verbose = 3; char* extractids = 0; char* extractframes = 0; char* extractjpegids = 0; +char* extractfontids = 0; char* extractpngids = 0; +char* extractsoundids = 0; +char* extractbinaryids = 0; char extractmp3 = 0; char* extractname = 0; char hollow = 0; +char originalplaceobjects = 0; +char movetozero = 0; int numextracts = 0; @@ -44,10 +61,15 @@ struct options_t options[] = {"i","id"}, {"j","jpegs"}, {"p","pngs"}, + {"P","placeobject"}, + {"0","movetozero"}, {"m","mp3"}, + {"s","sound"}, {"n","name"}, {"f","frame"}, + {"F","font"}, {"V","version"}, + {"b","binary"}, {0,0} }; @@ -94,14 +116,42 @@ int args_callback_option(char*name,char*val) fprintf(stderr, "Only one --jpegs argument is allowed. (Try to use a range, e.g. -j 1,2,3)\n"); exit(1); } + /* TODO: count number of IDs in val range */ numextracts++; extractjpegids = val; return 1; } + else if(!strcmp(name, "F")) { + if(extractfontids) { + fprintf(stderr, "Only one --font argument is allowed. (Try to use a range, e.g. -s 1,2,3)\n"); + exit(1); + } + numextracts++; + extractfontids = val; + return 1; + } + else if(!strcmp(name, "s")) { + if(extractsoundids) { + fprintf(stderr, "Only one --sound argument is allowed. (Try to use a range, e.g. -s 1,2,3)\n"); + exit(1); + } + numextracts++; + extractsoundids = val; + return 1; + } + else if(!strcmp(name, "b")) { + if(extractbinaryids) { + fprintf(stderr, "Only one --binary argument is allowed. (Try to use a range, e.g. -s 1,2,3)\n"); + exit(1); + } + numextracts++; + extractbinaryids = val; + return 1; + } #ifdef _ZLIB_INCLUDED_ else if(!strcmp(name, "p")) { if(extractpngids) { - fprintf(stderr, "Only one --pngs argument is allowed. (Try to use a range, e.g. -p 1,2,3)\n"); + fprintf(stderr, "Only one --png argument is allowed. (Try to use a range, e.g. -p 1,2,3)\n"); exit(1); } numextracts++; @@ -114,13 +164,21 @@ int args_callback_option(char*name,char*val) extractframes = val; return 1; } + else if(!strcmp(name, "P")) { + originalplaceobjects = 1; + return 0; + } + else if(!strcmp(name, "0")) { + movetozero = 1; + return 0; + } else if(!strcmp(name, "w")) { hollow = 1; return 0; } else { printf("Unknown option: -%s\n", name); - return 0; + exit(1); } return 0; @@ -134,17 +192,26 @@ void args_callback_usage(char*name) printf("Usage: %s [-v] [-n name] [-ijf ids] file.swf\n", name); printf("\t-v , --verbose\t\t\t Be more verbose\n"); printf("\t-o , --output filename\t\t set output filename\n"); - printf("\t-n , --name name\t\t instance name of the object to extract\n"); - printf("\t-i , --id IDs\t\t\t ID of the object to extract\n"); - printf("\t-j , --jpeg IDs\t\t\t IDs of the JPEG pictures to extract\n"); -#ifdef _ZLIB_INCLUDED_ - printf("\t-p , --pngs IDs\t\t\t IDs of the PNG pictures to extract\n"); -#endif - printf("\t-m , --mp3\t\t\t Extract main mp3 stream\n"); + printf("\t-V , --version\t\t\t Print program version and exit\n\n"); + printf("SWF Subelement extraction:\n"); + printf("\t-n , --name name\t\t instance name of the object (SWF Define) to extract\n"); + printf("\t-i , --id ID\t\t\t ID of the object, shape or movieclip to extract\n"); printf("\t-f , --frame frames\t\t frame numbers to extract\n"); printf("\t-w , --hollow\t\t\t hollow mode: don't remove empty frames\n"); printf("\t \t\t\t (use with -f)\n"); - printf("\t-V , --version\t\t\t Print program version and exit\n"); + printf("\t-P , --placeobject\t\t\t Insert original placeobject into output file\n"); + printf("\t \t\t\t (use with -i)\n"); + printf("SWF Font/Text extraction:\n"); + printf("\t-F , --font ID\t\t\t Extract font(s)\n"); + printf("Picture extraction:\n"); + printf("\t-j , --jpeg ID\t\t\t Extract JPEG picture(s)\n"); +#ifdef _ZLIB_INCLUDED_ + printf("\t-p , --pngs ID\t\t\t Extract PNG picture(s)\n"); +#endif + printf("\n"); + printf("Sound extraction:\n"); + printf("\t-m , --mp3\t\t\t Extract main mp3 stream\n"); + printf("\t-s , --sound ID\t\t\t Extract Sound(s)\n"); } int args_callback_command(char*name,char*val) { @@ -166,6 +233,7 @@ char used[65536]; TAG*tags[65536]; int changed; char * tagused; +int extractname_id = -1; void idcallback(void*data) { @@ -204,12 +272,25 @@ void enumerateIDs(TAG*tag, void(*callback)(void*)) callback(&tag->data[ptr[t]]); } +void moveToZero(TAG*tag) +{ + if(!swf_isPlaceTag(tag)) + return; + SWFPLACEOBJECT obj; + swf_GetPlaceObject(tag, &obj); + obj.matrix.tx = 0; + obj.matrix.ty = 0; + swf_ResetTag(tag, tag->id); + swf_SetPlaceObject(tag, &obj); +} + void extractTag(SWF*swf, char*filename) { SWF newswf; TAG*desttag; TAG*srctag; RGBA rgb; + SRECT objectbbox; char sprite; int f; int t; @@ -220,6 +301,12 @@ void extractTag(SWF*swf, char*filename) newswf.fileVersion = swf->fileVersion; newswf.frameRate = swf->frameRate; newswf.movieSize = swf->movieSize; + if(movetozero && originalplaceobjects) { + newswf.movieSize.xmax = swf->movieSize.xmax - swf->movieSize.xmin; + newswf.movieSize.ymax = swf->movieSize.ymax - swf->movieSize.ymin; + newswf.movieSize.xmin = 0; + newswf.movieSize.ymin = 0; + } newswf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR); desttag = newswf.firstTag; @@ -228,11 +315,15 @@ void extractTag(SWF*swf, char*filename) rgb.b = mainb; swf_SetRGB(desttag,&rgb); + swf_GetRect(0, &objectbbox); + do { changed = 0; for(t=0;t<65536;t++) { if(used[t] && !(used[t]&2)) { - if(tags[t]->id==ST_DEFINESPRITE) { + if(tags[t]==0) { + msg(" ID %d is referenced, but never defined.", t); + } else if(tags[t]->id==ST_DEFINESPRITE) { TAG*tag = tags[t]; while(tag->id != ST_END) { @@ -261,14 +352,19 @@ void extractTag(SWF*swf, char*filename) } if(srctag->id == ST_DEFINESPRITE) sprite = 1; + if(srctag->id == ST_JPEGTABLES) + copy = 1; if(swf_isDefiningTag(srctag)) { int id = swf_GetDefineID(srctag); - if(used[id]) + if(used[id]) { + SRECT b; copy = 1; + b = swf_GetDefineBBox(srctag); + swf_ExpandRect2(&objectbbox, &b); + } } else - if (((srctag->id == ST_PLACEOBJECT || - srctag->id == ST_PLACEOBJECT2 || - srctag->id == ST_STARTSOUND) && (used[swf_GetPlaceID(srctag)]&4) ) || + if ((((swf_isPlaceTag(srctag) && originalplaceobjects) + || srctag->id == ST_STARTSOUND) && (used[swf_GetPlaceID(srctag)]&4) ) || (swf_isPseudoDefiningTag(srctag) && used[swf_GetDefineID(srctag)]) || (tagused[tagnum])) { @@ -287,6 +383,9 @@ void extractTag(SWF*swf, char*filename) desttag->len = desttag->memsize = srctag->len; desttag->data = malloc(srctag->len); memcpy(desttag->data, srctag->data, srctag->len); + if(movetozero && swf_isPlaceTag(desttag)) { + moveToZero(desttag); + } if(reset) copy = 0; } @@ -294,98 +393,228 @@ void extractTag(SWF*swf, char*filename) srctag = srctag->next; tagnum ++; } - if(!extractframes && !hollow) - desttag = swf_InsertTag(desttag,ST_SHOWFRAME); + if(!extractframes && !hollow) { + if(!originalplaceobjects && (extractids||extractname_id>=0)) { + int number = 0; + int id = 0; + int t; + TAG* objtag = 0; + SRECT bbox; + memset(&bbox, 0, sizeof(SRECT)); + if(extractids) { + for(t=0;t<65536;t++) { + if(is_in_range(t, extractids)) { + id = t; + number++; + } + } + } + if(number>=2) { + printf("warning! You should use the -P when extracting multiple objects\n"); + } + if(number == 1) { + /* if there is only one object, we will scale it. + So let's figure out its bounding box */ + TAG*tag = swf->firstTag; + while(tag) { + if(swf_isDefiningTag(tag) && tag->id != ST_DEFINESPRITE) { + if(swf_GetDefineID(tag) == id) + bbox = swf_GetDefineBBox(tag); + objtag = tag; + } + tag = tag->next; + } + newswf.movieSize.xmin = 0; + newswf.movieSize.ymin = 0; + newswf.movieSize.xmax = 512*20; + newswf.movieSize.ymax = 512*20; + } else { + if((objectbbox.xmin|objectbbox.ymin|objectbbox.xmax|objectbbox.ymax)!=0) + newswf.movieSize = objectbbox; + } + + if(extractname_id>=0) { + desttag = swf_InsertTag(desttag, ST_PLACEOBJECT2); + swf_ObjectPlace(desttag, extractname_id, extractname_id, 0,0,extractname); + } else { + for(t=0;t<65536;t++) { + if(is_in_range(t, extractids)) { + MATRIX m; + desttag = swf_InsertTag(desttag, ST_PLACEOBJECT2); + swf_GetMatrix(0, &m); + if(objtag) { + int width = bbox.xmax - bbox.xmin; + int height = bbox.ymax - bbox.ymin; + int max = width>height?width:height; + m.tx = -bbox.xmin; + m.ty = -bbox.ymin; + if(max) { + m.sx = (512*20*65536)/max; + m.sy = (512*20*65536)/max; + } + //newswf.movieSize = swf_TurnRect(newswf.movieSize, &m); + } + swf_ObjectPlace(desttag, t, t, &m,0,0); + } + } + } + } + desttag = swf_InsertTag(desttag,ST_SHOWFRAME); + } desttag = swf_InsertTag(desttag,ST_END); - f = open(filename, O_TRUNC|O_WRONLY|O_CREAT, 0644); + f = open(filename, O_TRUNC|O_WRONLY|O_CREAT|O_BINARY, 0644); if FAILED(swf_WriteSWF(f,&newswf)) fprintf(stderr,"WriteSWF() failed.\n"); close(f); swf_FreeTags(&newswf); // cleanup } +int isOfType(int t, TAG*tag) +{ + int show = 0; + if(t == 0 && (tag->id == ST_DEFINESHAPE || + tag->id == ST_DEFINESHAPE2 || + tag->id == ST_DEFINESHAPE3)) { + show = 1; + } + if(t==1 && tag->id == ST_DEFINESPRITE) { + show = 1; + } + if(t == 2 && (tag->id == ST_DEFINEBITS || + tag->id == ST_DEFINEBITSJPEG2 || + tag->id == ST_DEFINEBITSJPEG3)) { + show = 1; + } + if(t == 3 && (tag->id == ST_DEFINEBITSLOSSLESS || + tag->id == ST_DEFINEBITSLOSSLESS2)) { + show = 1; + } + if(t == 4 && (tag->id == ST_DEFINESOUND)) { + show = 1; + } + if(t == 5 && (tag->id == ST_DEFINEFONT || tag->id == ST_DEFINEFONT2 || tag->id == ST_DEFINEFONT3)) { + show = 1; + } + if (t== 6 && (tag->id == ST_DEFINEBINARY)) { + show = 1; + } + return show; +} + void listObjects(SWF*swf) { TAG*tag; char first; int t; int frame = 0; - char*names[] = {"Shapes","MovieClips","JPEGs","PNGs","Sounds","Frames"}; + char*names[] = {"Shape", "MovieClip", "JPEG", "PNG", "Sound", "Font", "Binary"}; + char*options[] = {"-i", "-i", "-j", "-p", "-s", "-F","-b"}; + int mp3=0; printf("Objects in file %s:\n",filename); - for(t=0;t<6;t++) { + swf_FoldAll(swf); + for(t=0;tfirstTag; first = 1; while(tag) { - char show = 0; + if(tag->id == ST_SOUNDSTREAMHEAD || tag->id == ST_SOUNDSTREAMHEAD2) + mp3 = 1; + if(isOfType(t,tag)) + nr++; + tag = tag->next; + } + if(!nr) + continue; + + printf(" [%s] %d %s%s: ID(s) ", options[t], nr, names[t], nr>1?"s":""); + + tag = swf->firstTag; + while(tag) { char text[80]; - if(t == 0 && - (tag->id == ST_DEFINESHAPE || - tag->id == ST_DEFINESHAPE2 || - tag->id == ST_DEFINESHAPE3)) { - show = 1; - sprintf(text,"%d", swf_GetDefineID(tag)); + char show = isOfType(t,tag); + int id; + if(!show) { + tag = tag->next; + continue; } + id = swf_GetDefineID(tag); - if(tag->id == ST_DEFINESPRITE) { - if (t == 1) { - show = 1; - sprintf(text,"%d", swf_GetDefineID(tag)); + if(id == lastid+1) { + follow=1; + } else { + if(first || !follow) { + if(!first) + printf(", "); + printf("%d", id); + } else { + if(lastprint + 1 == lastid) + printf(", %d, %d", lastid, id); + else + printf("-%d, %d", lastid, id); } - - while(tag->id != ST_END) - tag = tag->next; + lastprint = id; + first = 0; + follow = 0; } + lastid = id; + tag=tag->next; + } + if(follow) { + if(lastprint + 1 == lastid) + printf(", %d", lastid); + else + printf("-%d", lastid); + } + printf("\n"); + } - if(t == 2 && (tag->id == ST_DEFINEBITS || - tag->id == ST_DEFINEBITSJPEG2 || - tag->id == ST_DEFINEBITSJPEG3)) { - show = 1; - sprintf(text,"%d", swf_GetDefineID(tag)); - } + if(frame) + printf(" [-f] %d Frames: ID(s) 0-%d\n", frame, frame); + else + printf(" [-f] 1 Frame: ID(s) 0\n"); - if(t == 3 && (tag->id == ST_DEFINEBITSLOSSLESS || - tag->id == ST_DEFINEBITSLOSSLESS2)) { - show = 1; - sprintf(text,"%d", swf_GetDefineID(tag)); - } + if(mp3) + printf(" [-m] 1 MP3 Soundstream\n"); +} +void handlefont(SWF*swf, TAG*tag) +{ + SWFFONT* f=0; + U16 id; + char name[80]; + char*filename = name; + int t; - if(t == 4 && (tag->id == ST_DEFINESOUND)) { - show = 1; - sprintf(text,"%d", swf_GetDefineID(tag)); - } - - if(t == 5 && (tag->id == ST_SHOWFRAME)) { - show = 1; - sprintf(text,"%d", frame); - frame ++; - } + id = swf_GetDefineID(tag); + sprintf(name, "font%d.swf", id); + if(numextracts==1) { + filename = destfilename; + } - if(show) { - if(!first) - printf(", "); - else - printf("%s: ", names[t]); - printf("%s", text); - first = 0; - } - tag=tag->next; - } - if(!first) - printf("\n"); + swf_FontExtract(swf, id, &f); + if(!f) { + printf("Couldn't extract font %d\n", id); + return; } + + swf_WriteFont(f, filename); + swf_FontFree(f); } -U8*jpegtables = 0; -int jpegtablessize; +static char has_jpegtables=0; +static U8*jpegtables = 0; +static int jpegtablessize = 0; void handlejpegtables(TAG*tag) { if(tag->id == ST_JPEGTABLES) { jpegtables = tag->data; jpegtablessize = tag->len; + has_jpegtables = 1; } } @@ -403,7 +632,7 @@ int findjpegboundary(U8*data, int len) { int t; int pos=-1; - for(t=0;tdata)); + + sprintf(name, "pic%d.jpg", GET16(tag->data)); + if(numextracts==1) { + filename = destfilename; + if(!strcmp(filename,"output.swf")) + filename = "output.jpg"; + } /* swf jpeg images have two streams, which both start with ff d8 and end with ff d9. The following code handles sorting the middle bytes out, so that one stream remains */ - if(tag->id == ST_DEFINEBITS && tag->len>2 && jpegtables) { - fi = save_fopen(name, "wb"); - fwrite(jpegtables, 1, jpegtablessize-2, fi); //don't write end tag (ff,d8) - fwrite(&tag->data[2+2], tag->len-2-2, 1, fi); //don't write start tag (ff,d9) + if(tag->id == ST_DEFINEBITSJPEG && tag->len>2 && has_jpegtables) { + fi = save_fopen(filename, "wb"); + if(jpegtablessize>=2) { + fwrite(jpegtables, 1, jpegtablessize-2, fi); //don't write end tag (ff,d8) + fwrite(&tag->data[2+2], tag->len-2-2, 1, fi); //don't write start tag (ff,d9) + } else { + fwrite(tag->data+2, tag->len-2, 1, fi); + } fclose(fi); } - if(tag->id == ST_DEFINEBITSJPEG2 && tag->len>2) { + else if(tag->id == ST_DEFINEBITSJPEG2 && tag->len>2) { int end = tag->len; int pos = findjpegboundary(&tag->data[2], tag->len-2); - if(pos<0) - return; - pos+=2; - fi = save_fopen(name, "wb"); - fwrite(&tag->data[2], pos-2, 1, fi); - fwrite(&tag->data[pos+4], end-(pos+4), 1, fi); - fclose(fi); + if(pos>=0) { + pos+=2; + fi = save_fopen(filename, "wb"); + fwrite(&tag->data[2], pos-2, 1, fi); + fwrite(&tag->data[pos+4], end-(pos+4), 1, fi); + fclose(fi); + } else { + fi = save_fopen(filename, "wb"); + fwrite(&tag->data[2], end-2, 1, fi); + fclose(fi); + } } - if(tag->id == ST_DEFINEBITSJPEG3 && tag->len>6) { + else if(tag->id == ST_DEFINEBITSJPEG3 && tag->len>6) { U32 end = GET32(&tag->data[2])+6; int pos = findjpegboundary(&tag->data[6], tag->len-6); - if(pos<0) - return; - pos+=6; - fi = save_fopen(name, "wb"); - fwrite(&tag->data[6], pos-6, 1, fi); - fwrite(&tag->data[pos+4], end-(pos+4), 1, fi); - fclose(fi); + if(pos<0) { + fi = save_fopen(filename, "wb"); + fwrite(&tag->data[6], end-6, 1, fi); + fclose(fi); + } else { + pos+=6; + fi = save_fopen(filename, "wb"); + fwrite(&tag->data[6], pos-6, 1, fi); + fwrite(&tag->data[pos+4], end-(pos+4), 1, fi); + fclose(fi); + } + } + else { + int id = GET16(tag->data); + fprintf(stderr, "Object %d is not a JPEG picture!\n", id); + exit(1); } } @@ -473,7 +726,7 @@ static void make_crc32_table(void) crc32_table[t] = c; } } -static void png_write_byte(FILE*fi, U8 byte) +static inline void png_write_byte(FILE*fi, U8 byte) { fwrite(&byte,1,1,fi); mycrc32 = crc32_table[(mycrc32 ^ byte) & 0xff] ^ (mycrc32 >> 8); @@ -517,6 +770,7 @@ static void png_end_chunk(FILE*fi) void handlelossless(TAG*tag) { char name[80]; + char*filename = name; FILE*fi; int width, height; int crc; @@ -525,11 +779,11 @@ void handlelossless(TAG*tag) U8 bpp = 1; U8 format; U8 tmp; - U8* data=0; + Bytef* data=0; U8* data2=0; U8* data3=0; - U32 datalen; - U32 datalen2; + uLongf datalen; + uLongf datalen2; U32 datalen3; U8 head[] = {137,80,78,71,13,10,26,10}; int cols; @@ -542,8 +796,11 @@ void handlelossless(TAG*tag) make_crc32_table(); if(tag->id != ST_DEFINEBITSLOSSLESS && - tag->id != ST_DEFINEBITSLOSSLESS2) - return; + tag->id != ST_DEFINEBITSLOSSLESS2) { + int id = GET16(tag->data); + fprintf(stderr, "Object %d is not a PNG picture!\n",id); + exit(1); + } id =swf_GetU16(tag); format = swf_GetU8(tag); @@ -566,11 +823,11 @@ void handlelossless(TAG*tag) // if(format == 5) cols = swf_GetU32(tag) + 1; else cols = 0; - logf(" Width %d", width); - logf(" Height %d", height); - logf(" Format %d", format); - logf(" Cols %d", cols); - logf(" Bpp %d", bpp); + msg(" Width %d", width); + msg(" Height %d", height); + msg(" Format %d", format); + msg(" Cols %d", cols); + msg(" Bpp %d", bpp); datalen = (width*height*bpp/8+cols*8); do { @@ -584,9 +841,9 @@ void handlelossless(TAG*tag) fprintf(stderr, "Zlib error %d (image %d)\n", error, id); return; } - logf(" Uncompressed image is %d bytes (%d colormap)", datalen, (3+alpha)*cols); + msg(" Uncompressed image is %d bytes (%d colormap)", datalen, (3+alpha)*cols); pos = 0; - datalen2 = datalen; + datalen2 = datalen+16; data2 = malloc(datalen2); palette = (RGBA*)malloc(cols*sizeof(RGBA)); @@ -600,7 +857,12 @@ void handlelossless(TAG*tag) } sprintf(name, "pic%d.png", id); - fi = save_fopen(name, "wb"); + if(numextracts==1) { + filename = destfilename; + if(!strcmp(filename,"output.swf")) + filename = "output.png"; + } + fi = save_fopen(filename, "wb"); fwrite(head,sizeof(head),1,fi); png_start_chunk(fi, "IHDR", 13); @@ -609,8 +871,10 @@ void handlelossless(TAG*tag) png_write_byte(fi,8); if(format == 3) png_write_byte(fi,3); //indexed - else if(format == 5) + else if(format == 5 && alpha==0) png_write_byte(fi,2); //rgb + else if(format == 5 && alpha==1) + png_write_byte(fi,6); //rgba else return; png_write_byte(fi,0); //compression mode @@ -620,29 +884,49 @@ void handlelossless(TAG*tag) if(format == 3) { png_start_chunk(fi, "PLTE", 768); + for(t=0;t<256;t++) { png_write_byte(fi,palette[t].r); png_write_byte(fi,palette[t].g); png_write_byte(fi,palette[t].b); } png_end_chunk(fi); + + if(alpha) { + /* write alpha palette */ + png_start_chunk(fi, "tRNS", 256); + for(t=0;t<256;t++) { + png_write_byte(fi,palette[t].a); + } + png_end_chunk(fi); + } } { int pos2 = 0; int x,y; int srcwidth = width * (bpp/8); - datalen3 = width*height*4; + datalen3 = (width*4+5)*height; data3 = (U8*)malloc(datalen3); for(y=0;y Compressed data is %d bytes", datalen2); + msg(" Compressed data is %d bytes", datalen2); png_start_chunk(fi, "IDAT", datalen2); png_write_bytes(fi,data2,datalen2); png_end_chunk(fi); @@ -672,7 +956,7 @@ void handlelossless(TAG*tag) } #endif -FILE*mp3file; +static FILE*mp3file=0; void handlesoundstream(TAG*tag) { char*filename = "output.mp3"; @@ -685,18 +969,18 @@ void handlesoundstream(TAG*tag) case ST_SOUNDSTREAMHEAD: if((tag->data[1]&0x30) == 0x20) { //mp3 compression mp3file = fopen(filename, "wb"); - logf(" Writing mp3 data to %s",filename); + msg(" Writing mp3 data to %s",filename); } else - logf(" Soundstream is not mp3"); + msg(" Soundstream is not mp3"); break; case ST_SOUNDSTREAMHEAD2: if((tag->data[1]&0x30) == 0x20) {//mp3 compression - mp3file = fopen("mainstream.mp3", "wb"); - logf(" Writing mp3 data to %s",filename); + mp3file = fopen(filename, "wb"); + msg(" Writing mp3 data to %s",filename); } else - logf(" Soundstream is not mp3 (2)"); + msg(" Soundstream is not mp3 (2)"); break; case ST_SOUNDSTREAMBLOCK: if(mp3file) @@ -705,6 +989,78 @@ void handlesoundstream(TAG*tag) } } +void handledefinesound(TAG*tag) +{ + U8 flags; + U32 samples; + char buf[128]; + char*filename = buf; + FILE*fi; + char*extension = 0; + int format; + U16 id; + int rate,bits,stereo; + char*rates[] = {"5500","11025","22050","44100"}; + id = swf_GetU16(tag); //id + + flags = swf_GetU8(tag); + format = flags>>4; + rate = (flags>>2)&3; + bits = flags&2?16:8; + stereo = flags&1; + + samples = swf_GetU32(tag); + + extension = "raw"; + + if(format == 2) { // mp3 + swf_GetU16(tag); //numsamples_seek + extension = "mp3"; + } else if(format == 0) { // raw + printf("Sound is RAW, format: %s samples/sec, %d bit, %s\n", rates[rate], bits, stereo?"stereo":"mono"); + // TODO: convert to WAV + extension = "raw"; + } else if(format == 1) { // adpcm + printf("Sound is ADPCM, format: %s samples/sec, %d bit, %s\n", rates[rate], bits, stereo?"stereo":"mono"); + extension = "adpcm"; + } + sprintf(buf, "sound%d.%s", id, extension); + if(numextracts==1) { + filename = destfilename; + if(!strcmp(filename,"output.swf")) { + sprintf(buf, "output.%s", extension); + filename = buf; + } + } + fi = save_fopen(filename, "wb"); + fwrite(&tag->data[tag->pos], tag->len - tag->pos, 1, fi); + fclose(fi); +} + +void handlebinary(TAG*tag) { + FILE *fout = NULL; + char buf[100]; + char *filename = buf; + int len = tag->memsize; + int dx = 6; // offset to binary data + if (tag->id!=ST_DEFINEBINARY) { + fprintf(stderr, "Object %d is not a binary entity!\n", + GET16(tag->data)); + return; + } + sprintf(buf, "binary%d.bin", GET16(tag->data)); + if(numextracts==1) { + filename = destfilename; + if(!strcmp(filename,"output.swf")) { + sprintf(buf, "output.bin"); + filename = buf; + } + } + fout = fopen(filename, "wb"); + fwrite(tag->data+dx,len-dx,1,fout); + fclose(fout); +} + int main (int argc,char ** argv) { TAG*tag; @@ -718,9 +1074,14 @@ int main (int argc,char ** argv) processargs(argc, argv); if(!extractframes && !extractids && ! extractname && !extractjpegids && !extractpngids - && !extractmp3) + && !extractmp3 && !extractsoundids && !extractfontids && !extractbinaryids) listavailable = 1; + if(!originalplaceobjects && movetozero) { + fprintf(stderr, "Error: -0 (--movetozero) can only be used in conjunction with -P (--placeobject)\n"); + return 0; + } + if(!filename) { fprintf(stderr, "You must supply a filename.\n"); @@ -728,7 +1089,7 @@ int main (int argc,char ** argv) } initLog(0,-1,0,0,-1, verbose); - f = open(filename,O_RDONLY); + f = open(filename,O_RDONLY|O_BINARY); if (f<0) { @@ -794,11 +1155,13 @@ int main (int argc,char ** argv) if(tag->id == ST_SOUNDSTREAMHEAD || tag->id == ST_SOUNDSTREAMHEAD2 || tag->id == ST_SOUNDSTREAMBLOCK) { - handlesoundstream(tag); + if(extractmp3) + handlesoundstream(tag); } - if(tag->id == ST_JPEGTABLES) + if(tag->id == ST_JPEGTABLES) { handlejpegtables(tag); + } if(swf_isDefiningTag(tag)) { int id = swf_GetDefineID(tag); @@ -807,9 +1170,18 @@ int main (int argc,char ** argv) used[id] = 5; found = 1; } + if(extractfontids && is_in_range(id, extractfontids)) { + handlefont(&swf, tag); + } if(extractjpegids && is_in_range(id, extractjpegids)) { handlejpeg(tag); } + if(extractsoundids && is_in_range(id, extractsoundids)) { + handledefinesound(tag); + } + if(extractbinaryids && is_in_range(id, extractbinaryids)) { + handlebinary(tag); + } #ifdef _ZLIB_INCLUDED_ if(extractpngids && is_in_range(id, extractpngids)) { handlelossless(tag); @@ -821,14 +1193,17 @@ int main (int argc,char ** argv) maing = tag->data[1]; mainb = tag->data[2]; } - else if(tag->id == ST_PLACEOBJECT2) { + else if(swf_isPlaceTag(tag) && tag->id != ST_PLACEOBJECT ) { char*name = swf_GetName(tag); if(name && extractname && !strcmp(name, extractname)) { int id = swf_GetPlaceID(tag); used[id] = 5; found = 1; - tagused[tagnum] = 1; + if(originalplaceobjects) { + tagused[tagnum] = 1; + } depths[swf_GetDepth(tag)] = 1; + extractname_id = id; } } else if(tag->id == ST_SHOWFRAME) { @@ -851,8 +1226,13 @@ int main (int argc,char ** argv) if (found) extractTag(&swf, destfilename); - if(mp3file) + if(mp3file) { fclose(mp3file); + } else { + if(extractmp3) { + msg(" Didn't find a soundstream in file"); + } + } swf_FreeTags(&swf); return 0;