implemented .swc import
[swftools.git] / lib / as3 / import.c
index 59dbac0..df0271e 100644 (file)
 #include "tokenizer.h"
 #include "assets.h"
 #include "../os.h"
+#include "../xml.h"
+#ifdef HAVE_ZZIP
+#include "zzip/lib.h"
+#endif
 
 static void import_code(void*_abc, char*filename, int pass, asset_bundle_t*a);
 
@@ -43,10 +47,15 @@ void as3_import_abc(char*filename)
     free(tag);
 }
 
-void as3_import_swf(char*filename)
+typedef struct _deps {
+    const char*name;
+    struct _deps*next;
+} deps_t;
+
+void as3_import_swf2(reader_t*r, char*filename, dict_t*deps)
 {
-    SWF* swf = swf_OpenSWF(filename);
-    if(!swf)
+    SWF _swf,*swf=&_swf;
+    if(swf_ReadSWF2(r, &_swf)<0)
         return;
     swf_FoldAll(swf);
 
@@ -54,34 +63,177 @@ void as3_import_swf(char*filename)
 
     asset_resolver_t* assets =  swf_ParseAssets(swf);
 
+    asset_bundle_list_t* asset_bundles = list_new();
+
+    dict_t*name2bundle = dict_new();
     /* pass 1 */
     while(tag) {
         if(tag->id == ST_DOABC || tag->id == ST_RAWABC) {
             abc_file_t*abc = swf_ReadABC(tag);
             import_code(abc, filename, 0, 0);
-            swf_FreeABC(abc);
+           NEW(asset_bundle_t, a);
+           a->file = abc;
+           if(abc->name) {
+               dict_put(name2bundle, abc->name, a);
+           }
+           list_append(asset_bundles, a);
         }
         tag = tag->next;
     }
 
     tag = swf->firstTag;
+    asset_bundle_list_t*b = asset_bundles;
     /* pass 2 */
     while(tag) {
         if(tag->id == ST_DOABC || tag->id == ST_RAWABC) {
-            abc_file_t*abc = swf_ReadABC(tag); //FIXME: mem leak
+           asset_bundle_t*a = b->asset_bundle;
+           abc_file_t*abc = a->file;
            swf_ResolveAssets(assets, abc);
-           NEW(asset_bundle_t, a);
-           a->file = abc;
+           if(deps && abc->name) {
+               deps_t*d = dict_lookup(deps, abc->name);
+               while(d) {
+                   if(d->name) {
+                       asset_bundle_t*other = dict_lookup(name2bundle, d->name);
+                       list_append(a->dependencies, other);
+                   }
+                   d = d->next;
+               }
+           }
            registry_add_asset(a);
             import_code(abc, filename, 1, a);
+           b=b->next;
         }
         tag = tag->next;
     }
 
+    dict_destroy(name2bundle);
+    list_free(asset_bundles);
+
     //swf_FreeTags(swf); // FIXME: mem leak
-    free(swf);
+}
+
+void as3_import_swf(char*filename)
+{
+    reader_t reader;
+    reader_init_filereader2(&reader, filename);
+    as3_import_swf2(&reader, filename, 0);
+    reader.dealloc(&reader);
+}
+
+#ifdef HAVE_ZZIP
+typedef struct _catalog_state {
+    char*xml_filename;
+    char in_libraries;
+    char*library;
+    char*script;
+    dict_t*deps;
+    deps_t*current_deps;
+    dict_t*name2deps;
+    dict_t*id2script;
+    ZZIP_DIR*dir;
+} catalog_state_t;
+
+const char* fa(catalog_state_t*state, xmlattribute_t*attr, const char*name)
+{
+    while(attr) {
+       if(!strcmp(attr->name, name)) return attr->value;
+       attr = attr->next;
+    }
+    syntaxerror("error parsing %s: attribute %s missing", state->xml_filename, name);
+}
 
