* Added support for extracting frames and multiple ids.
authorkramm <kramm>
Sun, 2 Dec 2001 11:49:53 +0000 (11:49 +0000)
committerkramm <kramm>
Sun, 2 Dec 2001 11:49:53 +0000 (11:49 +0000)
* Added -w (--hollow) option.
* Show list of ids if no option given.

src/swfextract.c

index d0b0c6c..005f166 100644 (file)
 char * filename = 0;
 char * destfilename = "output.swf";
 int verbose = 2;
-int extractid = -1;
+
+char* extractids = 0;
+char* extractframes = 0;
+
 char* extractname = 0;
 
+char hollow = 0;
+
 struct options_t options[] =
 {
  {"o","output"},
+ {"w","hollow"},
  {"v","verbose"},
  {"i","id"},
  {"n","name"},
+ {"f","frame"},
  {"V","version"},
  {0,0}
 };
@@ -36,30 +43,38 @@ int args_callback_option(char*name,char*val)
         printf("swfextract - part of %s %s\n", PACKAGE, VERSION);
         exit(0);
     } 
-    if(!strcmp(name, "o")) {
+    else if(!strcmp(name, "o")) {
        destfilename = val;
        return 1;
     } 
-    if(!strcmp(name, "i")) {
-       extractid = atoi(val);
+    else if(!strcmp(name, "i")) {
+       extractids = val;
        if(extractname) {
            fprintf(stderr, "You can only supply either name or id\n");
            exit(1);
        }
        return 1;
     } 
-    if(!strcmp(name, "n")) {
+    else if(!strcmp(name, "n")) {
        extractname = val;
-       if(extractid>=0) {
+       if(extractids) {
            fprintf(stderr, "You can only supply either name or id\n");
            exit(1);
        }
        return 1;
     } 
-    if(!strcmp(name, "v")) {
+    else if(!strcmp(name, "v")) {
        verbose ++;
        return 0;
     } 
+    else if(!strcmp(name, "f")) {
+       extractframes = val;
+       return 1;
+    }
+    else if(!strcmp(name, "w")) {
+       hollow = 1;
+       return 0;
+    }
     else {
         printf("Unknown option: -%s\n", name);
        return 0;
@@ -75,8 +90,11 @@ void args_callback_usage(char*name)
 {    
     printf("Usage: %s [-v] [-i id] 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-i , --id ID\t\t\t ID of the object to extract\n");
-    printf("\t-n , --name name\t\t\t instance name of the object to extract\n");
+    printf("\t-n , --name name\t\t instance name of the object to extract\n");
+    printf("\t-f , --frame frame\t\t frame number to extract\n");
+    printf("\t-w , --hollow\t\t\t hollow mode: don't remove empty frames\n");
     printf("\t-V , --version\t\t\t Print program version and exit\n");
 }
 int args_callback_command(char*name,char*val)
@@ -90,15 +108,21 @@ int args_callback_command(char*name,char*val)
 }
 
 U8 mainr,maing,mainb;
+/* 1 = used, not expanded,
+   3 = used, expanded
+   5 = wanted, not expanded
+   7 = wanted, expanded
+ */
 char used[65536];
 TAG*tags[65536];
 int changed;
+char * tagused;
 
 void idcallback(void*data)
 {
-    if(!used[*(U16*)data]) {
+    if(!(used[*(U16*)data]&1)) {
        changed = 1;
-       used[*(U16*)data] = 1;
+       used[*(U16*)data] |= 1;
     }
 }
 
@@ -121,7 +145,7 @@ void enumerateIDs(TAG*tag, void(*callback)(void*))
     map_ids_mem(data, len, callback);
 }
 
-void extractTag(SWF*swf, int defineid, char*filename)
+void extractTag(SWF*swf, char*filename)
 {
     SWF newswf;
     TAG*desttag;
@@ -130,9 +154,9 @@ void extractTag(SWF*swf, int defineid, char*filename)
     char sprite;
     int f;
     int t;
+    int tagnum;
     int copy = 0;
     memset(&newswf,0x00,sizeof(SWF));        // set global movie parameters
-    memset(used, 0,65536);
 
     newswf.fileVersion    = swf->fileVersion;
     newswf.frameRate      = swf->frameRate;
@@ -145,11 +169,10 @@ void extractTag(SWF*swf, int defineid, char*filename)
     rgb.b = mainb;
     swf_SetRGB(desttag,&rgb);
 
-    used[defineid] = 1;
     do {
        changed = 0;
        for(t=0;t<65536;t++) {
-          if(used[t]==1) {
+          if(used[t] && !(used[t]&2)) {
             if(tags[t]->id==ST_DEFINESPRITE) {
                 TAG*tag = tags[t];
                 while(tag->id != ST_END)
@@ -158,15 +181,17 @@ void extractTag(SWF*swf, int defineid, char*filename)
                     tag = tag->next;
                 }
             }
-            else
-               enumerateIDs(tags[t], idcallback);
-            used[t] = 2;
+            else 
+              enumerateIDs(tags[t], idcallback);
+            used[t] |= 2;
           }
        }
     }
     while(changed);
 
     srctag = swf->firstTag;
+    tagnum = 0;
+    sprite = 0;
     while(srctag && (srctag->id || sprite)) {
        int reset = 0;
        if(!sprite) {
@@ -183,13 +208,19 @@ void extractTag(SWF*swf, int defineid, char*filename)
                copy = 1;
        } else 
        if (((srctag->id == ST_PLACEOBJECT ||
-             srctag->id == ST_PLACEOBJECT2) && swf_GetPlaceID(srctag) == defineid) ||
-             (swf_isPseudoDefiningTag(srctag) && used[swf_GetDefineID(srctag)])) 
+             srctag->id == ST_PLACEOBJECT2 ||
+             srctag->id == ST_STARTSOUND) && (used[swf_GetPlaceID(srctag)]&4) ) ||
+             (swf_isPseudoDefiningTag(srctag) && used[swf_GetDefineID(srctag)]) ||
+             (tagused[tagnum])) 
        {
                if(copy == 0)
                    reset = 1;
                copy = 1;
        } 
+       if(srctag->id == ST_REMOVEOBJECT) {
+           if(!used[swf_GetPlaceID(srctag)])
+               copy = 0;
+       }
 
        if(copy) {
            TAG*ttag = (TAG*)malloc(sizeof(TAG));
@@ -202,8 +233,11 @@ void extractTag(SWF*swf, int defineid, char*filename)
        }
        
        srctag = srctag->next;
+       tagnum ++;
     }
-    desttag = swf_InsertTag(desttag,ST_SHOWFRAME);
+    if(!extractframes && !hollow)
+       desttag = swf_InsertTag(desttag,ST_SHOWFRAME);
+
     desttag = swf_InsertTag(desttag,ST_END);
     
     f = open(filename, O_TRUNC|O_WRONLY|O_CREAT, 0644);
@@ -213,13 +247,87 @@ void extractTag(SWF*swf, int defineid, char*filename)
     swf_FreeTags(&newswf);                       // cleanup
 }
 
+void listObjects(SWF*swf)
+{
+    TAG*tag;
+    char first;
+    int t;
+    int frame = 0;
+    char*names[] = {"Shapes","MovieClips","Bitmaps","Sounds","Frames"};
+    printf("Objects in file %s:\n",filename);
+    for(t=0;t<5;t++) {
+       tag = swf->firstTag;
+       first = 1;
+       while(tag) {
+           char show = 0;
+           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));
+           }
+
+           if(tag->id == ST_DEFINESPRITE) {
+               if (t == 1)  {
+                   show = 1;
+                   sprintf(text,"%d", swf_GetDefineID(tag));
+               }
+
+               while(tag->id != ST_END)
+                   tag = tag->next;
+           }
+
+           if(t == 2 && (tag->id == ST_DEFINEBITSLOSSLESS ||
+               tag->id == ST_DEFINEBITSJPEG2 ||
+               tag->id == ST_DEFINEBITSLOSSLESS2 ||
+               tag->id == ST_DEFINEBITSJPEG3)) {
+               show = 1;
+               sprintf(text,"%d", swf_GetDefineID(tag));
+           }
+
+           if(t == 3 && (tag->id == ST_DEFINESOUND)) {
+               show = 1;
+               sprintf(text,"%d", swf_GetDefineID(tag));
+           }
+           
+           if(t == 4 && (tag->id == ST_SHOWFRAME)) {
+               show = 1;
+               sprintf(text,"%d", frame);
+               frame ++;
+           }
+
+           if(show) {
+               if(!first)
+                   printf(", ");
+               else
+                   printf("%s: ", names[t]);
+               printf("%s", text);
+               first = 0;
+           }
+           tag=tag->next;
+       }
+       if(!first)
+           printf("\n");
+    }
+}
+
 int main (int argc,char ** argv)
 { 
     TAG*tag;
     SWF swf;
     int f;
+    int found = 0;
+    int frame = 0;
+    int tagnum = 0;
+    char depths[65536];
+    char listavailable = 0;
     processargs(argc, argv);
 
+    if(!extractframes && !extractids && ! extractname)
+       listavailable = 1;
+
     if(!filename)
     {
         fprintf(stderr, "You must supply a filename.\n");
@@ -234,19 +342,69 @@ int main (int argc,char ** argv)
         perror("Couldn't open file: ");
         exit(1);
     }
-    if FAILED(swf_ReadSWF(f,&swf))
+    if (swf_ReadSWF(f,&swf) < 0)
     { 
         fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
         close(f);
         exit(1);
     }
+    close(f);
+
+    if(listavailable) {
+       listObjects(&swf);
+       swf_FreeTags(&swf);
+       return 0;
+    }
 
     tag = swf.firstTag;
+    tagnum = 0;
+    while(tag) {
+       tagnum ++;
+       tag = tag->next;
+    }
 
+    tagused = (char*)malloc(tagnum);
+    memset(tagused, 0, tagnum);
+    memset(used, 0, 65536);
+    memset(depths, 0, 65536);
+
+    tag = swf.firstTag;
+    tagnum = 0;
     while(tag) {
+       if(swf_isAllowedSpriteTag(tag)) {
+           int write = 0;
+           if(extractframes && is_in_range(frame, extractframes)) {
+               write = 1;
+               if(tag->id == ST_PLACEOBJECT || tag->id == ST_PLACEOBJECT2) {
+                   depths[swf_GetDepth(tag)] = 1;
+               }
+               if(tag->id == ST_REMOVEOBJECT || tag->id == ST_REMOVEOBJECT2) {
+                   int depth = swf_GetDepth(tag);
+                   if(!depths[depth]) 
+                       write = 0;
+                   depths[swf_GetDepth(tag)] = 0;
+               }
+           } else {
+               if((tag->id == ST_REMOVEOBJECT || tag->id == ST_REMOVEOBJECT2) && 
+                   (depths[swf_GetDepth(tag)]) && hollow) {
+                   write = 1;
+                   depths[swf_GetDepth(tag)] = 0;
+               }
+           }
+           if(write) {
+               enumerateIDs(tag, idcallback);
+               found = 1;
+               tagused[tagnum] = 1;
+           }
+       }
+
        if(swf_isDefiningTag(tag)) {
            int id = swf_GetDefineID(tag);
            tags[id] = tag;
+           if(extractids && is_in_range(id, extractids)) {
+               used[id] = 5;
+               found = 1;
+           }
        }
        else if (tag->id == ST_SETBACKGROUNDCOLOR) {
            mainr = tag->data[0];
@@ -257,17 +415,31 @@ int main (int argc,char ** argv)
            char*name = swf_GetName(tag);
            if(name && extractname && !strcmp(name, extractname)) {
                int id = swf_GetPlaceID(tag); 
-               if(extractid>=0 && id != extractid) {
-                   fprintf(stderr, "Error: More than one instance with name \"%s\"", name);
-                   exit(1);
-               }
-               extractid = swf_GetPlaceID(tag); 
+               used[id] = 5;
+               found = 1;
+               tagused[tagnum] = 1;
+               depths[swf_GetDepth(tag)] = 1;
+           }
+       }
+       else if(tag->id == ST_SHOWFRAME) {
+           frame ++;
+           if(hollow) {
+               tagused[tagnum] = 1;
+               found = 1;
+           }
+       }
+       
+       if(tag->id == ST_DEFINESPRITE) {
+           while(tag->id != ST_END) { 
+               tag = tag->next;
+               tagnum ++;
            }
        }
        tag = tag->next;
+       tagnum ++;
     }
-    if(tags[extractid])
-       extractTag(&swf, extractid, destfilename);
+    if (found)
+       extractTag(&swf, destfilename);
 
     swf_FreeTags(&swf);
     return 0;