initial import
@@ -0,0 +1,1430 @@ | ||
1 | +# AsConverter.rb | |
2 | +# SWFからAS3のバイトコードを抽出しAS2に変換するコンバータクラス | |
3 | +# Author:: tmtysk <tmtysk@users.sourceforge.jp> | |
4 | +# Copyright:: Copyright (c) 2007 KLab, Inc. | |
5 | +# License:: Distributes under The BSD License | |
6 | +# Date:: 2007/10/19 | |
7 | + | |
8 | +require 'zlib' | |
9 | + | |
10 | +# AsConverter | |
11 | +class AsConverter | |
12 | + | |
13 | + # namespace定数配列 | |
14 | + NAMESPACE = { | |
15 | + '8' => 'Namespace', | |
16 | + '22' => 'PackageNamespace', | |
17 | + '23' => 'PackageInternalNs', | |
18 | + '24' => 'ProtectedNamespace', | |
19 | + '25' => 'ExplicitNamespace', | |
20 | + '26' => 'StaticProtectedNs', | |
21 | + '5' => 'PrivateNs' | |
22 | + } | |
23 | + | |
24 | + # multiname定数配列 | |
25 | + MULTINAME = { | |
26 | + '7' => 'QName', | |
27 | + '13' => 'QNameA', | |
28 | + '15' => 'RTQName', | |
29 | + '16' => 'RTQNameA', | |
30 | + '17' => 'RTQNameL', | |
31 | + '18' => 'RTQNameLA', | |
32 | + '9' => 'Multiname', | |
33 | + '14' => 'MultinameA', | |
34 | + '27' => 'MultinameL', | |
35 | + '28' => 'MultinameLA' | |
36 | + } | |
37 | + | |
38 | + # vkind定数配列 | |
39 | + VKIND = { | |
40 | + '3' => 'signed_integer', | |
41 | + '4' => 'unsigned_integer', | |
42 | + '6' => 'double', | |
43 | + '1' => 'string', | |
44 | + '8' => 'namespace', | |
45 | + '22' => 'namespace', | |
46 | + '23' => 'namespace', | |
47 | + '24' => 'namespace', | |
48 | + '25' => 'namespace', | |
49 | + '26' => 'namespace', | |
50 | + '5' => 'namespace', | |
51 | + } | |
52 | + | |
53 | + # AbcNameSpace構造体 | |
54 | + AbcNameSpace = Struct.new( | |
55 | + :kind, | |
56 | + :name | |
57 | + ) | |
58 | + | |
59 | + # AbcNsSet構造体 | |
60 | + AbcNsSet = Struct.new( | |
61 | + :nsset | |
62 | + ) | |
63 | + | |
64 | + # AbcMultiname構造体 | |
65 | + AbcMultiname = Struct.new( | |
66 | + :kind, | |
67 | + :ns, | |
68 | + :nsset, | |
69 | + :name | |
70 | + ) | |
71 | + | |
72 | + # AbcMethod構造体 | |
73 | + AbcMethod = Struct.new( | |
74 | + # paramは配列扱い | |
75 | + :param, | |
76 | + :return_type, | |
77 | + :name, | |
78 | + :flags, | |
79 | + :max_stack, | |
80 | + :local_count, | |
81 | + :init_scope_depth, | |
82 | + :max_scope_depth, | |
83 | + :code, | |
84 | + :exception, | |
85 | + # traitは配列扱い | |
86 | + :trait | |
87 | + ) | |
88 | + | |
89 | + # AbcInstance構造体 | |
90 | + AbcInstance = Struct.new( | |
91 | + :name, | |
92 | + :super_name, | |
93 | + :flags, | |
94 | + :protectedNs, | |
95 | + # interfaceは配列扱い | |
96 | + :interface, | |
97 | + :iinit, | |
98 | + # traitは配列扱い | |
99 | + :trait | |
100 | + ) | |
101 | + | |
102 | + # AbcClass構造体 | |
103 | + AbcClass = Struct.new( | |
104 | + :cinit, | |
105 | + # traitは配列扱い | |
106 | + :trait | |
107 | + ) | |
108 | + | |
109 | + # AbcScript構造体 | |
110 | + AbcScript = Struct.new( | |
111 | + :minit, | |
112 | + # traitは配列扱い | |
113 | + :trait | |
114 | + ) | |
115 | + | |
116 | + # AbcTrait構造体 | |
117 | + AbcTrait = Struct.new( | |
118 | + :name, | |
119 | + :kind, | |
120 | + :data, | |
121 | + :metadata | |
122 | + ) | |
123 | + | |
124 | + # コンストラクタ | |
125 | + def initialize | |
126 | + # ヘッド位置 | |
127 | + @head = 0 | |
128 | + # method_body中のcode配列 | |
129 | + @opcode = [] | |
130 | + # 逆アセンブル後のコード(テキスト) | |
131 | + @disassembled_code = "" | |
132 | + # ABC中のsigned integer定数プール | |
133 | + @abcint = [] | |
134 | + # ABC中のunsigned integer定数プール | |
135 | + @abcuint = [] | |
136 | + # ABC中のdouble定数プール | |
137 | + @abcdouble = [] | |
138 | + # ABC中のstring定数プール | |
139 | + @abcstring = [] | |
140 | + # ABC中のnamespace定数プール | |
141 | + @abcnamespace = [AbcNameSpace.new] | |
142 | + # ABC中のnsset定数プール | |
143 | + @abcnsset = [AbcNsSet.new] | |
144 | + # ABC中のmultiname定数プール | |
145 | + @abcmultiname = [AbcMultiname.new] | |
146 | + # ABC中のmethod構造体配列 | |
147 | + @abcmethod = [AbcMethod.new([], nil, nil, nil, nil, nil, nil, nil, nil, nil, [])] | |
148 | + # ABC中のinstance構造体配列 | |
149 | + @abcinstance = [AbcInstance.new(nil, nil, nil, nil, [], nil, [])] | |
150 | + # ABC中のclass構造体配列 | |
151 | + @abcclass = [AbcClass.new(nil, [])] | |
152 | + # ABC中のscript構造体配列 | |
153 | + @abcscript = [AbcScript.new(nil, [])] | |
154 | + # 変換後のAS2で使用する変数名のプール | |
155 | + @as2_varpool = [] | |
156 | + end | |
157 | + | |
158 | + # readSwfFile | |
159 | + # 外部SWFファイルを読み込んでインスタンス変数にバイト列を格納する | |
160 | + # Param:: 読み込むファイル名 | |
161 | + def readSwfFile(filename) | |
162 | + org = open(filename).read | |
163 | + swf = org.unpack("B*").to_s | |
164 | + h = 0 | |
165 | + # ヘッダ部 | |
166 | + ## CWS形式だったらswfを読み込み直す | |
167 | + if swf[h,8].to_i(2).chr == "C" then | |
168 | + swf = org[0,8].unpack("B*").to_s | |
169 | + swf << Zlib::Inflate.inflate(org[8,org.length-8]).unpack("B*").to_s | |
170 | + end | |
171 | + ## 最初の64ビットを無視 | |
172 | + h += 64 | |
173 | + ## RECT構造体 | |
174 | + ### 構造体各要素長さ | |
175 | + rl = swf[h,5].to_i(2) | |
176 | + ### RECT構造体を無視 | |
177 | + h += 5 + (4*rl) | |
178 | + ### padding | |
179 | + h += (8 - h%8) | |
180 | + ## ヘッダの残り32ビットを無視 | |
181 | + h += 32 | |
182 | + | |
183 | + # タグの読み取り開始 | |
184 | + begin | |
185 | + # タグタイプ&長さ取得 | |
186 | + tag_and_length = swf[h+8,8] + swf[h,8] | |
187 | + # EndTagだったら終了 | |
188 | + if (0 == tagid = tag_and_length[0,10].to_i(2)) then break end | |
189 | + | |
190 | + # longタグ対応 | |
191 | + if (63 == l = tag_and_length[10,6].to_i(2)) then | |
192 | + htemp = h + 16 | |
193 | + lstr = "" | |
194 | + 4.times do | |
195 | + lstr = swf[htemp,8] + lstr | |
196 | + htemp += 8 | |
197 | + end | |
198 | + l = lstr.to_i(2) | |
199 | + h += 32 | |
200 | + end | |
201 | + h += 16 | |
202 | + | |
203 | + # タグIDが0x52(DoABC)であればABCとしてインスタンス変数へ格納 | |
204 | + # それ以外は無視 | |
205 | + # DoABCは1回しか出てこないことを期待 | |
206 | + if tagid == 82 then | |
207 | + @abc = swf[h,8*l] | |
208 | + break | |
209 | + end | |
210 | + h += (8*l) | |
211 | + end until h > swf.length | |
212 | + end | |
213 | + | |
214 | + # readAbcFile | |
215 | + # 外部ABCファイルを読み込んでインスタンス変数にバイト列を格納する | |
216 | + # Param:: 読み込むファイル名 | |
217 | + def readAbcFile(filename) | |
218 | + @abc = open(filename).read.unpack("B*").to_s | |
219 | + end | |
220 | + | |
221 | + # getNextBit | |
222 | + # 現在の読み取りヘッドから指定分のビット列(ASCII)を取り出す | |
223 | + # 読み取り後にヘッドを移動する | |
224 | + # Param:: 読み取るビット数 | |
225 | + # Return:: 読み取ったビット列 | |
226 | + def getNextBit(b = 1) | |
227 | + h = @head | |
228 | + @head += b | |
229 | + @abc[h, b] | |
230 | + end | |
231 | + | |
232 | + # getNextByte | |
233 | + # 現在の読み取りヘッドから指定分のバイト列(ASCII)を取り出す | |
234 | + # 読み取り後にヘッドを移動する | |
235 | + # Param:: 読み取るバイト数 | |
236 | + # Return:: 読み取ったバイト列 | |
237 | + def getNextByte(byte = 1) | |
238 | + h = @head | |
239 | + b = byte * 8 | |
240 | + @head += b | |
241 | + @abc[h, b] | |
242 | + end | |
243 | + | |
244 | + # readSwfUI32 | |
245 | + # 現在の読み取りヘッドからUI32データを取り出す | |
246 | + # ABCフォーマットには存在しないが、DoABCタグの読み取りに使う | |
247 | + # Return:: UI32データ(Dec) | |
248 | + def readSwfUI32 | |
249 | + b = "" | |
250 | + 4.times do | |
251 | + b = getNextByte + b | |
252 | + end | |
253 | + b.to_i(2) | |
254 | + end | |
255 | + | |
256 | + # readSwfString | |
257 | + # 現在の読み取りヘッドから有効なStringデータを取り出す | |
258 | + # (NULL(0x00)に当たるまでのデータをそのまま返す | |
259 | + # Return:: String | |
260 | + def readSwfString | |
261 | + str = "" | |
262 | + until (b = getNextByte) == "00000000" do | |
263 | + str += [b].pack("B8") | |
264 | + end | |
265 | + str | |
266 | + end | |
267 | + | |
268 | + # readU8 | |
269 | + # 現在の読み取りヘッドからU8データを取り出す | |
270 | + # Return:: U8データ(Dec) | |
271 | + def readU8 | |
272 | + getNextByte.to_i(2) | |
273 | + end | |
274 | + | |
275 | + # readU16 | |
276 | + # 現在の読み取りヘッドからU16データを取り出す | |
277 | + # Return:: U16データ(Dec) | |
278 | + def readU16 | |
279 | + b = "" | |
280 | + 2.times do | |
281 | + b = getNextByte + b | |
282 | + end | |
283 | + b.to_i(2) | |
284 | + end | |
285 | + | |
286 | + # readS24 | |
287 | + # 現在の読み取りヘッドからS24データを取り出す | |
288 | + # Return:: S24データ(Dec/負数は2の補数表現) | |
289 | + def readS24 | |
290 | + b = "" | |
291 | + i = 0 | |
292 | + 3.times do | |
293 | + b = getNextByte + b | |
294 | + end | |
295 | + if b[0].chr == "1" then | |
296 | + i = - ((b[1,23].to_i(2) ^ ("1"*23).to_i(2)) + 1) | |
297 | + else | |
298 | + i = b.to_i(2) | |
299 | + end | |
300 | + i | |
301 | + end | |
302 | + | |
303 | + # readOpcodeS24 | |
304 | + # @opcodeの先頭からS24データを取り出す | |
305 | + # Return:: S24データ(Dec/負数は2の補数表現) | |
306 | + def readOpcodeS24 | |
307 | + b = "" | |
308 | + i = 0 | |
309 | + 3.times do | |
310 | + b = "%08d" % @opcode.shift.to_i.to_s(2) + b | |
311 | + end | |
312 | + if b[0].chr == "1" then | |
313 | + i = - ((b[1,23].to_i(2) ^ ("1"*23).to_i(2)) + 1) | |
314 | + else | |
315 | + i = b.to_i(2) | |
316 | + end | |
317 | + i | |
318 | + end | |
319 | + | |
320 | + # readU30 | |
321 | + # 現在の読み取りヘッドからU30データを取り出す | |
322 | + # 可変長エンコード: 各バイトの先頭ビットが次のバイトの有無を表す | |
323 | + # 値は各バイト下7ビットで表される | |
324 | + # 最大35ビットとなるが、上位5ビットを削除して扱う(仕様明記無し) | |
325 | + # Return:: U30データ(Dec) | |
326 | + def readU30 | |
327 | + c = 1 | |
328 | + b1 = "" | |
329 | + b2 = "" | |
330 | + begin | |
331 | + b1 = getNextByte | |
332 | + b2 = b1[1,7] + b2 | |
333 | + c = c + 1 | |
334 | + end until (c > 5) or (b1[0].chr == "0") | |
335 | + b2 = b2.slice(5,30) if b2.length > 30 | |
336 | + b2.to_i(2) | |
337 | + end | |
338 | + | |
339 | + # readOpcodeU30 | |
340 | + # @opcodeの先頭からU30データを取り出す | |
341 | + # 可変長エンコード: 各バイトの先頭ビットが次のバイトの有無を表す | |
342 | + # 値は各バイト下7ビットで表される | |
343 | + # 最大35ビットとなるが、上位5ビットを削除して扱う(仕様明記無し) | |
344 | + # Return:: U30データ(Dec) | |
345 | + def readOpcodeU30 | |
346 | + c = 1 | |
347 | + b1 = "" | |
348 | + b2 = "" | |
349 | + begin | |
350 | + b1 = "%08d" % @opcode.shift.to_i.to_s(2) | |
351 | + b2 = b1[1,7] + b2 | |
352 | + c += 1 | |
353 | + end until (c > 5) or (b1[0].chr == "0") | |
354 | + b2 = b2.slice(5,30) if b2.length > 30 | |
355 | + b2.to_i(2) | |
356 | + end | |
357 | + | |
358 | + # readU32 | |
359 | + # 現在の読み取りヘッドからU32データを取り出す | |
360 | + # 可変長エンコード: 各バイトの先頭ビットが次のバイトの有無を表す | |
361 | + # 値は各バイト下7ビットで表される | |
362 | + # 最大35ビットとなるが、上位3ビットを削除して扱う(仕様明記無し) | |
363 | + # Return:: U32データ(Dec) | |
364 | + def readU32 | |
365 | + c = 1 | |
366 | + b1 = "" | |
367 | + b2 = "" | |
368 | + begin | |
369 | + b1 = getNextByte | |
370 | + b2 = b1[1,7] + b2 | |
371 | + c += 1 | |
372 | + end until (c > 5) or (b1[0].chr == "0") | |
373 | + b2 = b2.slice(3,32) if b2.length > 32 | |
374 | + b2.to_i(2) | |
375 | + end | |
376 | + | |
377 | + # readS32 | |
378 | + # 現在の読み取りヘッドからS32データを取り出す | |
379 | + # 可変長エンコード: 各バイトの先頭ビットが次のバイトの有無を表す | |
380 | + # 値は各バイト下7ビットで表される | |
381 | + # 最大35ビットとなるが、上位3ビットを削除して扱う(仕様明記無し) | |
382 | + # Return:: U32データ(Dec/負数は2の補数表現) | |
383 | + def readS32 | |
384 | + c = 1 | |
385 | + i = 0 | |
386 | + b1 = "" | |
387 | + b2 = "" | |
388 | + begin | |
389 | + b1 = getNextByte | |
390 | + b2 = b1[1,7] + b2 | |
391 | + c += 1 | |
392 | + end until (c > 5) or (b1[0].chr == "0") | |
393 | + if b2[0].chr == "1" then | |
394 | + if b2.length > 32 then | |
395 | + b2 = b2.slice(3,32) | |
396 | + i = - ((b2.to_i(2) ^ ("1"*32).to_i(2)) + 1) | |
397 | + else | |
398 | + i = - ((b2[1,b2.length-1].to_i(2) ^ ("1"*(b2.length-1)).to_i(2)) + 1) | |
399 | + end | |
400 | + else | |
401 | + b2 = b2.slice(3,32) if b2.length > 32 | |
402 | + i = b2.to_i(2) | |
403 | + end | |
404 | + i | |
405 | + end | |
406 | + | |
407 | + # readD64 | |
408 | + # 現在の読み取りヘッドからD64データを取り出す | |
409 | + # Return:: D64データ(丸めてしまうと処理系毎に値が変わりそうなので | |
410 | + # とりあえず現時点ではビット列で返す) | |
411 | + def readD64 | |
412 | + b = "" | |
413 | + 8.times do | |
414 | + b = getNextByte + b | |
415 | + end | |
416 | + b | |
417 | + end | |
418 | + | |
419 | + # readString | |
420 | + # 現在の読み取りヘッドからStringデータを取り出す | |
421 | + # 1バイトめで文字列長さ(バイト)を表す | |
422 | + # Return:: Stringデータ | |
423 | + def readString | |
424 | + s = "" | |
425 | + c = getNextByte.to_i(2) | |
426 | + c.times do | |
427 | + s << readU8.chr | |
428 | + end | |
429 | + s | |
430 | + end | |
431 | + | |
432 | + # abc | |
433 | + # 現在読み込み済みのABCビット列を返す | |
434 | + # Return:: ABCビット列 | |
435 | + def abc | |
436 | + @abc | |
437 | + end | |
438 | + | |
439 | + # abc= | |
440 | + # ABCをBASE64 encoded文字列から読み込む | |
441 | + # Param:: ABCをBASE64エンコードした文字列 | |
442 | + def abc=(str) | |
443 | + require 'base64' | |
444 | + @abc = Base64.decode64(str).unpack("B*").to_s | |
445 | + end | |
446 | + | |
447 | + # head | |
448 | + # 現在読み込み済みのABCビット列に対する読み取りヘッド位置を返す | |
449 | + # Return:: 読み取りヘッド位置 | |
450 | + def head | |
451 | + @head | |
452 | + end | |
453 | + | |
454 | + # head= | |
455 | + # 読み取りヘッド位置を変更する | |
456 | + # Return:: 指定ヘッド位置 | |
457 | + def head=(h) | |
458 | + @head = h | |
459 | + end | |
460 | + | |
461 | + # disassembled_code | |
462 | + # 逆アセンブルしたコードを返す | |
463 | + # Return:: 逆アセンブル後のコード | |
464 | + def disassembled_code | |
465 | + @disassembled_code | |
466 | + end | |
467 | + | |
468 | + # disassemble | |
469 | + # 読み込み済みのABCを逆アセンブルする | |
470 | + def disassemble | |
471 | + s = "" | |
472 | + c = 0 | |
473 | + @head = 0 | |
474 | + | |
475 | + # Flags | |
476 | + s << "DoABC_Flags: " + readSwfUI32.to_s + "\n" | |
477 | + # ActionName | |
478 | + s << "DoABC_ActionName: " + readSwfString.to_s + "\n" | |
479 | + # abcFile | |
480 | + s << "abcFile:\n" | |
481 | + ## minor_version | |
482 | + s << "\tminor_version: " + readU16.to_s + "\n" | |
483 | + ## major_version | |
484 | + s << "\tmajor_version: " + readU16.to_s + "\n" | |
485 | + ## cpool_info | |
486 | + s << "\tcpool_info:\n" | |
487 | + ### int_count | |
488 | + c = readU30 | |
489 | + s << "\t\tint_count: " + c.to_s + "\n" | |
490 | + ### signed_integer | |
491 | + (c-1).times do |i| | |
492 | + s32 = readS32 | |
493 | + s << "\t\t\tsigned_integer[" + (i+1).to_s + "]: " + s32.to_s + "\n" | |
494 | + @abcint[i+1] = s32 | |
495 | + end | |
496 | + ### uint_count | |
497 | + c = readU30 | |
498 | + s << "\t\tuint_count: " + c.to_s + "\n" | |
499 | + ### unsigned_integer | |
500 | + (c-1).times do |i| | |
501 | + u32 = readU32 | |
502 | + s << "\t\t\tunsigned_integer[" + (i+1).to_s + "]: " + u32.to_s + "\n" | |
503 | + @abcuint[i+1] = u32 | |
504 | + end | |
505 | + ### double_count | |
506 | + c = readU30 | |
507 | + s << "\t\tdouble_count: " + c.to_s + "\n" | |
508 | + ### double_number | |
509 | + (c-1).times do |i| | |
510 | + d64 = readD64 | |
511 | + s << "\t\t\tdouble_number[" + (i+1).to_s + "]: " + d64.to_s + "\n" | |
512 | + @abcdouble[i+1] = d64 | |
513 | + end | |
514 | + ### string_count | |
515 | + c = readU30 | |
516 | + s << "\t\tstring_count: " + c.to_s + "\n" | |
517 | + ### string | |
518 | + (c-1).times do |i| | |
519 | + str = readString | |
520 | + s << "\t\t\tstring[" + (i+1).to_s + "]: \"" + str.to_s + "\"\n" | |
521 | + @abcstring[i+1] = str.to_s | |
522 | + end | |
523 | + ### namespace_count | |
524 | + c = readU30 | |
525 | + s << "\t\tnamespace_count: " + c.to_s + "\n" | |
526 | + ### namespace | |
527 | + (c-1).times do |i| | |
528 | + u8 = readU8 | |
529 | + u30 = readU30 | |
530 | + s << "\t\t\tnamespace[" + (i+1).to_s + "]: " + NAMESPACE[u8.to_s] + ": string[" + u30.to_s + "]\n" | |
531 | + @abcnamespace[i+1] = AbcNameSpace.new | |
532 | + @abcnamespace[i+1].kind = NAMESPACE[u8.to_s] | |
533 | + @abcnamespace[i+1].name = @abcstring[u30] | |
534 | + end | |
535 | + ### ns_set_count | |
536 | + c = readU30 | |
537 | + s << "\t\tns_set_count: " + c.to_s + "\n" | |
538 | + ### ns_set | |
539 | + (c-1).times do |i| | |
540 | + s << "\t\t\tns_set[" + (i+1).to_s + "]:\n" | |
541 | + @abcnsset[i+1] = AbcNsSet.new | |
542 | + cnt = readU30 | |
543 | + cnt.times do | |
544 | + u30 = readU30 | |
545 | + s << "\t\t\t\tnamespace[" + u30.to_s + "]\n" | |
546 | + @abcnsset[i+1].nsset.push(@abcnamespace[u30]) | |
547 | + end | |
548 | + end | |
549 | + ### multiname_count | |
550 | + c = readU30 | |
551 | + s << "\t\tmultiname_count: " + c.to_s + "\n" | |
552 | + ### multiname | |
553 | + (c-1).times do |i| | |
554 | + k = readU8 | |
555 | + s << "\t\t\tmultiname[" + (i+1).to_s + "]: " + MULTINAME[k.to_s] + ":\n" | |
556 | + @abcmultiname[i+1] = AbcMultiname.new | |
557 | + @abcmultiname[i+1].kind = MULTINAME[k.to_s] | |
558 | + case k | |
559 | + when 7, 13 | |
560 | + ns = readU30 | |
561 | + name = readU30 | |
562 | + s << "\t\t\t\tns: namespace[" + ns.to_s + "]\n" | |
563 | + s << "\t\t\t\tname: string[" + name.to_s + "]\n" | |
564 | + @abcmultiname[i+1].ns = @abcnamespace[ns] | |
565 | + @abcmultiname[i+1].name = @abcstring[name] | |
566 | + when 15, 16 | |
567 | + name = readU30 | |
568 | + s << "\t\t\t\tname: string[" + name.to_s + "]\n" | |
569 | + @abcmultiname[i+1].name = @abcstring[name] | |
570 | + when 17, 18 | |
571 | + s << "\t\t\t\t(no data)\n" | |
572 | + when 9, 14 | |
573 | + name = readU30 | |
574 | + nsset = readU30 | |
575 | + s << "\t\t\t\tname: string[" + name.to_s + "]\n" | |
576 | + s << "\t\t\t\tns_set: ns_set[" + nsset.to_s + "]\n" | |
577 | + @abcmultiname[i+1].name = @abcstring[name] | |
578 | + @abcmultiname[i+1].nsset = @abcnsset[nsset] | |
579 | + when 27, 28 | |
580 | + nsset = readU30 | |
581 | + s << "\t\t\t\tns_set: ns_set[" + nsset.to_s + "]\n" | |
582 | + @abcmultiname[i+1].nsset = @abcnsset[nsset] | |
583 | + end | |
584 | + end | |
585 | + ## method_count | |
586 | + c = readU30 | |
587 | + s << "\tmethod_count: " + c.to_s + "\n" | |
588 | + ## method | |
589 | + c.times do |i| | |
590 | + s << "\tmethod[" + (i+1).to_s + "]:\n" | |
591 | + @abcmethod[i+1] = AbcMethod.new([], nil, nil, nil, nil, nil, nil, nil, nil, nil, []) | |
592 | + cnt = readU30 | |
593 | + s << "\t\tparam_count: " + cnt.to_s + "\n" | |
594 | + return_type = readU30 | |
595 | + s << "\t\treturn_type: multiname[" + return_type.to_s + "]\n" | |
596 | + @abcmethod[i+1].return_type = @abcmultiname[return_type] | |
597 | + cnt.times do |j| | |
598 | + u30 = readU30 | |
599 | + s << "\t\tparam_type[" + (j+1).to_s + "]: multiname[" + u30.to_s + "]\n" | |
600 | + @abcmethod[i+1].param.push(@abcmultiname[u30]) | |
601 | + end | |
602 | + nm = readU30 | |
603 | + s << "\t\tname: string[" + nm.to_s + "]\n" | |
604 | + @abcmethod[i+1].name = @abcstring[nm] | |
605 | + fl = readU8 | |
606 | + s << "\t\tflags: " + fl.to_s + "\n" | |
607 | + @abcmethod[i+1].flags = fl.to_s | |
608 | + if fl & 8 == 8 then | |
609 | + s << "\t\toptions:\n" | |
610 | + optc = readU30 | |
611 | + s << "\t\t\toption_count: " + optc.to_s + "\n" | |
612 | + optc.times do |k| | |
613 | + s << "\t\t\toption_detail[" + (k+1).to_s + "]\n" | |
614 | + s << "\t\t\t\tval: " + readU30.to_s + "\n" | |
615 | + s << "\t\t\t\tkind: " + readU8.to_s + "\n" | |
616 | + end | |
617 | + end | |
618 | + if fl & 128 == 128 then | |
619 | + s << "\t\tparam_names:\n" | |
620 | + cnt.times do |j| | |
621 | + s << "\t\t\tparam_name[" + (j+1).to_s + "]: " + readU30.to_s + "\n" | |
622 | + end | |
623 | + end | |
624 | + end | |
625 | + ## metadata_count | |
626 | + c = readU30 | |
627 | + s << "\tmetadata_count: " + c.to_s + "\n" | |
628 | + ## metadata | |
629 | + c.times do |i| | |
630 | + s << "\tmetadata[" + (i+1).to_s + "]:\n" | |
631 | + s << "\t\tname: string[" + readU30.to_s + "]\n" | |
632 | + cnt = readU30 | |
633 | + s << "\t\titem_count: " + cnt.to_s + "\n" | |
634 | + cnt.times do |j| | |
635 | + s << "\t\titems[" + (j+1).to_s + "]:\n" | |
636 | + s << "\t\t\tkey: string[" + readU30 + "]\n" | |
637 | + s << "\t\t\tvalue: string[" + readU30 + "]\n" | |
638 | + end | |
639 | + end | |
640 | + ## class_count | |
641 | + c = readU30 | |
642 | + s << "\tclass_count: " + c.to_s + "\n" | |
643 | + ## instance | |
644 | + c.times do |i| | |
645 | + s << "\tinstance[" + (i+1).to_s + "]:\n" | |
646 | + @abcinstance[i+1] = AbcInstance.new(nil, nil, nil, nil, [], nil, []) | |
647 | + nm = readU30 | |
648 | + snm = readU30 | |
649 | + s << "\t\tname: multiname[" + nm.to_s + "]\n" | |
650 | + @abcinstance[i+1].name = @abcmultiname[nm] | |
651 | + s << "\t\tsuper_name: multiname[" + snm.to_s + "]\n" | |
652 | + @abcinstance[i+1].super_name = @abcmultiname[snm] | |
653 | + flag = readU8 | |
654 | + s << "\t\tflags: " + flag.to_s + "\n" | |
655 | + @abcinstance[i+1].flags = flag | |
656 | + if flag & 8 == 8 then | |
657 | + u30 = readU30 | |
658 | + s << "\t\tprotectedNs: namespace[" + u30.to_s + "]\n" | |
659 | + @abcinstance[i+1].protectedNs = @abcnamespace[u30] | |
660 | + end | |
661 | + cnt = readU30 | |
662 | + s << "\t\tintrf_count: " + cnt.to_s + "\n" | |
663 | + cnt.times do |j| | |
664 | + u30 = readU30 | |
665 | + s << "\t\tinterface[" + (j+1).to_s + "]: multiname[" + u30.to_s + "]\n" | |
666 | + @abcinstance[i+1].interface.push(@abcmultiname[u30]) | |
667 | + end | |
668 | + u30 = readU30 | |
669 | + s << "\t\tiinit: method[" + u30.to_s + "]\n" | |
670 | + @abcinstance[i+1].iinit = @abcmethod[u30] | |
671 | + trcnt = readU30 | |
672 | + s << "\t\ttrait_count: " + trcnt.to_s + "\n" | |
673 | + trcnt.times do |k| | |
674 | + s << "\t\ttrait[" + (k+1).to_s + "]:\n" | |
675 | + h = readTrait | |
676 | + s << h["str"] | |
677 | + @abcinstance[i+1].trait[k+1] = h["data"] | |
678 | + end | |
679 | + end | |
680 | + ## class | |
681 | + c.times do |i| | |
682 | + s << "\tclass[" + (i+1).to_s + "]:\n" | |
683 | + @abcclass[i+1] = AbcClass.new(nil, []) | |
684 | + u30 = readU30 | |
685 | + s << "\t\tcinit: method[" + u30.to_s + "]\n" | |
686 | + @abcclass[i+1].cinit = @abcmethod[u30] | |
687 | + trcnt = readU30 | |
688 | + s << "\t\ttrait_count: " + trcnt.to_s + "\n" | |
689 | + trcnt.times do |k| | |
690 | + s << "\t\ttrait[" + (k+1).to_s + "]:\n" | |
691 | + h = readTrait | |
692 | + s << h["str"] | |
693 | + @abcclass[i+1].trait[k+1] = h["data"] | |
694 | + end | |
695 | + end | |
696 | + ## script_count | |
697 | + c = readU30 | |
698 | + s << "\tscript_count: " + c.to_s + "\n" | |
699 | + ## script | |
700 | + c.times do |i| | |
701 | + s << "\tscript[" + (i+1).to_s + "]:\n" | |
702 | + @abcscript[i+1] = AbcScript.new(nil, []) | |
703 | + u30 = readU30 | |
704 | + s << "\t\tinit: method[" + u30.to_s + "]\n" | |
705 | + @abcscript[i+1].minit = @abcmethod[u30] | |
706 | + trcnt = readU30 | |
707 | + s << "\t\ttrait_count: " + trcnt.to_s + "\n" | |
708 | + trcnt.times do |k| | |
709 | + s << "\t\ttrait[" + (k+1).to_s + "]:\n" | |
710 | + h = readTrait | |
711 | + s << h["str"] | |
712 | + @abcscript[i+1].trait[k+1] = h["data"] | |
713 | + end | |
714 | + end | |
715 | + ## method_body_count | |
716 | + c = readU30 | |
717 | + s << "\tmethod_body_count: " + c.to_s + "\n" | |
718 | + ## method_body | |
719 | + c.times do |i| | |
720 | + s << "\tmethod_body[" + (i+1).to_s + "]:\n" | |
721 | + method_id = readU30 | |
722 | + s << "\t\tmethod: method[" + method_id.to_s + "]\n" | |
723 | + ms = readU30 | |
724 | + s << "\t\tmax_stack: " + ms.to_s + "\n" | |
725 | + @abcmethod[method_id].max_stack = ms | |
726 | + lc = readU30 | |
727 | + s << "\t\tlocal_count: " + lc.to_s + "\n" | |
728 | + @abcmethod[method_id].local_count = lc | |
729 | + isd = readU30 | |
730 | + s << "\t\tinit_scope_depth: " + isd.to_s + "\n" | |
731 | + @abcmethod[method_id].init_scope_depth = isd | |
732 | + msd = readU30 | |
733 | + s << "\t\tmax_scope_depth: " + msd.to_s + "\n" | |
734 | + @abcmethod[method_id].max_scope_depth = msd | |
735 | + len = readU30 | |
736 | + s << "\t\tcode_length: " + len.to_s + "\n" | |
737 | + s << "\t\tcode:\n" | |
738 | + opcodearr = [] | |
739 | + len.times do | |
740 | + opcodearr.push readU8.to_s | |
741 | + end | |
742 | + opcodes = readInstruct(opcodearr) | |
743 | + s << opcodes | |
744 | + @abcmethod[method_id].code = opcodes | |
745 | + expcnt = readU30 | |
746 | + s << "\t\texception_count: " + expcnt.to_s + "\n" | |
747 | + expcnt.times do |j| | |
748 | + s << "\t\texception[" + (j+1).to_s + "]:\n" | |
749 | + s << "\t\t\tfrom: " + readU30.to_s + "\n" | |
750 | + s << "\t\t\tto: " + readU30.to_s + "\n" | |
751 | + s << "\t\t\ttarget: " + readU30.to_s + "\n" | |
752 | + s << "\t\t\texc_type: string[" + readU30.to_s + "]\n" | |
753 | + s << "\t\t\tvar_name: string[" + readU30.to_s + "]\n" | |
754 | + end | |
755 | + trcnt = readU30 | |
756 | + s << "\t\ttrait_count: " + trcnt.to_s + "\n" | |
757 | + trcnt.times do |k| | |
758 | + s << "\t\ttrait[" + (k+1).to_s + "]:\n" | |
759 | + h = readTrait | |
760 | + s << h["str"] | |
761 | + @abcmethod[method_id].trait[k+1] = h["data"] | |
762 | + end | |
763 | + end | |
764 | + @disassembled_code = s | |
765 | + end | |
766 | + | |
767 | + # readTrait | |
768 | + # 現在のヘッド位置からTrait構造体をダンプし、 | |
769 | + # ダンプ文字列と構造体をセットで返す | |
770 | + # Return:: Trait構造体をダンプした文字列と構造体データ | |
771 | + def readTrait | |
772 | + s = "" | |
773 | + trait = AbcTrait.new | |
774 | + | |
775 | + name = readU30 | |
776 | + s << "\t\t\tname: multiname[" + name.to_s + "]\n" | |
777 | + trait.name = @abcmultiname[name].name | |
778 | + kind = readU8 | |
779 | + s << "\t\t\tkind: " + kind.to_s + "\n" | |
780 | + trait.kind = kind | |
781 | + | |
782 | + data = [] | |
783 | + case kind & 15 | |
784 | + when 0, 6 | |
785 | + s << "\t\t\ttrait_slot:\n" | |
786 | + slot_id = readU30 | |
787 | + s << "\t\t\t\tslot_id: " + slot_id.to_s + "\n" | |
788 | + type_name = readU30 | |
789 | + s << "\t\t\t\ttype_name: multiname[" + type_name.to_s + "]\n" | |
790 | + vi = readU30 | |
791 | + vk = 0 | |
792 | + if vi != 0 then | |
793 | + vk = readU8 | |
794 | + s << "\t\t\t\tvindex: " + VKIND[vk.to_s] + "[" + vi.to_s + "]\n" | |
795 | + end | |
796 | + trait.data = { | |
797 | + 'slot_id' => slot_id, | |
798 | + 'type_name' => type_name, | |
799 | + 'vindex' => vi, | |
800 | + 'vkind' => vk | |
801 | + } | |
802 | + when 4 | |
803 | + s << "\t\t\ttrait_class:\n" | |
804 | + slot_id = readU30 | |
805 | + s << "\t\t\t\tslot_id: " + slot_id.to_s + "\n" | |
806 | + classi = readU30 | |
807 | + s << "\t\t\t\tclassi: instance[" + classi.to_s + "]\n" | |
808 | + trait.data = { | |
809 | + 'slot_id' => slot_id, | |
810 | + 'classi' => @abcinstance[classi] | |
811 | + } | |
812 | + when 5 | |
813 | + s << "\t\t\ttrait_function:\n" | |
814 | + slot_id = readU30 | |
815 | + s << "\t\t\t\tslot_id: " + slot_id.to_s + "\n" | |
816 | + func = readU30 | |
817 | + s << "\t\t\t\tfunction: method[" + func.to_s + "]\n" | |
818 | + trait.data = { | |
819 | + 'slot_id' => slot_id, | |
820 | + 'function' => @abcmethod[func] | |
821 | + } | |
822 | + when 1, 2, 3 | |
823 | + s << "\t\t\ttrait_method:\n" | |
824 | + disp_id = readU30 | |
825 | + s << "\t\t\t\tdisp_id: " + disp_id.to_s + "\n" | |
826 | + meth = readU30 | |
827 | + s << "\t\t\t\tmethod: method[" + meth.to_s + "]\n" | |
828 | + trait.data = { | |
829 | + 'disp_id' => disp_id, | |
830 | + 'method' => @abcmethod[meth] | |
831 | + } | |
832 | + end | |
833 | + r = { | |
834 | + "str" => s, | |
835 | + "data" => trait | |
836 | + } | |
837 | + r | |
838 | + end | |
839 | + | |
840 | + # readInstruct | |
841 | + # 入力した opcode 配列を可読なコードに変換する | |
842 | + # Param:: opcode 配列 | |
843 | + # Return:: 変換後の opcode 文字列 | |
844 | + def readInstruct(opcodearr) | |
845 | + s = "" | |
846 | + @opcode = opcodearr | |
847 | + begin | |
848 | + o = @opcode.shift | |
849 | + case o | |
850 | + when "160" | |
851 | + s << "\t\t\tadd\n" | |
852 | + when "197" | |
853 | + s << "\t\t\tadd_i\n" | |
854 | + when "134" | |
855 | + s << "\t\t\tastype\n" | |
856 | + s << "\t\t\t\tmultiname[" + readOpcodeU30.to_s + "]\n" | |
857 | + when "135" | |
858 | + s << "\t\t\tastypelate\n" | |
859 | + when "168" | |
860 | + s << "\t\t\tbitand\n" | |
861 | + when "151" | |
862 | + s << "\t\t\tbitnot\n" | |
863 | + when "169" | |
864 | + s << "\t\t\tbitor\n" | |
865 | + when "170" | |
866 | + s << "\t\t\tbitxor\n" | |
867 | + when "65" | |
868 | + s << "\t\t\tcall\n" | |
869 | + s << "\t\t\t\targ_count: " + readOpcodeU30.to_s + "\n" | |
870 | + when "67" | |
871 | + s << "\t\t\tcallmethod\n" | |
872 | + s << "\t\t\t\tmethod[" + readOpcodeU30.to_st + "]\n" | |
873 | + s << "\t\t\t\targ_count: " + readOpcodeU30.to_s + "\n" | |
874 | + when "70" | |
875 | + s << "\t\t\tcallproperty\n" | |
876 | + s << "\t\t\t\tmultiname[" + readOpcodeU30.to_s + "]\n" | |
877 | + s << "\t\t\t\targ_count: " + readOpcodeU30.to_s + "\n" | |
878 | + when "76" | |
879 | + s << "\t\t\tcollproplex\n" | |
880 | + s << "\t\t\t\tmultiname[" + readOpcodeU30.to_s + "]\n" | |
881 | + s << "\t\t\t\targ_count: " + readOpcodeU30.to_s + "\n" | |
882 | + when "79" | |
883 | + s << "\t\t\tcallpropvoid\n" | |
884 | + s << "\t\t\t\tmultiname[" + readOpcodeU30.to_s + "]\n" | |
885 | + s << "\t\t\t\targ_count: " + readOpcodeU30.to_s + "\n" | |
886 | + when "68" | |
887 | + s << "\t\t\tcallstatic\n" | |
888 | + s << "\t\t\t\tmethod[" + readOpcodeU30.to_s + "]\n" | |
889 | + s << "\t\t\t\targ_count: " + readOpcodeU30.to_s + "\n" | |
890 | + when "69" | |
891 | + s << "\t\t\tcallsuper\n" | |
892 | + s << "\t\t\t\tmultiname[" + readOpcodeU30.to_s + "]\n" | |
893 | + s << "\t\t\t\targ_count: " + readOpcodeU30.to_s + "\n" | |
894 | + when "78" | |
895 | + s << "\t\t\tcallsupervoid\n" | |
896 | + s << "\t\t\t\tmultiname[" + readOpcodeU30.to_s + "]\n" | |
897 | + s << "\t\t\t\targ_count: " + readOpcodeU30.to_s + "\n" | |
898 | + when "120" | |
899 | + s << "\t\t\tcheckfilter\n" | |
900 | + when "128" | |
901 | + s << "\t\t\tcoerce\n" | |
902 | + s << "\t\t\t\tmultiname[" + readOpcodeU30.to_s + "]\n" | |
903 | + when "130" | |
904 | + s << "\t\t\tcoerce_a\n" | |
905 | + when "133" | |
906 | + s << "\t\t\tcoerce_s\n" | |
907 | + when "66" | |
908 | + s << "\t\t\tconstruct\n" | |
909 | + s << "\t\t\t\targ_count: " + readOpcodeU30.to_s + "\n" | |
910 | + when "74" | |
911 | + s << "\t\t\tconstructprop\n" | |
912 | + s << "\t\t\t\tmultiname[" + readOpcodeU30.to_s + "]\n" | |
913 | + s << "\t\t\t\targ_count: " + readOpcodeU30.to_s + "\n" | |
914 | + when "73" | |
915 | + s << "\t\t\tconstructsuper\n" | |
916 | + s << "\t\t\t\targ_count: " + readOpcodeU30.to_s + "\n" | |
917 | + when "118" | |
918 | + s << "\t\t\tconvert_b\n" | |
919 | + when "115" | |
920 | + s << "\t\t\tconvert_i\n" | |
921 | + when "117" | |
922 | + s << "\t\t\tconvert_d\n" | |
923 | + when "119" | |
924 | + s << "\t\t\tconvert_o\n" | |
925 | + when "116" | |
926 | + s << "\t\t\tconvert_u\n" | |
927 | + when "112" | |
928 | + s << "\t\t\tconvert_s\n" | |
929 | + when "239" | |
930 | + s << "\t\t\tdebug\n" | |
931 | + s << "\t\t\t\tdebug_type: " + @opcode.shift + "\n" | |
932 | + s << "\t\t\t\tstring[" + readOpcodeU30.to_s + "]\n" | |
933 | + s << "\t\t\t\treg: " + @opcode.shift + "\n" | |
934 | + s << "\t\t\t\textra: " + @opcode.shift + "\n" | |
935 | + when "241" | |
936 | + s << "\t\t\tdebugfile\n" | |
937 | + s << "\t\t\t\tstring[" + readOpcodeU30.to_s + "]\n" | |
938 | + when "240" | |
939 | + s << "\t\t\tdebugline\n" | |
940 | + s << "\t\t\t\tlinenum: " + readOpcodeU30.to_s + "\n" | |
941 | + when "148" | |
942 | + s << "\t\t\tdeclocal\n" | |
943 | + s << "\t\t\t\tlocalregister[" + readOpcodeU30.to_s + "]\n" | |
944 | + when "195" | |
945 | + s << "\t\t\tdeclocal_i\n" | |
946 | + s << "\t\t\t\tlocalregister[" + readOpcodeU30.to_s + "]\n" | |
947 | + when "147" | |
948 | + s << "\t\t\tdecrement\n" | |
949 | + when "193" | |
950 | + s << "\t\t\tdecrement_i\n" | |
951 | + when "106" | |
952 | + s << "\t\t\tdeleteproperty\n" | |
953 | + s << "\t\t\t\tmultiname[" + readOpcodeU30.to_s + "]\n" | |
954 | + when "163" | |
955 | + s << "\t\t\tdivide\n" | |
956 | + when "42" | |
957 | + s << "\t\t\tdup\n" | |
958 | + when "6" | |
959 | + s << "\t\t\tdxns\n" | |
960 | + s << "\t\t\t\tstring[" + readOpcodeU30.to_s + "]\n" | |
961 | + when "7" | |
962 | + s << "\t\t\tdxnslate\n" | |
963 | + when "171" | |
964 | + s << "\t\t\tequals\n" | |
965 | + when "114" | |
966 | + s << "\t\t\tesc_xattr\n" | |
967 | + when "113" | |
968 | + s << "\t\t\tesc_xelem\n" | |
969 | + when "94" | |
970 | + s << "\t\t\tfindproperty\n" | |
971 | + s << "\t\t\t\tmultiname[" + readOpcodeU30.to_s + "]\n" | |
972 | + when "93" | |
973 | + s << "\t\t\tfindpropstrict\n" | |
974 | + s << "\t\t\t\tmultiname[" + readOpcodeU30.to_s + "]\n" | |
975 | + when "89" | |
976 | + s << "\t\t\tgetdescendants\n" | |
977 | + s << "\t\t\t\tmultiname[" + readOpcodeU30.to_s + "]\n" | |
978 | + when "100" | |
979 | + s << "\t\t\tgetglobalscope\n" | |
980 | + when "110" | |
981 | + s << "\t\t\tgetglobalslot\n" | |
982 | + s << "\t\t\t\tglobalscope[" + readOpcodeU30.to_s + "]\n" | |
983 | + when "96" | |
984 | + s << "\t\t\tgetlex\n" | |
985 | + s << "\t\t\t\tmultiname[" + readOpcodeU30.to_s + "]\n" | |
986 | + when "98" | |
987 | + s << "\t\t\tgetlocal\n" | |
988 | + s << "\t\t\t\tlocalregister[" + readOpcodeU30.to_s + "]\n" | |
989 | + when "208" | |
990 | + s << "\t\t\tgetlocal_0\n" | |
991 | + when "209" | |
992 | + s << "\t\t\tgetlocal_1\n" | |
993 | + when "210" | |
994 | + s << "\t\t\tgetlocal_2\n" | |
995 | + when "211" | |
996 | + s << "\t\t\tgetlocal_3\n" | |
997 | + when "102" | |
998 | + s << "\t\t\tgetproperty\n" | |
999 | + s << "\t\t\t\tmultiname[" + readOpcodeU30.to_s + "]\n" | |
1000 | + when "101" | |
1001 | + s << "\t\t\tgetscopeobject\n" | |
1002 | + s << "\t\t\t\tscopeobject[" + @opcode.shift + "]\n" | |
1003 | + when "108" | |
1004 | + s << "\t\t\tgetslot\n" | |
1005 | + s << "\t\t\t\tobjectslot[" + readOpcodeU30.to_s + "]\n" | |
1006 | + when "4" | |
1007 | + s << "\t\t\tgetsuper\n" | |
1008 | + s << "\t\t\t\tmultiname[" + readOpcodeU30.to_s + "]\n" | |
1009 | + when "175" | |
1010 | + # graterthan と greaterequals が同じコードになってるので | |
1011 | + # graterthan だけ実装 | |
1012 | + s << "\t\t\tgraterthan\n" | |
1013 | + when "31" | |
1014 | + s << "\t\t\thasnext\n" | |
1015 | + when "50" | |
1016 | + s << "\t\t\thasnext2\n" | |
1017 | + s << "\t\t\t\tobject: localregister[" + @opcode.shift + "]\n" | |
1018 | + s << "\t\t\t\tindex: localregister[" + @opcode.shift + "]\n" | |
1019 | + when "19" | |
1020 | + s << "\t\t\tifeq\n" | |
1021 | + s << "\t\t\t\toffset: " + readOpcodeS24.to_s + "\n" | |
1022 | + when "18" | |
1023 | + s << "\t\t\tiffalse\n" | |
1024 | + s << "\t\t\t\toffset: " + readOpcodeS24.to_s + "\n" | |
1025 | + when "24" | |
1026 | + s << "\t\t\tifge\n" | |
1027 | + s << "\t\t\t\toffset: " + readOpcodeS24.to_s + "\n" | |
1028 | + when "23" | |
1029 | + s << "\t\t\tifgt\n" | |
1030 | + s << "\t\t\t\toffset: " + readOpcodeS24.to_s + "\n" | |
1031 | + when "22" | |
1032 | + s << "\t\t\tifle\n" | |
1033 | + s << "\t\t\t\toffset: " + readOpcodeS24.to_s + "\n" | |
1034 | + when "21" | |
1035 | + s << "\t\t\tiflt\n" | |
1036 | + s << "\t\t\t\toffset: " + readOpcodeS24.to_s + "\n" | |
1037 | + when "15" | |
1038 | + s << "\t\t\tifnge\n" | |
1039 | + when "14" | |
1040 | + s << "\t\t\tifngt\n" | |
1041 | + s << "\t\t\t\toffset: " + readOpcodeS24.to_s + "\n" | |
1042 | + when "13" | |
1043 | + s << "\t\t\tifnle\n" | |
1044 | + s << "\t\t\t\toffset: " + readOpcodeS24.to_s + "\n" | |
1045 | + when "12" | |
1046 | + s << "\t\t\tifnlt\n" | |
1047 | + s << "\t\t\t\toffset: " + readOpcodeS24.to_s + "\n" | |
1048 | + when "20" | |
1049 | + s << "\t\t\tifne\n" | |
1050 | + s << "\t\t\t\toffset: " + readOpcodeS24.to_s + "\n" | |
1051 | + when "24" | |
1052 | + s << "\t\t\tifstricteq\n" | |
1053 | + s << "\t\t\t\toffset: " + readOpcodeS24.to_s + "\n" | |
1054 | + when "25" | |
1055 | + s << "\t\t\tifstrictne\n" | |
1056 | + s << "\t\t\t\toffset: " + readOpcodeS24.to_s + "\n" | |
1057 | + when "17" | |
1058 | + s << "\t\t\tiftrue\n" | |
1059 | + s << "\t\t\t\toffset: " + readOpcodeS24.to_s + "\n" | |
1060 | + when "180" | |
1061 | + s << "\t\t\tin\n" | |
1062 | + when "146" | |
1063 | + s << "\t\t\tinclocal\n" | |
1064 | + s << "\t\t\t\tlocalregister[" + readOpcodeU30.to_s + "]\n" | |
1065 | + when "194" | |
1066 | + s << "\t\t\tinclocal_i\n" | |
1067 | + s << "\t\t\t\tlocalregister[" + readOpcodeU30.to_s + "]\n" | |
1068 | + when "145" | |
1069 | + s << "\t\t\tincrement\n" | |
1070 | + when "192" | |
1071 | + s << "\t\t\tincrement_i\n" | |
1072 | + when "104" | |
1073 | + s << "\t\t\tinitproperty\n" | |
1074 | + s << "\t\t\t\tmultiname[" + readOpcodeU30.to_s + "]\n" | |
1075 | + when "177" | |
1076 | + s << "\t\t\tinstanceof\n" | |
1077 | + when "178" | |
1078 | + s << "\t\t\tistype\n" | |
1079 | + s << "\t\t\t\tmultiname[" + readOpcodeU30.to_s + "]\n" | |
1080 | + when "179" | |
1081 | + s << "\t\t\tistypelate\n" | |
1082 | + when "16" | |
1083 | + s << "\t\t\tjump\n" | |
1084 | + s << "\t\t\t\toffset: " + readOpcodeS24.to_s + "\n" | |
1085 | + when "8" | |
1086 | + s << "\t\t\tkill\n" | |
1087 | + s << "\t\t\t\tlocalregister[" + readOpcodeU30.to_s + "]\n" | |
1088 | + when "9" | |
1089 | + s << "\t\t\tlabel\n" | |
1090 | + when "174" | |
1091 | + s << "\t\t\tlessequals\n" | |
1092 | + when "173" | |
1093 | + s << "\t\t\tlessthan\n" | |
1094 | + when "27" | |
1095 | + s << "\t\t\tlookupswitch\n" | |
1096 | + s << "\t\t\t\tdefault_offset: " + readOpcodeS24.to_s + "\n" | |
1097 | + c = readOpcodeU30 | |
1098 | + s << "\t\t\t\tcase_count: " + c.to_s + "\n" | |
1099 | + (c+1).times do |i| | |
1100 | + s << "\t\t\tcase_offsets[" + (i+1).to_s + "]: " + readOpcodeS24.to_s + "\n" | |
1101 | + end | |
1102 | + when "165" | |
1103 | + s << "\t\t\tlshift\n" | |
1104 | + when "164" | |
1105 | + s << "\t\t\tmodulo\n" | |
1106 | + when "162" | |
1107 | + s << "\t\t\tmultiply\n" | |
1108 | + when "199" | |
1109 | + s << "\t\t\tmultiply_i\n" | |
1110 | + when "144" | |
1111 | + s << "\t\t\tnegate\n" | |
1112 | + when "196" | |
1113 | + s << "\t\t\tnegate_i\n" | |
1114 | + when "87" | |
1115 | + s << "\t\t\tnewactivation\n" | |
1116 | + when "86" | |
1117 | + s << "\t\t\tnewobject\n" | |
1118 | + s << "\t\t\t\targ_count: " + readOpcodeU30.to_s + "\n" | |
1119 | + when "90" | |
1120 | + s << "\t\t\tnewcatch\n" | |
1121 | + s << "\t\t\t\texception[" + readOpcodeU30.to_s + "]\n" | |
1122 | + when "88" | |
1123 | + s << "\t\t\tnewclass\n" | |
1124 | + s << "\t\t\t\tclass[" + readOpcodeU30.to_s + "]\n" | |
1125 | + when "64" | |
1126 | + s << "\t\t\tnewfunction\n" | |
1127 | + s << "\t\t\t\tmethod[" + readOpcodeU30.to_s + "]\n" | |
1128 | + when "85" | |
1129 | + s << "\t\t\tnewobject\n" | |
1130 | + s << "\t\t\t\targ_count: " + readOpcodeU30.to_s + "\n" | |
1131 | + when "30" | |
1132 | + s << "\t\t\tnextname\n" | |
1133 | + when "35" | |
1134 | + s << "\t\t\tnextvalue\n" | |
1135 | + when "2" | |
1136 | + s << "\t\t\tnop\n" | |
1137 | + when "150" | |
1138 | + s << "\t\t\tnot\n" | |
1139 | + when "41" | |
1140 | + s << "\t\t\tpop\n" | |
1141 | + when "29" | |
1142 | + s << "\t\t\tpopscope\n" | |
1143 | + when "36" | |
1144 | + s << "\t\t\tpushbyte\n" | |
1145 | + s << "\t\t\t\tbyte_value: " + @opcode.shift + "\n" | |
1146 | + when "47" | |
1147 | + # 仕様上は 46 となってるけど、それだと pushuint と同じ | |
1148 | + # pushdouble を 47 と見る説が有力 | |
1149 | + s << "\t\t\tpushdouble\n" | |
1150 | + s << "\t\t\t\tdouble[" + readOpcodeU30.to_s + "]\n" | |
1151 | + when "39" | |
1152 | + s << "\t\t\tpushfalse\n" | |
1153 | + when "45" | |
1154 | + s << "\t\t\tpushint\n" | |
1155 | + s << "\t\t\t\tsigned_integer[" + readOpcodeU30.to_s + "]\n" | |
1156 | + when "49" | |
1157 | + s << "\t\t\tpushnamespace\n" | |
1158 | + s << "\t\t\t\tnamespace[" + readOpcodeU30.to_s + "]\n" | |
1159 | + when "40" | |
1160 | + s << "\t\t\tpushnan\n" | |
1161 | + when "32" | |
1162 | + s << "\t\t\tpushnull\n" | |
1163 | + when "48" | |
1164 | + s << "\t\t\tpushscope\n" | |
1165 | + when "37" | |
1166 | + s << "\t\t\tpushshort\n" | |
1167 | + s << "\t\t\t\tshort_value: " + readOpcodeU30.to_s + "\n" | |
1168 | + when "44" | |
1169 | + s << "\t\t\tpushstring\n" | |
1170 | + s << "\t\t\t\tstring[" + readOpcodeU30.to_s + "]\n" | |
1171 | + when "38" | |
1172 | + s << "\t\t\tpushtrue\n" | |
1173 | + when "46" | |
1174 | + s << "\t\t\tpushuint\n" | |
1175 | + s << "\t\t\tunsined_integer[" + readOpcodeU30.to_s + "]\n" | |
1176 | + when "33" | |
1177 | + s << "\t\t\tpushundefined\n" | |
1178 | + when "28" | |
1179 | + s << "\t\t\tpushwith\n" | |
1180 | + when "72" | |
1181 | + s << "\t\t\treturnvalue\n" | |
1182 | + when "71" | |
1183 | + s << "\t\t\treturnvoid\n" | |
1184 | + when "166" | |
1185 | + s << "\t\t\trshift\n" | |
1186 | + when "99" | |
1187 | + s << "\t\t\tsetlocal\n" | |
1188 | + s << "\t\t\t\tlocalregister[" + readOpcodeU30.to_s + "]\n" | |
1189 | + when "212" | |
1190 | + s << "\t\t\tsetlocal_0\n" | |
1191 | + when "213" | |
1192 | + s << "\t\t\tsetlocal_1\n" | |
1193 | + when "214" | |
1194 | + s << "\t\t\tsetlocal_2\n" | |
1195 | + when "215" | |
1196 | + s << "\t\t\tsetlocal_3\n" | |
1197 | + when "111" | |
1198 | + s << "\t\t\tsetglobalslot\n" | |
1199 | + s << "\t\t\t\tglobalscope[" + readOpcodeU30.to_s + "]\n" | |
1200 | + when "97" | |
1201 | + s << "\t\t\tsetproperty\n" | |
1202 | + s << "\t\t\t\tmultiname[" + readOpcodeU30.to_s + "]\n" | |
1203 | + when "109" | |
1204 | + s << "\t\t\tsetslot\n" | |
1205 | + s << "\t\t\t\tobjectslot[" + readOpcodeU30.to_s + "]\n" | |
1206 | + when "5" | |
1207 | + s << "\t\t\tsetsuper\n" | |
1208 | + s << "\t\t\t\tmultiname[" + readOpcodeU30.to_s + "]\n" | |
1209 | + when "172" | |
1210 | + s << "\t\t\tstrictequals\n" | |
1211 | + when "161" | |
1212 | + s << "\t\t\tsubtract\n" | |
1213 | + when "198" | |
1214 | + s << "\t\t\tsubtract_i\n" | |
1215 | + when "43" | |
1216 | + s << "\t\t\tswap\n" | |
1217 | + when "3" | |
1218 | + s << "\t\t\tthrow\n" | |
1219 | + when "149" | |
1220 | + s << "\t\t\ttypeof\n" | |
1221 | + when "167" | |
1222 | + s << "\t\t\turshift\n" | |
1223 | + else | |
1224 | + s << "\t\t\tundefined_instruction: " + o.to_s + "\n" | |
1225 | + end | |
1226 | + end until @opcode.empty? | |
1227 | + s | |
1228 | + end | |
1229 | + | |
1230 | + # toAs2 | |
1231 | + # 読み込んだ ABC を AS2 コードに変換する | |
1232 | + # Return:: 変換後の AS2 コード文字列 | |
1233 | + def toAs2 | |
1234 | + as2 = "class " | |
1235 | + mainclass = "" | |
1236 | + entry_method = [] | |
1237 | + # script 配列の init メソッドを確認し、各行を配列へ突っ込む | |
1238 | + @abcscript[@abcscript.length - 1].minit.code.each_line do |l| | |
1239 | + entry_method.push(l.strip) | |
1240 | + end | |
1241 | + | |
1242 | + # init メソッド中のバイトコードから initproperty を発見し | |
1243 | + # その引数となっているクラスを参照する | |
1244 | + # このクラスがAS2のメインのクラスとなる | |
1245 | + entry_method.each_with_index do |l, i| | |
1246 | + case l | |
1247 | + when "initproperty" | |
1248 | + mainclass = opMultiname(entry_method[i+1]).name | |
1249 | + as2 << mainclass + " {\n\n" | |
1250 | + as2 << " static function main() {\n" | |
1251 | + as2 << " var app:" + mainclass + " = new " + mainclass + "(_root);\n" | |
1252 | + as2 << " }\n\n" | |
1253 | + end | |
1254 | + end | |
1255 | + | |
1256 | + # initproperty されているオブジェクトの trait 構造体を確認する | |
1257 | + # 定義しておくべきプロパティ(メソッド)を先に評価してしまう | |
1258 | + # さらに、initproperty されているオブジェクトの instance 初期化 | |
1259 | + # メソッドを確認する | |
1260 | + # これが mainclass のコンストラクタになる | |
1261 | + constructor = [] | |
1262 | + @abcinstance.each do |instance| | |
1263 | + if instance.name != nil and instance.name.name == mainclass then | |
1264 | + # trait の method があれば、このopcodeを配列に突っ込む | |
1265 | + instance.trait.each_with_index do |trait,i| | |
1266 | + if trait != nil then | |
1267 | + case trait.kind & 15 | |
1268 | + when 1,2,3 | |
1269 | + name = trait.name | |
1270 | + prop = arrayOfOpcode(trait.data["method"]) | |
1271 | + as2 << ppOpcode(prop, name) | |
1272 | + end | |
1273 | + end | |
1274 | + end | |
1275 | + | |
1276 | + # コンストラクタの opcode を配列へつっこむ | |
1277 | + #instance.iinit.code.each_line do |l| | |
1278 | + # constructor.push(l.strip) | |
1279 | + #end | |
1280 | + constructor = arrayOfOpcode(instance.iinit) | |
1281 | + | |
1282 | + #as2 << " function " + mainclass + "() {\n" | |
1283 | + | |
1284 | + # コンストラクタの処理を汎用メソッドにより変換する | |
1285 | + # コンストラクタは引数 "mc" を持つ | |
1286 | + as2 << ppOpcode(constructor, instance.name.name, ["mc"]) | |
1287 | + #as2 << " }\n" | |
1288 | + | |
1289 | + # mainclass 終わり | |
1290 | + as2 << "}\n" | |
1291 | + end | |
1292 | + end | |
1293 | + as2 | |
1294 | + end | |
1295 | + | |
1296 | + # arrayOdOfcode | |
1297 | + # 指定されたメソッドのOpcodeを配列に格納する | |
1298 | + # Param:: Methodの指定子 | |
1299 | + # Return:: Opcodeを格納した配列 | |
1300 | + def arrayOfOpcode(m) | |
1301 | + a = [] | |
1302 | + m.code.each_line do |l| | |
1303 | + a.push(l.strip) | |
1304 | + end | |
1305 | + a | |
1306 | + end | |
1307 | + | |
1308 | + # ppOpcode | |
1309 | + # 読み込んだ Opcode を AS2 コードに変換する | |
1310 | + # 内部で別のメソッドをコールする場合はそのメソッドの Opcode を読み取り | |
1311 | + # 再帰的に処理する | |
1312 | + # Param:: 変換するOpcode | |
1313 | + # Param:: 変換対象のメソッド名 | |
1314 | + # Param:: メソッドに渡される引数 | |
1315 | + # Return:: 変換後の AS2 コード文字列 | |
1316 | + def ppOpcode(opcode, methodName, args = []) | |
1317 | + # 必要なスタック操作の opcode をピックアップし、そこでのスタックの動きを | |
1318 | + # エミュレーションする | |
1319 | + # AS2 のコードに落とせるパターンをピックアップし、スタックを参照しながら | |
1320 | + # コード変換を行う | |
1321 | + # 例) ステージ上で constructprop されているクラスのコンストラクタメソッドを | |
1322 | + # AS2 の _root レシーバが持つメソッドに対応付けて変換する | |
1323 | + | |
1324 | + # 変換後のAS2コード | |
1325 | + opcode_as2 = "" | |
1326 | + | |
1327 | + # operand stack | |
1328 | + st = [] | |
1329 | + | |
1330 | + # scope stack | |
1331 | + sst = ["this"] | |
1332 | + | |
1333 | + # local register | |
1334 | + lreg = ["this"] | |
1335 | + | |
1336 | + # 引数のシリアル化 | |
1337 | + argstr = "" | |
1338 | + args.each_with_index do |a,i| | |
1339 | + argstr << a | |
1340 | + argstr << ", " if i < args.length-1 | |
1341 | + end | |
1342 | + | |
1343 | + # エントリポイントのコンストラクタのときだけは | |
1344 | + # コンテキストを mc 引数にしてやる必要があるぽい | |
1345 | + # それ以外のときは、まだ考えてないけど | |
1346 | + # method 構造体から引数を取得して変数を生成することになると思う | |
1347 | + argstr == "mc" ? ctxt = "mc" : ctxt = "hoge" | |
1348 | + | |
1349 | + opcode_as2 << " function " + methodName + "(" + argstr + ") {\n" | |
1350 | + # TODO: ↑の参照方法だと汎用性に欠ける | |
1351 | + | |
1352 | + opcode.each_with_index do |op, i| | |
1353 | + case op | |
1354 | + when "getlocal_0" | |
1355 | + st.push(lreg[0]) | |
1356 | + when "setlocal_2" | |
1357 | + lreg[2] = st.pop | |
1358 | + when "pushscope" | |
1359 | + sst.push(st.pop) | |
1360 | + when "newactivation" | |
1361 | + # 今のところは、これが何なのかよくわかってない | |
1362 | + st.push("new_activation_object") | |
1363 | + when "dup" | |
1364 | + v = st.pop | |
1365 | + st.push(v) | |
1366 | + st.push(v) | |
1367 | + when "getscopeobject" | |
1368 | + | |
1369 | + when "constructprop" | |
1370 | + case opMultiname(opcode[i+1]).name | |
1371 | + when "TextField" | |
1372 | + v = genVarname | |
1373 | + opcode_as2 << " var " + v + " = " + ctxt + ".createTextField(\"" + v + "\", " + ctxt + ".getNextHighestDepth(), 0, Stage.height/2, Stage.width, Stage.height/2);\n" | |
1374 | + st.push(ctxt + "." + v) | |
1375 | + end | |
1376 | + when "coerce" | |
1377 | + v = st.pop | |
1378 | + # v を opMultiname(opcode[i+1]).name へキャストする処理? | |
1379 | + st.push(v) | |
1380 | + when "pushstring" | |
1381 | + st.push("\"" + opString(opcode[i+1]) + "\"") | |
1382 | + when "setproperty" | |
1383 | + prop = st.pop | |
1384 | + obj = st.pop | |
1385 | + opcode_as2 << " " + obj + "." + opMultiname(opcode[i+1]).name + " = " + prop + ";\n" | |
1386 | + when "callproperty" | |
1387 | + args = [] | |
1388 | + opArgCount(opcode[i+2]).times do | |
1389 | + args.push(st.pop) | |
1390 | + end | |
1391 | + st.push(opMultiname(opcode[i+1]).name + "()") | |
1392 | + when "returnvalue" | |
1393 | + opcode_as2 << " return " + st.pop + ";\n" | |
1394 | + end | |
1395 | + end | |
1396 | + opcode_as2 << " }\n\n" | |
1397 | + opcode_as2 | |
1398 | + end | |
1399 | + | |
1400 | + # genVarname | |
1401 | + # AS2で使用する変数名を生成し、変数名配列へストアする | |
1402 | + # Return:: 生成された変数名 | |
1403 | + def genVarname | |
1404 | + @as2_varpool.push("as2var_aaaaaa") if @as2_varpool.length == 0 | |
1405 | + @as2_varpool.push(@as2_varpool[@as2_varpool.length - 1].succ) | |
1406 | + @as2_varpool[@as2_varpool.length - 1] | |
1407 | + end | |
1408 | + | |
1409 | + # opMultiname | |
1410 | + # opcode中で参照されるmultiname定数を取得する | |
1411 | + # Return:: 参照されているAbcMultiname | |
1412 | + def opMultiname(mn) | |
1413 | + @abcmultiname[(mn.gsub(/multiname\[(\d+)\]/) { $1 }).to_i] | |
1414 | + end | |
1415 | + | |
1416 | + # opString | |
1417 | + # opcode中で参照されるstring定数(文字列)を取得する | |
1418 | + # Return:: 参照されている文字列 | |
1419 | + def opString(str) | |
1420 | + @abcstring[(str.gsub(/string\[(\d+)\]/) { $1 }).to_i] | |
1421 | + end | |
1422 | + | |
1423 | + # opArgCount | |
1424 | + # opcodeが伴う引数の数を取得する | |
1425 | + # Return:: 引数の数 | |
1426 | + def opArgCount(str) | |
1427 | + (str.gsub(/arg_count: (\d+)/) { $1 }).to_i | |
1428 | + end | |
1429 | + | |
1430 | +end |
@@ -0,0 +1,3 @@ | ||
1 | +http://lab.klab.org/modules/mediawiki/index.php/3to2 | |
2 | + | |
3 | +Sorry, Japanese only. |