+void catalog_start_tag(xmlconsumer_t*c, char*name, xmlattribute_t*attr)
+{
+    catalog_state_t*state = (catalog_state_t*)c->internal;
+    if(!strcmp(name, "libraries")) {
+       state->in_libraries = 1;
+    } else if(!strcmp(name, "library")) {
+       state->library = strdup(fa(state, attr, "path"));
+    } else if(!strcmp(name, "script")) {
+       state->script = strdup(fa(state, attr, "name"));
+    } else if(!strcmp(name, "def")) {
+       dict_put(state->id2script, strdup(fa(state, attr, "id")), strdup(state->script));
+    } else if(!strcmp(name, "dep")) {
+       NEW(deps_t,d);
+       d->name = strdup(fa(state, attr, "id"));
+       d->next = state->current_deps;
+       state->current_deps = d;
+    }
+}
+void catalog_data(xmlconsumer_t*c, char*data, int len)
+{
+    catalog_state_t*state = (catalog_state_t*)c->internal;
+}
+void catalog_end_tag(xmlconsumer_t*c, char*name)
+{
+    catalog_state_t*state = (catalog_state_t*)c->internal;
+    if(!strcmp(name, "libraries")) {
+       state->in_libraries = 0;
+    } else if(!strcmp(name, "library")) {
+       ZZIP_FILE*file = zzip_file_open(state->dir, state->library, 0);
+
+       DICT_ITERATE_DATA(state->deps,deps_t*,deps) {
+           while(deps) {
+               char*script = dict_lookup(state->id2script, deps->name);
+               if(!script) {
+                   //as3_warning("when importing %s: depencency %s referenced in catalog.xml, but not found.", state->xml_filename, deps->name);
+               }
+               deps->name = script;
+               deps = deps->next;
+           }
+       }
+
+       if(!file) {
+           as3_warning("when importing %s: %s referenced in catalog.xml, but not found.", state->xml_filename, state->library);
+       } else {
+           reader_t r;
+           reader_init_zzipreader(&r, file);
+           as3_import_swf2(&r, state->library, state->deps);
+           r.dealloc(&r);
+           zzip_file_close(file);
+       }
+       dict_destroy(state->deps);
+       state->deps = 0;
+       free(state->library);
+       state->library = 0;
+    } else if(!strcmp(name, "script")) {
+       dict_put(state->deps, state->script, state->current_deps);
+       free(state->script);
+       state->current_deps = 0;
+       state->script = 0;
+    }
+}
+void as3_import_zipfile(char*filename)
+{
+    ZZIP_DIR*dir = zzip_opendir(filename);
+    if(!dir) as3_error("Error reading %s\n", filename);
+    ZZIP_FILE*file = zzip_file_open(dir, "catalog.xml", 0);
+    reader_t r;
+    reader_init_zzipreader(&r, file);
+
+    xmlconsumer_t c;
+    catalog_state_t state;
+    memset(&state, 0, sizeof(state));
+    state.dir = dir;
+    state.xml_filename = filename;
+    state.name2deps = dict_new();
+    state.id2script = dict_new();
+    state.deps = dict_new();
+    c.start_tag = catalog_start_tag;
+    c.data= catalog_data;
+    c.end_tag = catalog_end_tag;
+    c.internal = &state;
+
+    xml_parse(&r, &c);
+
+    r.dealloc(&r);
+}
+#else
+void as3_import_zipfile(char*filename)
+{
+    as3_warning("No zipfile support compiled in- can't import %s\n", filename);
 }
+#endif
 
 void as3_import_file(char*filename)
 {
@@ -93,6 +245,8 @@ void as3_import_file(char*filename)
     if(!strncmp(head, "FWS", 3) ||
        !strncmp(head, "CWS", 3)) {
         as3_import_swf(filename);
+    } else if(!strncmp(head, "PK", 2)) {
+       as3_import_zipfile(filename);
     } else {
         as3_import_abc(filename);
     }