• R/O
  • SSH
  • HTTPS

asc3to2: 提交


Commit MetaInfo

修订版1 (tree)
时间2007-12-27 15:58:51
作者tmtysk

Log Message

initial import

更改概述

差异

--- AsConverter.rb (nonexistent)
+++ AsConverter.rb (revision 1)
@@ -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
--- README (nonexistent)
+++ README (revision 1)
@@ -0,0 +1,3 @@
1+http://lab.klab.org/modules/mediawiki/index.php/3to2
2+
3+Sorry, Japanese only.
Show on old repository browser