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