зеркало из https://github.com/mozilla/gecko-dev.git
1661 строка
42 KiB
ActionScript
1661 строка
42 KiB
ActionScript
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
|
* "License"); you may not use this file except in compliance with the License. You may obtain
|
|
* a copy of the License at http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
|
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
|
* language governing rights and limitations under the License.
|
|
*
|
|
* The Original Code is [Open Source Virtual Machine.]
|
|
*
|
|
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
|
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
|
* Reserved.
|
|
*
|
|
* Contributor(s): Adobe AS3 Team
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
|
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
|
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
|
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
|
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
|
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
|
* above and replace them with the notice and other provisions required by the GPL or the
|
|
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
|
* under the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
package abcdump
|
|
{
|
|
import flash.utils.ByteArray
|
|
import avmplus.System
|
|
|
|
const TAB = " "
|
|
|
|
// method flags
|
|
const NEED_ARGUMENTS:int = 0x01
|
|
const NEED_ACTIVATION:int = 0x02
|
|
const NEED_REST:int = 0x04
|
|
const HAS_OPTIONAL:int = 0x08
|
|
const IGNORE_REST:int = 0x10
|
|
const NATIVE:int = 0x20
|
|
const HAS_ParamNames:int = 0x80
|
|
|
|
const CONSTANT_Utf8 :int = 0x01
|
|
const CONSTANT_Int :int = 0x03
|
|
const CONSTANT_UInt :int = 0x04
|
|
const CONSTANT_PrivateNs :int = 0x05 // non-shared namespace
|
|
const CONSTANT_Double :int = 0x06
|
|
const CONSTANT_Qname :int = 0x07 // o.ns::name, ct ns, ct name
|
|
const CONSTANT_Namespace :int = 0x08
|
|
const CONSTANT_Multiname :int = 0x09 // o.name, ct nsset, ct name
|
|
const CONSTANT_False :int = 0x0A
|
|
const CONSTANT_True :int = 0x0B
|
|
const CONSTANT_Null :int = 0x0C
|
|
const CONSTANT_QnameA :int = 0x0D // o.@ns::name, ct ns, ct attr-name
|
|
const CONSTANT_MultinameA :int = 0x0E // o.@name, ct attr-name
|
|
const CONSTANT_RTQname :int = 0x0F // o.ns::name, rt ns, ct name
|
|
const CONSTANT_RTQnameA :int = 0x10 // o.@ns::name, rt ns, ct attr-name
|
|
const CONSTANT_RTQnameL :int = 0x11 // o.ns::[name], rt ns, rt name
|
|
const CONSTANT_RTQnameLA :int = 0x12 // o.@ns::[name], rt ns, rt attr-name
|
|
const CONSTANT_NameL :int = 0x13 // o.[], ns=public implied, rt name
|
|
const CONSTANT_NameLA :int = 0x14 // o.@[], ns=public implied, rt attr-name
|
|
const CONSTANT_NamespaceSet :int = 0x15
|
|
const CONSTANT_PackageNs :int = 0x16
|
|
const CONSTANT_PackageInternalNs :int = 0x17
|
|
const CONSTANT_ProtectedNs :int = 0x18
|
|
const CONSTANT_StaticProtectedNs :int = 0x19
|
|
const CONSTANT_StaticProtectedNs2 :int = 0x1a
|
|
const CONSTANT_MultinameL :int = 0x1B
|
|
const CONSTANT_MultinameLA :int = 0x1C
|
|
|
|
const constantKinds:Array = [ "0", "utf8", "2",
|
|
"int", "uint", "private", "double", "qname", "namespace",
|
|
"multiname", "false", "true", "null", "@qname", "@multiname", "rtqname",
|
|
"@rtqname", "[qname]", "@[qname]", "[name]", "@[name]", "nsset"
|
|
]
|
|
|
|
const TRAIT_Slot :int = 0x00
|
|
const TRAIT_Method :int = 0x01
|
|
const TRAIT_Getter :int = 0x02
|
|
const TRAIT_Setter :int = 0x03
|
|
const TRAIT_Class :int = 0x04
|
|
const TRAIT_Function :int = 0x05
|
|
const TRAIT_Const :int = 0x06
|
|
|
|
const traitKinds:Array = [
|
|
"var", "function", "function get", "function set", "class", "function", "const"
|
|
]
|
|
|
|
const OP_bkpt:int = 0x01
|
|
const OP_nop:int = 0x02
|
|
const OP_throw:int = 0x03
|
|
const OP_getsuper:int = 0x04
|
|
const OP_setsuper:int = 0x05
|
|
const OP_dxns:int = 0x06
|
|
const OP_dxnslate:int = 0x07
|
|
const OP_kill:int = 0x08
|
|
const OP_label:int = 0x09
|
|
const OP_ifnlt:int = 0x0C
|
|
const OP_ifnle:int = 0x0D
|
|
const OP_ifngt:int = 0x0E
|
|
const OP_ifnge:int = 0x0F
|
|
const OP_jump:int = 0x10
|
|
const OP_iftrue:int = 0x11
|
|
const OP_iffalse:int = 0x12
|
|
const OP_ifeq:int = 0x13
|
|
const OP_ifne:int = 0x14
|
|
const OP_iflt:int = 0x15
|
|
const OP_ifle:int = 0x16
|
|
const OP_ifgt:int = 0x17
|
|
const OP_ifge:int = 0x18
|
|
const OP_ifstricteq:int = 0x19
|
|
const OP_ifstrictne:int = 0x1A
|
|
const OP_lookupswitch:int = 0x1B
|
|
const OP_pushwith:int = 0x1C
|
|
const OP_popscope:int = 0x1D
|
|
const OP_nextname:int = 0x1E
|
|
const OP_hasnext:int = 0x1F
|
|
const OP_pushnull:int = 0x20
|
|
const OP_pushundefined:int = 0x21
|
|
const OP_pushconstant:int = 0x22
|
|
const OP_nextvalue:int = 0x23
|
|
const OP_pushbyte:int = 0x24
|
|
const OP_pushshort:int = 0x25
|
|
const OP_pushtrue:int = 0x26
|
|
const OP_pushfalse:int = 0x27
|
|
const OP_pushnan:int = 0x28
|
|
const OP_pop:int = 0x29
|
|
const OP_dup:int = 0x2A
|
|
const OP_swap:int = 0x2B
|
|
const OP_pushstring:int = 0x2C
|
|
const OP_pushint:int = 0x2D
|
|
const OP_pushuint:int = 0x2E
|
|
const OP_pushdouble:int = 0x2F
|
|
const OP_pushscope:int = 0x30
|
|
const OP_pushnamespace:int = 0x31
|
|
const OP_hasnext2:int = 0x32
|
|
const OP_newfunction:int = 0x40
|
|
const OP_call:int = 0x41
|
|
const OP_construct:int = 0x42
|
|
const OP_callmethod:int = 0x43
|
|
const OP_callstatic:int = 0x44
|
|
const OP_callsuper:int = 0x45
|
|
const OP_callproperty:int = 0x46
|
|
const OP_returnvoid:int = 0x47
|
|
const OP_returnvalue:int = 0x48
|
|
const OP_constructsuper:int = 0x49
|
|
const OP_constructprop:int = 0x4A
|
|
const OP_callsuperid:int = 0x4B
|
|
const OP_callproplex:int = 0x4C
|
|
const OP_callinterface:int = 0x4D
|
|
const OP_callsupervoid:int = 0x4E
|
|
const OP_callpropvoid:int = 0x4F
|
|
const OP_newobject:int = 0x55
|
|
const OP_newarray:int = 0x56
|
|
const OP_newactivation:int = 0x57
|
|
const OP_newclass:int = 0x58
|
|
const OP_getdescendants:int = 0x59
|
|
const OP_newcatch:int = 0x5A
|
|
const OP_findpropstrict:int = 0x5D
|
|
const OP_findproperty:int = 0x5E
|
|
const OP_finddef:int = 0x5F
|
|
const OP_getlex:int = 0x60
|
|
const OP_setproperty:int = 0x61
|
|
const OP_getlocal:int = 0x62
|
|
const OP_setlocal:int = 0x63
|
|
const OP_getglobalscope:int = 0x64
|
|
const OP_getscopeobject:int = 0x65
|
|
const OP_getproperty:int = 0x66
|
|
const OP_getpropertylate:int = 0x67
|
|
const OP_initproperty:int = 0x68
|
|
const OP_setpropertylate:int = 0x69
|
|
const OP_deleteproperty:int = 0x6A
|
|
const OP_deletepropertylate:int = 0x6B
|
|
const OP_getslot:int = 0x6C
|
|
const OP_setslot:int = 0x6D
|
|
const OP_getglobalslot:int = 0x6E
|
|
const OP_setglobalslot:int = 0x6F
|
|
const OP_convert_s:int = 0x70
|
|
const OP_esc_xelem:int = 0x71
|
|
const OP_esc_xattr:int = 0x72
|
|
const OP_convert_i:int = 0x73
|
|
const OP_convert_u:int = 0x74
|
|
const OP_convert_d:int = 0x75
|
|
const OP_convert_b:int = 0x76
|
|
const OP_convert_o:int = 0x77
|
|
const OP_coerce:int = 0x80
|
|
const OP_coerce_b:int = 0x81
|
|
const OP_coerce_a:int = 0x82
|
|
const OP_coerce_i:int = 0x83
|
|
const OP_coerce_d:int = 0x84
|
|
const OP_coerce_s:int = 0x85
|
|
const OP_astype:int = 0x86
|
|
const OP_astypelate:int = 0x87
|
|
const OP_coerce_u:int = 0x88
|
|
const OP_coerce_o:int = 0x89
|
|
const OP_negate:int = 0x90
|
|
const OP_increment:int = 0x91
|
|
const OP_inclocal:int = 0x92
|
|
const OP_decrement:int = 0x93
|
|
const OP_declocal:int = 0x94
|
|
const OP_typeof:int = 0x95
|
|
const OP_not:int = 0x96
|
|
const OP_bitnot:int = 0x97
|
|
const OP_concat:int = 0x9A
|
|
const OP_add_d:int = 0x9B
|
|
const OP_add:int = 0xA0
|
|
const OP_subtract:int = 0xA1
|
|
const OP_multiply:int = 0xA2
|
|
const OP_divide:int = 0xA3
|
|
const OP_modulo:int = 0xA4
|
|
const OP_lshift:int = 0xA5
|
|
const OP_rshift:int = 0xA6
|
|
const OP_urshift:int = 0xA7
|
|
const OP_bitand:int = 0xA8
|
|
const OP_bitor:int = 0xA9
|
|
const OP_bitxor:int = 0xAA
|
|
const OP_equals:int = 0xAB
|
|
const OP_strictequals:int = 0xAC
|
|
const OP_lessthan:int = 0xAD
|
|
const OP_lessequals:int = 0xAE
|
|
const OP_greaterthan:int = 0xAF
|
|
const OP_greaterequals:int = 0xB0
|
|
const OP_instanceof:int = 0xB1
|
|
const OP_istype:int = 0xB2
|
|
const OP_istypelate:int = 0xB3
|
|
const OP_in:int = 0xB4
|
|
const OP_increment_i:int = 0xC0
|
|
const OP_decrement_i:int = 0xC1
|
|
const OP_inclocal_i:int = 0xC2
|
|
const OP_declocal_i:int = 0xC3
|
|
const OP_negate_i:int = 0xC4
|
|
const OP_add_i:int = 0xC5
|
|
const OP_subtract_i:int = 0xC6
|
|
const OP_multiply_i:int = 0xC7
|
|
const OP_getlocal0:int = 0xD0
|
|
const OP_getlocal1:int = 0xD1
|
|
const OP_getlocal2:int = 0xD2
|
|
const OP_getlocal3:int = 0xD3
|
|
const OP_setlocal0:int = 0xD4
|
|
const OP_setlocal1:int = 0xD5
|
|
const OP_setlocal2:int = 0xD6
|
|
const OP_setlocal3:int = 0xD7
|
|
const OP_debug:int = 0xEF
|
|
const OP_debugline:int = 0xF0
|
|
const OP_debugfile:int = 0xF1
|
|
const OP_bkptline:int = 0xF2
|
|
|
|
const opNames = [
|
|
"OP_0x00 ",
|
|
"bkpt ",
|
|
"nop ",
|
|
"throw ",
|
|
"getsuper ",
|
|
"setsuper ",
|
|
"dxns ",
|
|
"dxnslate ",
|
|
"kill ",
|
|
"label ",
|
|
"OP_0x0A ",
|
|
"OP_0x0B ",
|
|
"ifnlt ",
|
|
"ifnle ",
|
|
"ifngt ",
|
|
"ifnge ",
|
|
"jump ",
|
|
"iftrue ",
|
|
"iffalse ",
|
|
"ifeq ",
|
|
"ifne ",
|
|
"iflt ",
|
|
"ifle ",
|
|
"ifgt ",
|
|
"ifge ",
|
|
"ifstricteq ",
|
|
"ifstrictne ",
|
|
"lookupswitch ",
|
|
"pushwith ",
|
|
"popscope ",
|
|
"nextname ",
|
|
"hasnext ",
|
|
"pushnull ",
|
|
"pushundefined ",
|
|
"pushconstant ",
|
|
"nextvalue ",
|
|
"pushbyte ",
|
|
"pushshort ",
|
|
"pushtrue ",
|
|
"pushfalse ",
|
|
"pushnan ",
|
|
"pop ",
|
|
"dup ",
|
|
"swap ",
|
|
"pushstring ",
|
|
"pushint ",
|
|
"pushuint ",
|
|
"pushdouble ",
|
|
"pushscope ",
|
|
"pushnamespace ",
|
|
"hasnext2 ",
|
|
"OP_0x33 ",
|
|
"OP_0x34 ",
|
|
"OP_0x35 ",
|
|
"OP_0x36 ",
|
|
"OP_0x37 ",
|
|
"OP_0x38 ",
|
|
"OP_0x39 ",
|
|
"OP_0x3A ",
|
|
"OP_0x3B ",
|
|
"OP_0x3C ",
|
|
"OP_0x3D ",
|
|
"OP_0x3E ",
|
|
"OP_0x3F ",
|
|
"newfunction ",
|
|
"call ",
|
|
"construct ",
|
|
"callmethod ",
|
|
"callstatic ",
|
|
"callsuper ",
|
|
"callproperty ",
|
|
"returnvoid ",
|
|
"returnvalue ",
|
|
"constructsuper",
|
|
"constructprop ",
|
|
"callsuperid ",
|
|
"callproplex ",
|
|
"callinterface ",
|
|
"callsupervoid ",
|
|
"callpropvoid ",
|
|
"OP_0x50 ",
|
|
"OP_0x51 ",
|
|
"OP_0x52 ",
|
|
"OP_0x53 ",
|
|
"OP_0x54 ",
|
|
"newobject ",
|
|
"newarray ",
|
|
"newactivation ",
|
|
"newclass ",
|
|
"getdescendants",
|
|
"newcatch ",
|
|
"OP_0x5B ",
|
|
"OP_0x5C ",
|
|
"findpropstrict",
|
|
"findproperty ",
|
|
"finddef ",
|
|
"getlex ",
|
|
"setproperty ",
|
|
"getlocal ",
|
|
"setlocal ",
|
|
"getglobalscope",
|
|
"getscopeobject",
|
|
"getproperty ",
|
|
"OP_0x67 ",
|
|
"initproperty ",
|
|
"OP_0x69 ",
|
|
"deleteproperty",
|
|
"OP_0x6A ",
|
|
"getslot ",
|
|
"setslot ",
|
|
"getglobalslot ",
|
|
"setglobalslot ",
|
|
"convert_s ",
|
|
"esc_xelem ",
|
|
"esc_xattr ",
|
|
"convert_i ",
|
|
"convert_u ",
|
|
"convert_d ",
|
|
"convert_b ",
|
|
"convert_o ",
|
|
"checkfilter ",
|
|
"OP_0x79 ",
|
|
"OP_0x7A ",
|
|
"OP_0x7B ",
|
|
"OP_0x7C ",
|
|
"OP_0x7D ",
|
|
"OP_0x7E ",
|
|
"OP_0x7F ",
|
|
"coerce ",
|
|
"coerce_b ",
|
|
"coerce_a ",
|
|
"coerce_i ",
|
|
"coerce_d ",
|
|
"coerce_s ",
|
|
"astype ",
|
|
"astypelate ",
|
|
"coerce_u ",
|
|
"coerce_o ",
|
|
"OP_0x8A ",
|
|
"OP_0x8B ",
|
|
"OP_0x8C ",
|
|
"OP_0x8D ",
|
|
"OP_0x8E ",
|
|
"OP_0x8F ",
|
|
"negate ",
|
|
"increment ",
|
|
"inclocal ",
|
|
"decrement ",
|
|
"declocal ",
|
|
"typeof ",
|
|
"not ",
|
|
"bitnot ",
|
|
"OP_0x98 ",
|
|
"OP_0x99 ",
|
|
"concat ",
|
|
"add_d ",
|
|
"OP_0x9C ",
|
|
"OP_0x9D ",
|
|
"OP_0x9E ",
|
|
"OP_0x9F ",
|
|
"add ",
|
|
"subtract ",
|
|
"multiply ",
|
|
"divide ",
|
|
"modulo ",
|
|
"lshift ",
|
|
"rshift ",
|
|
"urshift ",
|
|
"bitand ",
|
|
"bitor ",
|
|
"bitxor ",
|
|
"equals ",
|
|
"strictequals ",
|
|
"lessthan ",
|
|
"lessequals ",
|
|
"greaterthan ",
|
|
"greaterequals ",
|
|
"instanceof ",
|
|
"istype ",
|
|
"istypelate ",
|
|
"in ",
|
|
"OP_0xB5 ",
|
|
"OP_0xB6 ",
|
|
"OP_0xB7 ",
|
|
"OP_0xB8 ",
|
|
"OP_0xB9 ",
|
|
"OP_0xBA ",
|
|
"OP_0xBB ",
|
|
"OP_0xBC ",
|
|
"OP_0xBD ",
|
|
"OP_0xBE ",
|
|
"OP_0xBF ",
|
|
"increment_i ",
|
|
"decrement_i ",
|
|
"inclocal_i ",
|
|
"declocal_i ",
|
|
"negate_i ",
|
|
"add_i ",
|
|
"subtract_i ",
|
|
"multiply_i ",
|
|
"OP_0xC8 ",
|
|
"OP_0xC9 ",
|
|
"OP_0xCA ",
|
|
"OP_0xCB ",
|
|
"OP_0xCC ",
|
|
"OP_0xCD ",
|
|
"OP_0xCE ",
|
|
"OP_0xCF ",
|
|
"getlocal0 ",
|
|
"getlocal1 ",
|
|
"getlocal2 ",
|
|
"getlocal3 ",
|
|
"setlocal0 ",
|
|
"setlocal1 ",
|
|
"setlocal2 ",
|
|
"setlocal3 ",
|
|
"OP_0xD8 ",
|
|
"OP_0xD9 ",
|
|
"OP_0xDA ",
|
|
"OP_0xDB ",
|
|
"OP_0xDC ",
|
|
"OP_0xDD ",
|
|
"OP_0xDE ",
|
|
"OP_0xDF ",
|
|
"OP_0xE0 ",
|
|
"OP_0xE1 ",
|
|
"OP_0xE2 ",
|
|
"OP_0xE3 ",
|
|
"OP_0xE4 ",
|
|
"OP_0xE5 ",
|
|
"OP_0xE6 ",
|
|
"OP_0xE7 ",
|
|
"OP_0xE8 ",
|
|
"OP_0xE9 ",
|
|
"OP_0xEA ",
|
|
"OP_0xEB ",
|
|
"OP_0xEC ",
|
|
"OP_0xED ",
|
|
"OP_0xEE ",
|
|
"debug ",
|
|
"debugline ",
|
|
"debugfile ",
|
|
"bkptline ",
|
|
"timestamp ",
|
|
"OP_0xF4 ",
|
|
"verifypass ",
|
|
"alloc ",
|
|
"mark ",
|
|
"wb ",
|
|
"prologue ",
|
|
"sendenter ",
|
|
"doubletoatom ",
|
|
"sweep ",
|
|
"codegenop ",
|
|
"verifyop ",
|
|
"decode "
|
|
];
|
|
|
|
var totalSize:int
|
|
var opSizes:Array = new Array(256)
|
|
|
|
class Multiname
|
|
{
|
|
var nsset:Array
|
|
var name:String
|
|
function Multiname(nsset:Array, name:String)
|
|
{
|
|
this.nsset = nsset
|
|
this.name = name
|
|
}
|
|
|
|
public function toString()
|
|
{
|
|
return /*'{' + nsset + '}::' + */name
|
|
}
|
|
}
|
|
|
|
dynamic class MetaData
|
|
{
|
|
var name:String
|
|
public function toString():String
|
|
{
|
|
var last:String
|
|
var s:String = last = '['+name+'('
|
|
var n
|
|
for (n in this)
|
|
s = (last = s + n + "=" + '"' + this[n] + '"') + ','
|
|
return last + ')]'
|
|
}
|
|
}
|
|
|
|
class MemberInfo
|
|
{
|
|
var id:int
|
|
var kind:int
|
|
var name
|
|
var metadata:Array
|
|
}
|
|
|
|
dynamic class LabelInfo
|
|
{
|
|
var count:int
|
|
function labelFor (target:int):String
|
|
{
|
|
if (target in this)
|
|
return this[target]
|
|
return this[target] = "L" + (++count)
|
|
}
|
|
}
|
|
|
|
class MethodInfo extends MemberInfo
|
|
{
|
|
var flags:int
|
|
var debugName
|
|
var paramTypes
|
|
var optionalValues
|
|
var returnType
|
|
var local_count:int
|
|
var max_scope:int
|
|
var max_stack:int
|
|
var code_length:uint
|
|
var code:ByteArray
|
|
var activation:Traits
|
|
var anon:Boolean
|
|
|
|
public function toString():String
|
|
{
|
|
return format()
|
|
}
|
|
|
|
public function format():String
|
|
{
|
|
var s:String = ""
|
|
if (flags & NATIVE)
|
|
s = "native "
|
|
|
|
return s + traitKinds[kind] + " " + name + "(" + paramTypes + "):" + returnType + "\t/* disp_id " + id + "*/"
|
|
}
|
|
|
|
function dump(abc:Abc, indent:String, attr:String="")
|
|
{
|
|
print("")
|
|
|
|
if (metadata) {
|
|
for each (var md in metadata)
|
|
print(indent+md)
|
|
}
|
|
|
|
print(indent+attr+format())
|
|
if (code)
|
|
{
|
|
print(indent+"{")
|
|
var oldindent = indent
|
|
indent += TAB
|
|
if (flags & NEED_ACTIVATION) {
|
|
print(indent+"activation {")
|
|
activation.dump(abc, indent+TAB, "")
|
|
print(indent+"}")
|
|
}
|
|
print(indent+"// local_count="+local_count+
|
|
" max_scope=" + max_scope +
|
|
" max_stack=" + max_stack +
|
|
" code_len=" + code.length)
|
|
code.position = 0
|
|
var labels:LabelInfo = new LabelInfo()
|
|
while (code.bytesAvailable > 0)
|
|
{
|
|
var start:int = code.position
|
|
var s = indent + start
|
|
while (s.length < 12) s += ' ';
|
|
var opcode = code.readUnsignedByte()
|
|
|
|
if (opcode == OP_label || ((code.position-1) in labels)) {
|
|
print(indent)
|
|
print(indent + labels.labelFor(code.position-1) + ": ")
|
|
}
|
|
|
|
s += opNames[opcode]
|
|
s += opNames[opcode].length < 8 ? "\t\t" : "\t"
|
|
|
|
switch(opcode)
|
|
{
|
|
case OP_debugfile:
|
|
case OP_pushstring:
|
|
s += '"' + abc.strings[readU32()].replace(/\n/g,"\\n").replace(/\t/g,"\\t") + '"'
|
|
break
|
|
case OP_pushnamespace:
|
|
s += abc.namespaces[readU32()]
|
|
break
|
|
case OP_pushint:
|
|
var i:int = abc.ints[readU32()]
|
|
s += i + "\t// 0x" + i.toString(16)
|
|
break
|
|
case OP_pushuint:
|
|
var u:uint = abc.uints[readU32()]
|
|
s += u + "\t// 0x" + u.toString(16)
|
|
break;
|
|
case OP_pushdouble:
|
|
s += abc.doubles[readU32()]
|
|
break;
|
|
case OP_getsuper:
|
|
case OP_setsuper:
|
|
case OP_getproperty:
|
|
case OP_initproperty:
|
|
case OP_setproperty:
|
|
case OP_getlex:
|
|
case OP_findpropstrict:
|
|
case OP_findproperty:
|
|
case OP_finddef:
|
|
case OP_deleteproperty:
|
|
case OP_istype:
|
|
case OP_coerce:
|
|
case OP_astype:
|
|
case OP_getdescendants:
|
|
s += abc.names[readU32()]
|
|
break;
|
|
case OP_constructprop:
|
|
case OP_callproperty:
|
|
case OP_callproplex:
|
|
case OP_callsuper:
|
|
case OP_callsupervoid:
|
|
case OP_callpropvoid:
|
|
s += abc.names[readU32()]
|
|
s += " (" + readU32() + ")"
|
|
break;
|
|
case OP_newfunction: {
|
|
var method_id = readU32()
|
|
s += abc.methods[method_id]
|
|
abc.methods[method_id].anon = true
|
|
break;
|
|
}
|
|
case OP_callstatic:
|
|
s += abc.methods[readU32()]
|
|
s += " (" + readU32() + ")"
|
|
break;
|
|
case OP_newclass:
|
|
s += abc.instances[readU32()]
|
|
break;
|
|
case OP_lookupswitch:
|
|
var pos = code.position-1;
|
|
var target = pos + readS24()
|
|
var maxindex = readU32()
|
|
s += "default:" + labels.labelFor(target) // target + "("+(target-pos)+")"
|
|
s += " maxcase:" + maxindex
|
|
for (var i:int=0; i <= maxindex; i++) {
|
|
target = pos + readS24();
|
|
s += " " + labels.labelFor(target) // target + "("+(target-pos)+")"
|
|
}
|
|
break;
|
|
case OP_jump:
|
|
case OP_iftrue: case OP_iffalse:
|
|
case OP_ifeq: case OP_ifne:
|
|
case OP_ifge: case OP_ifnge:
|
|
case OP_ifgt: case OP_ifngt:
|
|
case OP_ifle: case OP_ifnle:
|
|
case OP_iflt: case OP_ifnlt:
|
|
case OP_ifstricteq: case OP_ifstrictne:
|
|
var offset = readS24()
|
|
var target = code.position+offset
|
|
//s += target + " ("+offset+")"
|
|
s += labels.labelFor(target)
|
|
if (!((code.position) in labels))
|
|
s += "\n"
|
|
break;
|
|
case OP_inclocal:
|
|
case OP_declocal:
|
|
case OP_inclocal_i:
|
|
case OP_declocal_i:
|
|
case OP_getlocal:
|
|
case OP_kill:
|
|
case OP_setlocal:
|
|
case OP_debugline:
|
|
case OP_getglobalslot:
|
|
case OP_getslot:
|
|
case OP_setglobalslot:
|
|
case OP_setslot:
|
|
case OP_pushshort:
|
|
case OP_newcatch:
|
|
s += readU32()
|
|
break
|
|
case OP_debug:
|
|
s += code.readUnsignedByte()
|
|
s += " " + readU32()
|
|
s += " " + code.readUnsignedByte()
|
|
s += " " + readU32()
|
|
break;
|
|
case OP_newobject:
|
|
s += "{" + readU32() + "}"
|
|
break;
|
|
case OP_newarray:
|
|
s += "[" + readU32() + "]"
|
|
break;
|
|
case OP_call:
|
|
case OP_construct:
|
|
case OP_constructsuper:
|
|
s += "(" + readU32() + ")"
|
|
break;
|
|
case OP_pushbyte:
|
|
case OP_getscopeobject:
|
|
s += code.readByte()
|
|
break;
|
|
case OP_hasnext2:
|
|
s += readU32() + " " + readU32()
|
|
default:
|
|
/*if (opNames[opcode] == ("0x"+opcode.toString(16).toUpperCase()))
|
|
s += " UNKNOWN OPCODE"*/
|
|
break
|
|
}
|
|
var size:int = code.position - start
|
|
totalSize += size
|
|
opSizes[opcode] = int(opSizes[opcode]) + size
|
|
print(s)
|
|
}
|
|
print(oldindent+"}\n")
|
|
}
|
|
}
|
|
|
|
function readU32():int
|
|
{
|
|
var result:int = code.readUnsignedByte();
|
|
if (!(result & 0x00000080))
|
|
return result;
|
|
result = result & 0x0000007f | code.readUnsignedByte()<<7;
|
|
if (!(result & 0x00004000))
|
|
return result;
|
|
result = result & 0x00003fff | code.readUnsignedByte()<<14;
|
|
if (!(result & 0x00200000))
|
|
return result;
|
|
result = result & 0x001fffff | code.readUnsignedByte()<<21;
|
|
if (!(result & 0x10000000))
|
|
return result;
|
|
return result & 0x0fffffff | code.readUnsignedByte()<<28;
|
|
}
|
|
|
|
function readS24():int
|
|
{
|
|
var b:int = code.readUnsignedByte()
|
|
b |= code.readUnsignedByte()<<8
|
|
b |= code.readByte()<<16
|
|
return b
|
|
}
|
|
}
|
|
|
|
class SlotInfo extends MemberInfo
|
|
{
|
|
var type
|
|
var value
|
|
public function format():String
|
|
{
|
|
return traitKinds[kind] + " " + name + ":" + type +
|
|
(value !== undefined ? (" = " + (value is String ? ('"'+value+'"') : value)) : "") +
|
|
"\t/* slot_id " + id + " */"
|
|
}
|
|
function dump(abc:Abc, indent:String, attr:String="")
|
|
{
|
|
|
|
if (kind == TRAIT_Const || kind == TRAIT_Slot)
|
|
{
|
|
if (metadata) {
|
|
for each (var md in metadata)
|
|
print(indent+md)
|
|
}
|
|
print(indent+attr+format())
|
|
return
|
|
}
|
|
|
|
// else, class
|
|
|
|
var ct:Traits = value
|
|
var it:Traits = ct.itraits
|
|
print('')
|
|
if (metadata) {
|
|
for each (var md in metadata)
|
|
print(indent+md)
|
|
}
|
|
var def:String;
|
|
if (it.flags & CLASS_FLAG_interface)
|
|
def = "interface"
|
|
else {
|
|
def = "class";
|
|
if (!(it.flags & CLASS_FLAG_sealed))
|
|
def = "dynamic " + def;
|
|
if (it.flags & CLASS_FLAG_final)
|
|
def = "final " + def;
|
|
|
|
}
|
|
print(indent+attr+def+" "+name+" extends "+it.base)
|
|
var oldindent = indent
|
|
indent += TAB
|
|
if (it.interfaces.length > 0)
|
|
print(indent+"implements "+it.interfaces)
|
|
print(oldindent+"{")
|
|
it.init.dump(abc,indent)
|
|
it.dump(abc,indent)
|
|
ct.dump(abc,indent,"static ")
|
|
ct.init.dump(abc,indent,"static ")
|
|
print(oldindent+"}\n")
|
|
}
|
|
}
|
|
|
|
class Traits
|
|
{
|
|
var name
|
|
var init:MethodInfo
|
|
var itraits:Traits
|
|
var base
|
|
var flags:int
|
|
var protectedNs:Namespace
|
|
const interfaces:Array = []
|
|
const names:Object = {}
|
|
const slots:Array = []
|
|
const methods:Array = []
|
|
const members:Array = []
|
|
|
|
public function toString():String
|
|
{
|
|
return String(name)
|
|
}
|
|
|
|
public function dump(abc:Abc, indent:String, attr:String="")
|
|
{
|
|
for each (var m in members)
|
|
m.dump(abc,indent,attr)
|
|
}
|
|
}
|
|
|
|
const ATTR_final :int = 0x01; // 1=final, 0=virtual
|
|
const ATTR_override :int = 0x02; // 1=override, 0=new
|
|
const ATTR_metadata :int = 0x04; // 1=has metadata, 0=no metadata
|
|
const ATTR_public :int = 0x08; // 1=add public namespace
|
|
|
|
const CLASS_FLAG_sealed :int = 0x01;
|
|
const CLASS_FLAG_final :int = 0x02;
|
|
const CLASS_FLAG_interface :int = 0x04;
|
|
|
|
class Abc
|
|
{
|
|
private var data:ByteArray
|
|
|
|
var major:int
|
|
var minor:int
|
|
|
|
var ints:Array
|
|
var uints:Array
|
|
var doubles:Array
|
|
var strings:Array
|
|
var namespaces:Array
|
|
var nssets:Array
|
|
var names:Array
|
|
|
|
var defaults:Array = new Array(constantKinds.length)
|
|
|
|
var methods:Array
|
|
var instances:Array
|
|
var classes:Array
|
|
var scripts:Array
|
|
|
|
var publicNs = new Namespace("")
|
|
var anyNs = new Namespace("*")
|
|
|
|
var magic:int
|
|
|
|
function Abc(data:ByteArray)
|
|
{
|
|
data.position = 0
|
|
this.data = data
|
|
magic = data.readInt()
|
|
|
|
print("magic " + magic.toString(16))
|
|
|
|
if (magic != (46<<16|14) && magic != (46<<16|15) && magic != (46<<16|16))
|
|
throw new Error("not an abc file. magic=" + magic.toString(16))
|
|
|
|
parseCpool()
|
|
|
|
defaults[CONSTANT_Utf8] = strings
|
|
defaults[CONSTANT_Int] = ints
|
|
defaults[CONSTANT_UInt] = uints
|
|
defaults[CONSTANT_Double] = doubles
|
|
defaults[CONSTANT_Int] = ints
|
|
defaults[CONSTANT_False] = { 10:false }
|
|
defaults[CONSTANT_True] = { 11:true }
|
|
defaults[CONSTANT_Namespace] = namespaces
|
|
defaults[CONSTANT_PrivateNs] = namespaces
|
|
defaults[CONSTANT_PackageNs] = namespaces
|
|
defaults[CONSTANT_PackageInternalNs] = namespaces
|
|
defaults[CONSTANT_ProtectedNs] = namespaces
|
|
defaults[CONSTANT_StaticProtectedNs] = namespaces
|
|
defaults[CONSTANT_StaticProtectedNs2] = namespaces
|
|
defaults[CONSTANT_Null] = { 12: null }
|
|
|
|
parseMethodInfos()
|
|
parseMetadataInfos()
|
|
parseInstanceInfos()
|
|
parseClassInfos()
|
|
parseScriptInfos()
|
|
parseMethodBodies()
|
|
}
|
|
|
|
function readU32():int
|
|
{
|
|
var result:int = data.readUnsignedByte();
|
|
if (!(result & 0x00000080))
|
|
return result;
|
|
result = result & 0x0000007f | data.readUnsignedByte()<<7;
|
|
if (!(result & 0x00004000))
|
|
return result;
|
|
result = result & 0x00003fff | data.readUnsignedByte()<<14;
|
|
if (!(result & 0x00200000))
|
|
return result;
|
|
result = result & 0x001fffff | data.readUnsignedByte()<<21;
|
|
if (!(result & 0x10000000))
|
|
return result;
|
|
return result & 0x0fffffff | data.readUnsignedByte()<<28;
|
|
}
|
|
|
|
function parseCpool()
|
|
{
|
|
var i:int, j:int
|
|
var n:int
|
|
var kind:int
|
|
|
|
var start:int = data.position
|
|
|
|
// ints
|
|
n = readU32()
|
|
ints = [0]
|
|
for (i=1; i < n; i++)
|
|
ints[i] = readU32()
|
|
|
|
// uints
|
|
n = readU32()
|
|
uints = [0]
|
|
for (i=1; i < n; i++)
|
|
uints[i] = uint(readU32())
|
|
|
|
// doubles
|
|
n = readU32()
|
|
doubles = [NaN]
|
|
for (i=1; i < n; i++)
|
|
doubles[i] = data.readDouble()
|
|
|
|
print("Cpool numbers size "+(data.position-start)+" "+int(100*(data.position-start)/data.length)+" %")
|
|
start = data.position
|
|
|
|
// strings
|
|
n = readU32()
|
|
strings = [""]
|
|
for (i=1; i < n; i++)
|
|
strings[i] = data.readUTFBytes(readU32())
|
|
|
|
print("Cpool strings count "+ n +" size "+(data.position-start)+" "+int(100*(data.position-start)/data.length)+" %")
|
|
start = data.position
|
|
|
|
// namespaces
|
|
n = readU32()
|
|
namespaces = [publicNs]
|
|
for (i=1; i < n; i++)
|
|
switch (data.readByte())
|
|
{
|
|
case CONSTANT_Namespace:
|
|
case CONSTANT_PackageNs:
|
|
case CONSTANT_PackageInternalNs:
|
|
case CONSTANT_ProtectedNs:
|
|
case CONSTANT_StaticProtectedNs:
|
|
case CONSTANT_StaticProtectedNs2:
|
|
{
|
|
namespaces[i] = new Namespace(strings[readU32()])
|
|
// todo mark kind of namespace.
|
|
break;
|
|
}
|
|
case CONSTANT_PrivateNs:
|
|
readU32();
|
|
namespaces[i] = new Namespace(null, "private")
|
|
break;
|
|
}
|
|
|
|
print("Cpool namespaces count "+ n +" size "+(data.position-start)+" "+int(100*(data.position-start)/data.length)+" %")
|
|
start = data.position
|
|
|
|
// namespace sets
|
|
n = readU32()
|
|
nssets = [null]
|
|
for (i=1; i < n; i++)
|
|
{
|
|
var count:int = readU32()
|
|
var nsset = nssets[i] = []
|
|
for (j=0; j < count; j++)
|
|
nsset[j] = namespaces[readU32()]
|
|
}
|
|
|
|
print("Cpool nssets count "+ n +" size "+(data.position-start)+" "+int(100*(data.position-start)/data.length)+" %")
|
|
start = data.position
|
|
|
|
// multinames
|
|
n = readU32()
|
|
names = [null]
|
|
namespaces[0] = anyNs
|
|
strings[0] = "*" // any name
|
|
for (i=1; i < n; i++)
|
|
switch (data.readByte())
|
|
{
|
|
case CONSTANT_Qname:
|
|
case CONSTANT_QnameA:
|
|
names[i] = new QName(namespaces[readU32()], strings[readU32()])
|
|
break;
|
|
|
|
case CONSTANT_RTQname:
|
|
case CONSTANT_RTQnameA:
|
|
names[i] = new QName(strings[readU32()])
|
|
break;
|
|
|
|
case CONSTANT_RTQnameL:
|
|
case CONSTANT_RTQnameLA:
|
|
names[i] = null
|
|
break;
|
|
|
|
case CONSTANT_NameL:
|
|
case CONSTANT_NameLA:
|
|
names[i] = new QName(new Namespace(""), null)
|
|
break;
|
|
|
|
case CONSTANT_Multiname:
|
|
case CONSTANT_MultinameA:
|
|
var name = strings[readU32()]
|
|
names[i] = new Multiname(nssets[readU32()], name)
|
|
break;
|
|
|
|
case CONSTANT_MultinameL:
|
|
case CONSTANT_MultinameLA:
|
|
names[i] = new Multiname(nssets[readU32()], null)
|
|
break;
|
|
|
|
default:
|
|
throw new Error("invalid kind " + data[data.position-1])
|
|
}
|
|
|
|
print("Cpool names count "+ n +" size "+(data.position-start)+" "+int(100*(data.position-start)/data.length)+" %")
|
|
start = data.position
|
|
|
|
namespaces[0] = publicNs
|
|
strings[0] = "*"
|
|
}
|
|
|
|
function parseMethodInfos()
|
|
{
|
|
var start:int = data.position
|
|
names[0] = new QName(publicNs,"*")
|
|
var method_count:int = readU32()
|
|
methods = []
|
|
for (var i:int=0; i < method_count; i++)
|
|
{
|
|
var m = methods[i] = new MethodInfo()
|
|
var param_count:int = readU32()
|
|
m.returnType = names[readU32()]
|
|
m.paramTypes = []
|
|
for (var j:int=0; j < param_count; j++)
|
|
m.paramTypes[j] = names[readU32()]
|
|
m.debugName = strings[readU32()]
|
|
m.flags = data.readByte()
|
|
if (m.flags & HAS_OPTIONAL)
|
|
{
|
|
// has_optional
|
|
var optional_count:int = readU32();
|
|
m.optionalValues = []
|
|
for( var k:int = param_count-optional_count; k < param_count; ++k)
|
|
{
|
|
var index = readU32() // optional value index
|
|
var kind:int = data.readByte() // kind byte for each default value
|
|
if (index == 0)
|
|
{
|
|
// kind is ignored, default value is based on type
|
|
m.optionalValues[k] = undefined
|
|
}
|
|
else
|
|
{
|
|
if (!defaults[kind])
|
|
print("ERROR kind="+kind+" method_id " + i)
|
|
else
|
|
m.optionalValues[k] = defaults[kind][index]
|
|
}
|
|
}
|
|
}
|
|
if (m.flags & HAS_ParamNames)
|
|
{
|
|
// has_paramnames
|
|
for( var k:int = 0; k < param_count; ++k)
|
|
{
|
|
readU32();
|
|
}
|
|
}
|
|
}
|
|
print("MethodInfo count " +method_count+ " size "+(data.position-start)+" "+int(100*(data.position-start)/data.length)+" %")
|
|
}
|
|
|
|
function parseMetadataInfos()
|
|
{
|
|
var count:int = readU32()
|
|
metadata = []
|
|
for (var i:int=0; i < count; i++)
|
|
{
|
|
// MetadataInfo
|
|
var m = metadata[i] = new MetaData()
|
|
m.name = strings[readU32()];
|
|
var values_count:int = readU32();
|
|
var names:Array = []
|
|
for(var q:int = 0; q < values_count; ++q)
|
|
names[q] = strings[readU32()] // name
|
|
for(var q:int = 0; q < values_count; ++q)
|
|
m[names[q]] = strings[readU32()] // value
|
|
}
|
|
}
|
|
|
|
function parseInstanceInfos()
|
|
{
|
|
var start:int = data.position
|
|
var count:int = readU32()
|
|
instances = []
|
|
for (var i:int=0; i < count; i++)
|
|
{
|
|
var t = instances[i] = new Traits()
|
|
t.name = names[readU32()]
|
|
t.base = names[readU32()]
|
|
t.flags = data.readByte()
|
|
if (t.flags & 8)
|
|
t.protectedNs = namespaces[readU32()]
|
|
var interface_count = readU32()
|
|
for (var j:int=0; j < interface_count; j++)
|
|
t.interfaces[i] = names[readU32()]
|
|
var m = t.init = methods[readU32()]
|
|
m.name = t.name
|
|
m.kind = TRAIT_Method
|
|
m.id = -1
|
|
parseTraits(t)
|
|
}
|
|
print("InstanceInfo size "+(data.position-start)+" "+int(100*(data.position-start)/data.length)+" %")
|
|
}
|
|
|
|
function parseTraits(t:Traits)
|
|
{
|
|
var namecount = readU32()
|
|
for (var i:int=0; i < namecount; i++)
|
|
{
|
|
var name = names[readU32()]
|
|
var tag = data.readByte()
|
|
var kind = tag & 0xf
|
|
var member
|
|
switch(kind) {
|
|
case TRAIT_Slot:
|
|
case TRAIT_Const:
|
|
case TRAIT_Class:
|
|
var slot = member = new SlotInfo()
|
|
slot.id = readU32()
|
|
t.slots[slot.id] = slot
|
|
if (kind==TRAIT_Slot || kind==TRAIT_Const)
|
|
{
|
|
slot.type = names[readU32()]
|
|
var index=readU32()
|
|
if (index)
|
|
slot.value = defaults[data.readByte()][index]
|
|
}
|
|
else // (kind == TRAIT_Class)
|
|
{
|
|
slot.value = classes[readU32()]
|
|
}
|
|
break;
|
|
case TRAIT_Method:
|
|
case TRAIT_Getter:
|
|
case TRAIT_Setter:
|
|
var disp_id = readU32()
|
|
var method = member = methods[readU32()]
|
|
t.methods[disp_id] = method
|
|
method.id = disp_id
|
|
//print("\t",traitKinds[kind],name,disp_id,method,"// disp_id", disp_id)
|
|
break;
|
|
}
|
|
if (!member)
|
|
print("error trait kind "+kind)
|
|
member.kind = kind
|
|
member.name = name
|
|
t.names[String(name)] = t.members[i] = member
|
|
|
|
if ( (tag >> 4) & ATTR_metadata ) {
|
|
member.metadata = []
|
|
for(var j:int=0, mdCount:int=readU32(); j < mdCount; ++j)
|
|
member.metadata[j] = metadata[readU32()]
|
|
}
|
|
}
|
|
}
|
|
|
|
function parseClassInfos()
|
|
{
|
|
var start:int = data.position
|
|
var count:int = instances.length
|
|
classes = []
|
|
for (var i:int=0; i < count; i++)
|
|
{
|
|
var t:Traits = classes[i] = new Traits()
|
|
t.init = methods[readU32()]
|
|
t.base = "Class"
|
|
t.itraits = instances[i]
|
|
t.name = t.itraits.name + "$"
|
|
t.init.name = t.itraits.name + "$cinit"
|
|
t.init.kind = TRAIT_Method
|
|
parseTraits(t)
|
|
}
|
|
print("ClassInfo size "+(data.position-start)+" "+int(100*(data.position-start)/data.length)+"%")
|
|
}
|
|
|
|
function parseScriptInfos()
|
|
{
|
|
var start:int = data.position
|
|
var count:int = readU32()
|
|
scripts = []
|
|
for (var i:int=0; i < count; i++)
|
|
{
|
|
var t = new Traits()
|
|
scripts[i] = t
|
|
t.name = "script" + i
|
|
t.base = names[0] // Object
|
|
t.init = methods[readU32()]
|
|
t.init.name = t.name + "$init"
|
|
t.init.kind = TRAIT_Method
|
|
parseTraits(t)
|
|
}
|
|
print("ScriptInfo size "+(data.position-start)+" "+int(100*(data.position-start)/data.length)+" %")
|
|
}
|
|
|
|
function parseMethodBodies()
|
|
{
|
|
var start:int = data.position
|
|
var count:int = readU32()
|
|
for (var i:int=0; i < count; i++)
|
|
{
|
|
var m = methods[readU32()]
|
|
m.max_stack = readU32()
|
|
m.local_count = readU32()
|
|
var initScopeDepth = readU32()
|
|
var maxScopeDepth = readU32()
|
|
m.max_scope = maxScopeDepth - initScopeDepth
|
|
var code_length = readU32()
|
|
m.code = new ByteArray()
|
|
m.code.endian = "littleEndian"
|
|
if (code_length > 0)
|
|
data.readBytes(m.code, 0, code_length)
|
|
var ex_count = readU32()
|
|
for (var j:int = 0; j < ex_count; j++)
|
|
{
|
|
var from = readU32()
|
|
var to = readU32()
|
|
var target = readU32()
|
|
var type = names[readU32()]
|
|
//print("magic " + magic.toString(16))
|
|
//if (magic >= (46<<16|16))
|
|
var name = names[readU32()];
|
|
}
|
|
parseTraits(m.activation = new Traits)
|
|
}
|
|
print("MethodBodies size "+(data.position-start)+" "+int(100*(data.position-start)/data.length)+" %")
|
|
}
|
|
|
|
function dump(indent:String="")
|
|
{
|
|
for each (var t in scripts)
|
|
{
|
|
print(indent+t.name)
|
|
t.dump(this,indent)
|
|
t.init.dump(this,indent)
|
|
}
|
|
|
|
for each (var m in methods)
|
|
{
|
|
if (m.anon) {
|
|
m.dump(this,indent)
|
|
}
|
|
}
|
|
|
|
print("OPCODE\tSIZE\t% OF "+totalSize)
|
|
var done = []
|
|
for (;;)
|
|
{
|
|
var max:int = -1;
|
|
var maxsize:int = 0;
|
|
for (var i:int=0; i < 256; i++)
|
|
{
|
|
if (opSizes[i] > maxsize && !done[i])
|
|
{
|
|
max = i;
|
|
maxsize = opSizes[i];
|
|
}
|
|
}
|
|
if (max == -1)
|
|
break;
|
|
done[max] = 1;
|
|
print(opNames[max]+"\t"+int(opSizes[max])+"\t"+int(100*opSizes[max]/totalSize)+"%")
|
|
}
|
|
}
|
|
}
|
|
|
|
class Rect
|
|
{
|
|
var nBits:int
|
|
var xMin:int, xMax:int
|
|
var yMin:int, yMax:int
|
|
public function toString()
|
|
{
|
|
return "[Rect "+xMin+" "+yMin+" "+xMax+" "+yMax+"]"
|
|
}
|
|
}
|
|
|
|
const stagDoABC :int = 72; // embedded .abc (AVM+) bytecode
|
|
const stagSymbolClass :int = 76;
|
|
const stagDoABC2 :int = 82; // revised ABC version with a name
|
|
|
|
var tagNames:Array = [
|
|
"End", // 00
|
|
"ShowFrame", // 01
|
|
"DefineShape", // 02
|
|
"FreeCharacter", // 03
|
|
"PlaceObject", // 04
|
|
"RemoveObject", // 05
|
|
"DefineBits", // 06
|
|
"DefineButton", // 07
|
|
"JPEGTables", // 08
|
|
"SetBackgroundColor", // 09
|
|
|
|
"DefineFont", // 10
|
|
"DefineText", // 11
|
|
"DoAction", // 12
|
|
"DefineFontInfo", // 13
|
|
|
|
"DefineSound", // 14
|
|
"StartSound", // 15
|
|
"StopSound", // 16
|
|
|
|
"DefineButtonSound", // 17
|
|
|
|
"SoundStreamHead", // 18
|
|
"SoundStreamBlock", // 19
|
|
|
|
"DefineBitsLossless", // 20
|
|
"DefineBitsJPEG2", // 21
|
|
|
|
"DefineShape2", // 22
|
|
"DefineButtonCxform", // 23
|
|
|
|
"Protect", // 24
|
|
|
|
"PathsArePostScript", // 25
|
|
|
|
"PlaceObject2", // 26
|
|
"27 (invalid)", // 27
|
|
"RemoveObject2", // 28
|
|
|
|
"SyncFrame", // 29
|
|
"30 (invalid)", // 30
|
|
"FreeAll", // 31
|
|
|
|
"DefineShape3", // 32
|
|
"DefineText2", // 33
|
|
"DefineButton2", // 34
|
|
"DefineBitsJPEG3", // 35
|
|
"DefineBitsLossless2", // 36
|
|
"DefineEditText", // 37
|
|
|
|
"DefineVideo", // 38
|
|
|
|
"DefineSprite", // 39
|
|
"NameCharacter", // 40
|
|
"ProductInfo", // 41
|
|
"DefineTextFormat", // 42
|
|
"FrameLabel", // 43
|
|
"DefineBehavior", // 44
|
|
"SoundStreamHead2", // 45
|
|
"DefineMorphShape", // 46
|
|
"FrameTag", // 47
|
|
"DefineFont2", // 48
|
|
"GenCommand", // 49
|
|
"DefineCommandObj", // 50
|
|
"CharacterSet", // 51
|
|
"FontRef", // 52
|
|
|
|
"DefineFunction", // 53
|
|
"PlaceFunction", // 54
|
|
|
|
"GenTagObject", // 55
|
|
|
|
"ExportAssets", // 56
|
|
"ImportAssets", // 57
|
|
|
|
"EnableDebugger", // 58
|
|
|
|
"DoInitAction", // 59
|
|
"DefineVideoStream", // 60
|
|
"VideoFrame", // 61
|
|
|
|
"DefineFontInfo2", // 62
|
|
"DebugID", // 63
|
|
"EnableDebugger2", // 64
|
|
"ScriptLimits", // 65
|
|
|
|
"SetTabIndex", // 66
|
|
|
|
"DefineShape4", // 67
|
|
"DefineMorphShape2", // 68
|
|
|
|
"FileAttributes", // 69
|
|
|
|
"PlaceObject3", // 70
|
|
"ImportAssets2", // 71
|
|
|
|
"DoABC", // 72
|
|
"73 (invalid)", // 73
|
|
"74 (invalid)", // 74
|
|
"75 (invalid)", // 75
|
|
"SymbolClass", // 76
|
|
"77 (invalid)", // 77
|
|
"78 (invalid)", // 78
|
|
"79 (invalid)", // 79
|
|
"80 (invalid)", // 80
|
|
"81 (invalid)", // 81
|
|
"DoABC2", // 82
|
|
"83 (invalid)" // 83
|
|
]
|
|
|
|
|
|
class Swf
|
|
{
|
|
private var bitPos:int
|
|
private var bitBuf:int
|
|
|
|
private var data:ByteArray
|
|
|
|
function Swf(data:ByteArray)
|
|
{
|
|
this.data = data
|
|
print("size "+decodeRect())
|
|
print("frame rate "+(data.readUnsignedByte()<<8|data.readUnsignedByte()))
|
|
print("frame count "+data.readUnsignedShort())
|
|
decodeTags()
|
|
}
|
|
|
|
private function decodeTags()
|
|
{
|
|
var type:int, h:int, length:int
|
|
var offset:int
|
|
|
|
while (data.position < data.length)
|
|
{
|
|
type = (h = data.readUnsignedShort()) >> 6;
|
|
|
|
if (((length = h & 0x3F) == 0x3F))
|
|
length = data.readInt();
|
|
|
|
print(tagNames[type]+" "+length+"b "+int(100*length/data.length)+"%")
|
|
switch (type)
|
|
{
|
|
case 0: return
|
|
case stagDoABC2:
|
|
var pos1:int = data.position
|
|
data.readInt()
|
|
print("\nabc name "+readString())
|
|
length -= (data.position-pos1)
|
|
// fall through
|
|
case stagDoABC:
|
|
var data2 = new ByteArray
|
|
data2.endian = "littleEndian"
|
|
data.readBytes(data2,0,length)
|
|
new Abc(data2).dump(" ")
|
|
print("")
|
|
break
|
|
default:
|
|
data.position += length
|
|
}
|
|
}
|
|
}
|
|
|
|
private function readString():String
|
|
{
|
|
var s:String = ""
|
|
var c:int
|
|
|
|
while (c=data.readUnsignedByte())
|
|
s += String.fromCharCode(c)
|
|
|
|
return s
|
|
}
|
|
|
|
private function syncBits()
|
|
{
|
|
bitPos = 0
|
|
}
|
|
|
|
private function decodeRect():Rect
|
|
{
|
|
syncBits();
|
|
|
|
var rect:Rect = new Rect();
|
|
|
|
var nBits:int = readUBits(5)
|
|
rect.xMin = readSBits(nBits);
|
|
rect.xMax = readSBits(nBits);
|
|
rect.yMin = readSBits(nBits);
|
|
rect.yMax = readSBits(nBits);
|
|
|
|
return rect;
|
|
}
|
|
|
|
function readSBits(numBits:int):int
|
|
{
|
|
if (numBits > 32)
|
|
throw new Error("Number of bits > 32");
|
|
|
|
var num:int = readUBits(numBits);
|
|
var shift:int = 32-numBits;
|
|
// sign extension
|
|
num = (num << shift) >> shift;
|
|
return num;
|
|
}
|
|
|
|
function readUBits(numBits:int):uint
|
|
{
|
|
if (numBits == 0)
|
|
return 0
|
|
|
|
var bitsLeft:int = numBits;
|
|
var result:int = 0;
|
|
|
|
if (bitPos == 0) //no value in the buffer - read a byte
|
|
{
|
|
bitBuf = data.readUnsignedByte()
|
|
bitPos = 8;
|
|
}
|
|
|
|
while (true)
|
|
{
|
|
var shift:int = bitsLeft - bitPos;
|
|
if (shift > 0)
|
|
{
|
|
// Consume the entire buffer
|
|
result |= bitBuf << shift;
|
|
bitsLeft -= bitPos;
|
|
|
|
// Get the next byte from the input stream
|
|
bitBuf = data.readUnsignedByte();
|
|
bitPos = 8;
|
|
}
|
|
else
|
|
{
|
|
// Consume a portion of the buffer
|
|
result |= bitBuf >> -shift;
|
|
bitPos -= bitsLeft;
|
|
bitBuf &= 0xff >> (8 - bitPos); // mask off the consumed bits
|
|
|
|
// if (print) System.out.println(" read"+numBits+" " + result);
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// main
|
|
|
|
for each (var file in System.argv)
|
|
{
|
|
var data:ByteArray = ByteArray.readFile(file)
|
|
data.endian = "littleEndian"
|
|
var version:uint = data.readUnsignedInt()
|
|
switch (version) {
|
|
case 46<<16|14:
|
|
case 46<<16|15:
|
|
case 46<<16|16:
|
|
var abc:Abc = new Abc(data)
|
|
abc.dump()
|
|
break
|
|
case 67|87<<8|83<<16|9<<24: // SWC9
|
|
case 67|87<<8|83<<16|8<<24: // SWC8
|
|
case 67|87<<8|83<<16|7<<24: // SWC7
|
|
case 67|87<<8|83<<16|6<<24: // SWC6
|
|
var udata:ByteArray = new ByteArray
|
|
udata.endian = "littleEndian"
|
|
data.position = 8
|
|
data.readBytes(udata,0,data.length-data.position)
|
|
var csize:int = udata.length
|
|
udata.uncompress()
|
|
print("decompressed swf "+csize+" -> "+udata.length)
|
|
udata.position = 0
|
|
/*var swf:Swf =*/ new Swf(udata)
|
|
break
|
|
case 70|87<<8|83<<16|9<<24: // SWC9
|
|
case 70|87<<8|83<<16|8<<24: // SWC8
|
|
case 70|87<<8|83<<16|7<<24: // SWC7
|
|
case 70|87<<8|83<<16|6<<24: // SWC6
|
|
case 70|87<<8|83<<16|5<<24: // SWC5
|
|
case 70|87<<8|83<<16|4<<24: // SWC4
|
|
data.position = 8 // skip header and length
|
|
/*var swf:Swf =*/ new Swf(data)
|
|
break
|
|
default:
|
|
print('unknown format '+version)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|