X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=src%2Fswfextract.c;h=35af23f7836f4322e585b12679c4151d03deeacf;hb=1bc632448cd804201098dc4f70700a813d5f6795;hp=131a9a0dccaf8116a95e090451e7e400593cd474;hpb=d68c5b5c60449094852f867d4af3dfbc35c8a74a;p=swftools.git diff --git a/src/swfextract.c b/src/swfextract.c index 131a9a0..35af23f 100644 --- a/src/swfextract.c +++ b/src/swfextract.c @@ -13,7 +13,6 @@ #include "../lib/rfxswf.h" #include "../lib/args.h" #include "../lib/log.h" -#include "reloc.h" #ifdef HAVE_ZLIB_H #ifdef HAVE_LIBZ #include "zlib.h" @@ -28,12 +27,15 @@ int verbose = 3; char* extractids = 0; char* extractframes = 0; char* extractjpegids = 0; +char* extractfontids = 0; char* extractpngids = 0; +char* extractsoundids = 0; char extractmp3 = 0; char* extractname = 0; char hollow = 0; +char originalplaceobjects = 0; int numextracts = 0; @@ -45,9 +47,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} }; @@ -99,10 +104,28 @@ 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"); + exit(1); + } + numextracts++; + extractsoundids = 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++; @@ -115,13 +138,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; @@ -135,16 +162,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"); + 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-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 IDs\t\t\t IDs of the PNG pictures to extract\n"); + 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-f , --frame frames\t\t frame numbers to extract\n"); - printf("\t-w , --hollow\t\t\t hollow mode: don't remove empty frames (use with -f)\n"); - printf("\t-V , --version\t\t\t Print program version and exit\n"); + printf("\t-s , --sound ID\t\t\t Extract Sound(s)\n"); } int args_callback_command(char*name,char*val) { @@ -166,6 +203,7 @@ char used[65536]; TAG*tags[65536]; int changed; char * tagused; +int extractname_id = -1; void idcallback(void*data) { @@ -177,7 +215,7 @@ void idcallback(void*data) void enumerateIDs(TAG*tag, void(*callback)(void*)) { - U8*data; +/* U8*data; int len = tag->len; if(tag->len>=64) { len += 6; @@ -195,6 +233,13 @@ void enumerateIDs(TAG*tag, void(*callback)(void*)) memcpy(&data[2], tag->data, tag->len); } map_ids_mem(data, len, callback); + */ + int num = swf_GetNumUsedIDs(tag); + int *ptr = malloc(sizeof(int)*num); + int t; + swf_GetUsedIDs(tag, ptr); + for(t=0;tdata[ptr[t]]); } void extractTag(SWF*swf, char*filename) @@ -203,6 +248,7 @@ void extractTag(SWF*swf, char*filename) TAG*desttag; TAG*srctag; RGBA rgb; + SRECT objectbbox; char sprite; int f; int t; @@ -221,6 +267,8 @@ 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++) { @@ -256,12 +304,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])) { @@ -287,9 +338,29 @@ 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); @@ -305,9 +376,9 @@ void listObjects(SWF*swf) char first; int t; int frame = 0; - char*names[] = {"Shapes","MovieClips","JPEGs","PNGs","Sounds","Frames"}; + char*names[] = {"Shapes","MovieClips","JPEGs","PNGs","Sounds","Fonts"}; printf("Objects in file %s:\n",filename); - for(t=0;t<6;t++) { + for(t=0;tfirstTag; first = 1; while(tag) { @@ -350,12 +421,11 @@ void listObjects(SWF*swf) sprintf(text,"%d", swf_GetDefineID(tag)); } - if(t == 5 && (tag->id == ST_SHOWFRAME)) { + if(t == 5 && (tag->id == ST_DEFINEFONT || tag->id == ST_DEFINEFONT2)) { show = 1; - sprintf(text,"%d", frame); - frame ++; + sprintf(text,"%d", swf_GetDefineID(tag)); } - + if(show) { if(!first) printf(", "); @@ -369,6 +439,37 @@ void listObjects(SWF*swf) if(!first) printf("\n"); } + + if(frame) + printf("Frames: 0-%d\n", frame); + else + printf("Frames: 0\n"); +} + +void handlefont(SWF*swf, TAG*tag) +{ + SWFFONT* f=0; + U16 id; + char name[80]; + char*filename = name; + int t; + + id = swf_GetDefineID(tag); + sprintf(name, "font%d.swf", id); + if(numextracts==1) { + filename = destfilename; + } + + 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; @@ -411,39 +512,51 @@ int findjpegboundary(U8*data, int len) void handlejpeg(TAG*tag) { char name[80]; + char*filename = name; FILE*fi; - sprintf(name, "pic%d.jpeg", GET16(tag->data)); + + 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"); + fi = save_fopen(filename, "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) 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"); + 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); } - 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"); + 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); + } } #ifdef _ZLIB_INCLUDED_ @@ -510,6 +623,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; @@ -535,8 +649,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); @@ -593,7 +710,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); @@ -685,7 +807,7 @@ void handlesoundstream(TAG*tag) break; case ST_SOUNDSTREAMHEAD2: if((tag->data[1]&0x30) == 0x20) {//mp3 compression - mp3file = fopen("mainstream.mp3", "wb"); + mp3file = fopen(filename, "wb"); logf(" Writing mp3 data to %s",filename); } else @@ -698,6 +820,37 @@ void handlesoundstream(TAG*tag) } } +void handledefinesound(TAG*tag) +{ + U8 flags; + U32 samples; + char buf[128]; + char*filename = buf; + FILE*fi; + U16 id; + id = swf_GetU16(tag); //id + sprintf(buf, "sound%d.mp3", id); + + 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; + } + 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); +} + int main (int argc,char ** argv) { TAG*tag; @@ -711,7 +864,7 @@ int main (int argc,char ** argv) processargs(argc, argv); if(!extractframes && !extractids && ! extractname && !extractjpegids && !extractpngids - && !extractmp3) + && !extractmp3 && !extractsoundids && !extractfontids) listavailable = 1; if(!filename) @@ -787,7 +940,8 @@ 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) @@ -800,9 +954,15 @@ 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); + } #ifdef _ZLIB_INCLUDED_ if(extractpngids && is_in_range(id, extractpngids)) { handlelossless(tag); @@ -822,6 +982,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) {