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