implemented asset resolving
[swftools.git] / lib / as3 / assets.c
diff --git a/lib/as3/assets.c b/lib/as3/assets.c
new file mode 100644 (file)
index 0000000..06fadd8
--- /dev/null
@@ -0,0 +1,202 @@
+#include <assert.h>
+#include "../rfxswf.h"
+#include "assets.h"
+
+asset_resolver_t* swf_ParseAssets(SWF*swf)
+{
+    NEW(asset_resolver_t,assets);
+    assets->name2asset = dict_new2(&charptr_type);
+    assets->id2asset = malloc(sizeof(abc_asset_t*)*65536);
+
+    TAG*tag = swf->firstTag;
+    while(tag) {
+       if(swf_isDefiningTag(tag)) {
+           NEW(abc_asset_t, asset);
+           list_append(asset->tags, tag);
+           assets->id2asset[swf_GetDefineID(tag)] = asset;
+       }
+       tag = tag->next;
+    }
+
+    tag = swf->firstTag;
+    while(tag) {
+       if(swf_isDefiningTag(tag)) {
+           abc_asset_t*asset = assets->id2asset[swf_GetDefineID(tag)];
+           assert(asset);
+           int num = swf_GetNumUsedIDs(tag);
+           int*positions = malloc(sizeof(int)*num);
+           swf_GetUsedIDs(tag, positions);
+           int t;
+           for(t=0;t<num;t++) {
+               U16 id = GET16(&tag->data[positions[t]]);
+               abc_asset_t*a = assets->id2asset[id];
+               if(!a) {
+                   fprintf(stderr, "Error: ID %d referenced, but not defined\n", id);
+               } else {
+                   list_append(asset->dependencies, a);
+               }
+           }
+       } else if(swf_isPseudoDefiningTag(tag)) {
+           abc_asset_t*asset = assets->id2asset[swf_GetDefineID(tag)];
+           if(asset) {
+               list_append(asset->tags, tag);
+           }
+       } else if(tag->id == ST_SYMBOLCLASS) {
+           int t, num = swf_GetU16(tag);
+           for(t=0;t<num;t++) {
+               U16 id = swf_GetU16(tag);
+               if(!id) {
+                   assets->mainclass_id = id;
+               } else {
+                   abc_asset_t*asset = assets->id2asset[id];
+                   if(!asset) {
+                       fprintf(stderr, "Error: ID %d referenced, but not defined\n", id);
+                   } else {
+                       char*name = swf_GetString(tag);
+                       dict_put(assets->name2asset, name, asset);
+                   }
+               }
+           }
+       }
+       tag = tag->next;
+    }
+    return assets;
+}
+
+void swf_ResolveAssets(asset_resolver_t*assets, abc_file_t*file)
+{
+    int num = assets->name2asset->num;
+    int resolved = 0;
+    int t;
+    for(t=0;t<file->classes->num;t++) {
+       abc_class_t*cls = (abc_class_t*)array_getvalue(file->classes, t);
+       char*fullname = abc_class_fullname(cls);
+       abc_asset_t*a = (abc_asset_t*)dict_lookup(assets->name2asset, fullname);
+       if(a) {
+           resolved++;
+           cls->asset = a;
+       }
+       free(fullname);
+    }
+}
+
+static void dump_asset_list(FILE*fo, abc_asset_list_t*l, const char*prefix)
+{
+    while(l) {
+       TAG_list_t*t = l->abc_asset->tags;
+       while(t) {
+           TAG*tag = t->TAG;
+           fprintf(fo, "%s[tag] %s defines ID %d\n", prefix, swf_TagGetName(tag), swf_GetDefineID(tag));
+           t = t->next;
+       }
+       char*prefix2 = allocprintf("%s    ", prefix);
+       dump_asset_list(fo, l->abc_asset->dependencies, prefix2);
+       free(prefix2);
+       l = l->next;
+    }
+}
+
+void swf_DumpAsset(FILE*fo, abc_asset_t*asset, const char*prefix)
+{
+    abc_asset_list_t*l = 0;
+    list_append(l, asset);
+    dump_asset_list(fo, l, prefix);
+    list_free(l);
+}
+
+static TAG* write_tag(TAG*prev, TAG*tag, dict_t*written)
+{
+    if(!dict_contains(written, tag)) {
+       dict_put(written, tag, 0);
+       if(prev) {
+           prev->next = tag;
+       }
+       tag->prev = prev;
+       tag->next = 0;
+       prev = tag;
+    }
+    return prev;
+}
+static TAG*write_asset(TAG*tag, abc_asset_t*a, dict_t*written)
+{
+    TAG_list_t*tags = a->tags;
+    abc_asset_list_t*deps = a->dependencies;
+    while(deps) {
+       tag = write_asset(tag, deps->abc_asset, written);
+       deps = deps->next;
+    }
+    while(tags) {
+       tag = write_tag(tag, tags->TAG, written);
+       tags = tags->next;
+    }
+    return tag;
+}
+
+void swf_WriteABCSymbols(TAG*tag, abc_file_t*file)
+{
+    int num = 0;
+    int t;
+    for(t=0;t<file->classes->num;t++) {
+       abc_class_t*cls = (abc_class_t*)array_getvalue(file->classes, t);
+       abc_asset_t*a = cls->asset;
+       if(a && a->tags) {
+           num++;
+       }
+    }
+    swf_SetU16(tag, num);
+    for(t=0;t<file->classes->num;t++) {
+       abc_class_t*cls = (abc_class_t*)array_getvalue(file->classes, t);
+       abc_asset_t*a = cls->asset;
+       if(a && a->tags) {
+           U16 id = swf_GetDefineID(a->tags->TAG);
+           char*fullname = abc_class_fullname(cls);
+           swf_SetU16(tag, id);
+           swf_SetString(tag, fullname);
+       }
+    }
+}
+
+TAG*swf_AssetsToTags(TAG*itag, asset_bundle_list_t*assets)
+{
+    char* bitmap = rfx_calloc(sizeof(char)*65536);
+    asset_bundle_list_t*l = assets;
+    dict_t*written = dict_new2(&ptr_type);
+    while(l) {
+       if(l->asset_bundle->used) {
+           abc_file_t*file = l->asset_bundle->file;
+           int t;
+           TAG* tag = 0;
+           for(t=0;t<file->classes->num;t++) {
+               abc_asset_t*a = ((abc_class_t*)array_getvalue(file->classes, t))->asset;
+               if(a) {
+                   tag = write_asset(tag, a, written);
+               }
+           }
+           
+           tag = swf_InsertTag(tag, ST_DOABC);
+           swf_WriteABC(tag, file);
+           tag = swf_InsertTag(tag, ST_SYMBOLCLASS);
+           swf_WriteABCSymbols(tag, file);
+
+           TAG*first = tag;
+           while(first && first->prev) 
+               first=first->prev;
+
+           SWF swf;
+           memset(&swf, 0, sizeof(SWF));
+           swf.firstTag = first;
+           swf_Relocate(&swf, bitmap);
+           if(!itag) {
+               itag = first;
+           } else {
+               itag->next = first;
+               first->prev = itag;
+               itag = tag;
+           }
+       }
+       l = l->next;
+    }
+    dict_destroy(written);
+    free(bitmap);
+    return itag;
+}