X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=src%2Fswfextract.c;h=9393ff62958efd8240b71e5a7149a6021585ab84;hb=5b709a634c4998b6d699f9a183c27747e93e92a7;hp=15be5a50f6e4953e8ec486b8827875c8db812904;hpb=23c1c9363c730dfafc683bd00920a2c33cc07ee2;p=swftools.git diff --git a/src/swfextract.c b/src/swfextract.c index 15be5a5..9393ff6 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,6 +39,7 @@ int verbose = 3; char* extractids = 0; char* extractframes = 0; char* extractjpegids = 0; +char* extractfontids = 0; char* extractpngids = 0; char* extractsoundids = 0; char extractmp3 = 0; @@ -34,6 +47,7 @@ char extractmp3 = 0; char* extractname = 0; char hollow = 0; +char originalplaceobjects = 0; int numextracts = 0; @@ -45,10 +59,12 @@ struct options_t options[] = {"i","id"}, {"j","jpegs"}, {"p","pngs"}, + {"P","placeobject"}, {"m","mp3"}, {"s","sound"}, {"n","name"}, {"f","frame"}, + {"F","font"}, {"V","version"}, {0,0} }; @@ -100,6 +116,15 @@ int args_callback_option(char*name,char*val) 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"); @@ -112,7 +137,7 @@ int args_callback_option(char*name,char*val) #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++; @@ -125,13 +150,17 @@ 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, "w")) { hollow = 1; return 0; } else { printf("Unknown option: -%s\n", name); - return 0; + exit(1); } return 0; @@ -148,10 +177,14 @@ void args_callback_usage(char*name) 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 (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-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_ @@ -182,6 +215,7 @@ char used[65536]; TAG*tags[65536]; int changed; char * tagused; +int extractname_id = -1; void idcallback(void*data) { @@ -226,6 +260,7 @@ void extractTag(SWF*swf, char*filename) TAG*desttag; TAG*srctag; RGBA rgb; + SRECT objectbbox; char sprite; int f; int t; @@ -244,11 +279,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) { @@ -279,12 +318,15 @@ void extractTag(SWF*swf, char*filename) sprite = 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 (((((srctag->id == ST_PLACEOBJECT || srctag->id == ST_PLACEOBJECT2) && originalplaceobjects) + || srctag->id == ST_STARTSOUND) && (used[swf_GetPlaceID(srctag)]&4) ) || (swf_isPseudoDefiningTag(srctag) && used[swf_GetDefineID(srctag)]) || (tagused[tagnum])) { @@ -310,88 +352,162 @@ void extractTag(SWF*swf, char*filename) srctag = srctag->next; tagnum ++; } - if(!extractframes && !hollow) + if(!extractframes && !hollow) { + if(!originalplaceobjects && (extractids||extractname_id>=0)) { + int t; + int s=0; + 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)) { + desttag = swf_InsertTag(desttag, ST_PLACEOBJECT2); + swf_ObjectPlace(desttag, t, t, 0,0,0); + s++; + if(s==2) + printf("warning! You should use the -P when extracting multiple objects\n"); + } + } + } + } 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)) { + 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"}; 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(isOfType(t,tag)) + nr++; + tag = tag->next; + } + if(!nr) + continue; + + printf(" %d %s%s: ID(s) ", 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; - } - - if(t == 2 && (tag->id == ST_DEFINEBITS || - tag->id == ST_DEFINEBITSJPEG2 || - tag->id == ST_DEFINEBITSJPEG3)) { - show = 1; - sprintf(text,"%d", swf_GetDefineID(tag)); + 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 == 3 && (tag->id == ST_DEFINEBITSLOSSLESS || - tag->id == ST_DEFINEBITSLOSSLESS2)) { - show = 1; - sprintf(text,"%d", swf_GetDefineID(tag)); - } + if(frame) + printf(" %d Frames: ID(s) 0-%d\n", frame, frame); + else + printf(" 1 Frame: ID(s) 0\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; } + if(!f->layout) + swf_FontCreateLayout(f); + + swf_WriteFont(f, filename); + swf_FontFree(f); } U8*jpegtables = 0; @@ -501,7 +617,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); @@ -598,11 +714,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 { @@ -616,7 +732,7 @@ 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; data2 = malloc(datalen2); @@ -646,8 +762,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 @@ -657,6 +775,7 @@ 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); @@ -674,12 +793,22 @@ void handlelossless(TAG*tag) { data3[pos2++]=0; //filter type if(bpp==32) { - // 32 bit to 24 bit "conversion" - for(x=0;x 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); @@ -722,18 +851,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(filename, "wb"); - logf(" Writing mp3 data to %s",filename); + 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) @@ -749,25 +878,42 @@ void handledefinesound(TAG*tag) 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 - sprintf(buf, "sound%d.mp3", 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")) - filename = "output.mp3"; - } - flags = swf_GetU8(tag); - if((flags>>4)!=2) { - printf("Sorry, can only extract MP3 sounds. Sound %d is ADPCM or RAW.\n", id); - /* not mp3 */ - return; + if(!strcmp(filename,"output.swf")) { + sprintf(buf, "output.%s", extension); + filename = buf; + } } - samples = swf_GetU32(tag); - - swf_GetU16(tag); //(only for mp3) numsamples_seek - fi = save_fopen(filename, "wb"); fwrite(&tag->data[tag->pos], tag->len - tag->pos, 1, fi); fclose(fi); @@ -786,7 +932,7 @@ int main (int argc,char ** argv) processargs(argc, argv); if(!extractframes && !extractids && ! extractname && !extractjpegids && !extractpngids - && !extractmp3 && !extractsoundids) + && !extractmp3 && !extractsoundids && !extractfontids) listavailable = 1; if(!filename) @@ -796,7 +942,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) { @@ -876,6 +1022,9 @@ 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); } @@ -901,6 +1050,7 @@ int main (int argc,char ** argv) found = 1; tagused[tagnum] = 1; depths[swf_GetDepth(tag)] = 1; + extractname_id = id; } } else if(tag->id == ST_SHOWFRAME) {