implemented asset resolving
[swftools.git] / lib / as3 / assets.c
1 #include <assert.h>
2 #include "../rfxswf.h"
3 #include "assets.h"
4
5 asset_resolver_t* swf_ParseAssets(SWF*swf)
6 {
7     NEW(asset_resolver_t,assets);
8     assets->name2asset = dict_new2(&charptr_type);
9     assets->id2asset = malloc(sizeof(abc_asset_t*)*65536);
10
11     TAG*tag = swf->firstTag;
12     while(tag) {
13         if(swf_isDefiningTag(tag)) {
14             NEW(abc_asset_t, asset);
15             list_append(asset->tags, tag);
16             assets->id2asset[swf_GetDefineID(tag)] = asset;
17         }
18         tag = tag->next;
19     }
20
21     tag = swf->firstTag;
22     while(tag) {
23         if(swf_isDefiningTag(tag)) {
24             abc_asset_t*asset = assets->id2asset[swf_GetDefineID(tag)];
25             assert(asset);
26             int num = swf_GetNumUsedIDs(tag);
27             int*positions = malloc(sizeof(int)*num);
28             swf_GetUsedIDs(tag, positions);
29             int t;
30             for(t=0;t<num;t++) {
31                 U16 id = GET16(&tag->data[positions[t]]);
32                 abc_asset_t*a = assets->id2asset[id];
33                 if(!a) {
34                     fprintf(stderr, "Error: ID %d referenced, but not defined\n", id);
35                 } else {
36                     list_append(asset->dependencies, a);
37                 }
38             }
39         } else if(swf_isPseudoDefiningTag(tag)) {
40             abc_asset_t*asset = assets->id2asset[swf_GetDefineID(tag)];
41             if(asset) {
42                 list_append(asset->tags, tag);
43             }
44         } else if(tag->id == ST_SYMBOLCLASS) {
45             int t, num = swf_GetU16(tag);
46             for(t=0;t<num;t++) {
47                 U16 id = swf_GetU16(tag);
48                 if(!id) {
49                     assets->mainclass_id = id;
50                 } else {
51                     abc_asset_t*asset = assets->id2asset[id];
52                     if(!asset) {
53                         fprintf(stderr, "Error: ID %d referenced, but not defined\n", id);
54                     } else {
55                         char*name = swf_GetString(tag);
56                         dict_put(assets->name2asset, name, asset);
57                     }
58                 }
59             }
60         }
61         tag = tag->next;
62     }
63     return assets;
64 }
65
66 void swf_ResolveAssets(asset_resolver_t*assets, abc_file_t*file)
67 {
68     int num = assets->name2asset->num;
69     int resolved = 0;
70     int t;
71     for(t=0;t<file->classes->num;t++) {
72         abc_class_t*cls = (abc_class_t*)array_getvalue(file->classes, t);
73         char*fullname = abc_class_fullname(cls);
74         abc_asset_t*a = (abc_asset_t*)dict_lookup(assets->name2asset, fullname);
75         if(a) {
76             resolved++;
77             cls->asset = a;
78         }
79         free(fullname);
80     }
81 }
82
83 static void dump_asset_list(FILE*fo, abc_asset_list_t*l, const char*prefix)
84 {
85     while(l) {
86         TAG_list_t*t = l->abc_asset->tags;
87         while(t) {
88             TAG*tag = t->TAG;
89             fprintf(fo, "%s[tag] %s defines ID %d\n", prefix, swf_TagGetName(tag), swf_GetDefineID(tag));
90             t = t->next;
91         }
92         char*prefix2 = allocprintf("%s    ", prefix);
93         dump_asset_list(fo, l->abc_asset->dependencies, prefix2);
94         free(prefix2);
95         l = l->next;
96     }
97 }
98
99 void swf_DumpAsset(FILE*fo, abc_asset_t*asset, const char*prefix)
100 {
101     abc_asset_list_t*l = 0;
102     list_append(l, asset);
103     dump_asset_list(fo, l, prefix);
104     list_free(l);
105 }
106
107 static TAG* write_tag(TAG*prev, TAG*tag, dict_t*written)
108 {
109     if(!dict_contains(written, tag)) {
110         dict_put(written, tag, 0);
111         if(prev) {
112             prev->next = tag;
113         }
114         tag->prev = prev;
115         tag->next = 0;
116         prev = tag;
117     }
118     return prev;
119 }
120 static TAG*write_asset(TAG*tag, abc_asset_t*a, dict_t*written)
121 {
122     TAG_list_t*tags = a->tags;
123     abc_asset_list_t*deps = a->dependencies;
124     while(deps) {
125         tag = write_asset(tag, deps->abc_asset, written);
126         deps = deps->next;
127     }
128     while(tags) {
129         tag = write_tag(tag, tags->TAG, written);
130         tags = tags->next;
131     }
132     return tag;
133 }
134
135 void swf_WriteABCSymbols(TAG*tag, abc_file_t*file)
136 {
137     int num = 0;
138     int t;
139     for(t=0;t<file->classes->num;t++) {
140         abc_class_t*cls = (abc_class_t*)array_getvalue(file->classes, t);
141         abc_asset_t*a = cls->asset;
142         if(a && a->tags) {
143             num++;
144         }
145     }
146     swf_SetU16(tag, num);
147     for(t=0;t<file->classes->num;t++) {
148         abc_class_t*cls = (abc_class_t*)array_getvalue(file->classes, t);
149         abc_asset_t*a = cls->asset;
150         if(a && a->tags) {
151             U16 id = swf_GetDefineID(a->tags->TAG);
152             char*fullname = abc_class_fullname(cls);
153             swf_SetU16(tag, id);
154             swf_SetString(tag, fullname);
155         }
156     }
157 }
158
159 TAG*swf_AssetsToTags(TAG*itag, asset_bundle_list_t*assets)
160 {
161     char* bitmap = rfx_calloc(sizeof(char)*65536);
162     asset_bundle_list_t*l = assets;
163     dict_t*written = dict_new2(&ptr_type);
164     while(l) {
165         if(l->asset_bundle->used) {
166             abc_file_t*file = l->asset_bundle->file;
167             int t;
168             TAG* tag = 0;
169             for(t=0;t<file->classes->num;t++) {
170                 abc_asset_t*a = ((abc_class_t*)array_getvalue(file->classes, t))->asset;
171                 if(a) {
172                     tag = write_asset(tag, a, written);
173                 }
174             }
175             
176             tag = swf_InsertTag(tag, ST_DOABC);
177             swf_WriteABC(tag, file);
178             tag = swf_InsertTag(tag, ST_SYMBOLCLASS);
179             swf_WriteABCSymbols(tag, file);
180
181             TAG*first = tag;
182             while(first && first->prev) 
183                 first=first->prev;
184
185             SWF swf;
186             memset(&swf, 0, sizeof(SWF));
187             swf.firstTag = first;
188             swf_Relocate(&swf, bitmap);
189             if(!itag) {
190                 itag = first;
191             } else {
192                 itag->next = first;
193                 first->prev = itag;
194                 itag = tag;
195             }
196         }
197         l = l->next;
198     }
199     dict_destroy(written);
200     free(bitmap);
201     return itag;
202 }