1 /* -*- indent-tabs-mode: nil; tab-width: 4 -*- */
2 /* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is [Open Source Virtual Machine.].
18 * The Initial Developer of the Original Code is
19 * Adobe System Incorporated.
20 * Portions created by the Initial Developer are Copyright (C) 2004-2006
21 * the Initial Developer. All Rights Reserved.
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
42 import flash
.utils
.ByteArray
46 include "abc-constants.as"
49 "Displays the contents of abc or swf files",
53 " abcdump [options] file ...",
55 "Each file can be an ABC or SWF/SWC format file",
59 " -a Extract the ABC blocks from the SWF/SWC, but do not",
60 " otherwise display their contents. The file names are",
61 " of the form file<n>.abc where \"file\" is the name",
62 " of the input file minus the .swf/.swc extension;",
63 " and <n> is omitted if it is 0.",
65 " -i Print information about the ABC, but do not dump the byte code.",
67 " -abs Print the bytecode, but no information about the ABC",
68 " -api Print the public API exposed by this abc/swf",
69 " -mdversions Use in conjunction with -api when the abc/swf uses old-style versioning",
70 " -pools Print out the contents of the constant pools"
76 var opSizes
:Array = new Array(256)
78 function dumpPrint
(s
) {
83 function infoPrint
(s
) {
85 print
((doExtractAbs
? "// " : "") + s
)
88 function toStringNull
(x
) {
89 return (x
== null) ? "<null>" : x
.toString
()
92 // keep track of old-style versioning metadata in a global stack
93 var currentVersionMetadata
:Array = new Array()
94 var apiVersionNames
:Array = ["9", "air1", "10", "air1.5", "air1.5.1",
95 "10.0.32", "air1.5.2", "10.1", "air2",
98 function getVersionMetadata
():Array {
99 if (currentVersionMetadata
.length
> 0)
100 return currentVersionMetadata
[currentVersionMetadata
.length
- 1]
105 function pushVersionMetadata
(md
:Array):Boolean {
110 for each(var m
in md
) {
111 if(m
.name
== "Version")
112 for each(var t
:Tuple
in m
.tuples
)
115 for each(var t
:Tuple
in m
.tuples
)
116 vers
.push
(currentVersionMetadata
[int(t
.value
) - 660])
119 if(vers
.length
> 0) {
120 currentVersionMetadata
.push
(vers
)
126 function popVersionMetadata
(cond
:Boolean):void {
128 currentVersionMetadata
.pop
()
134 public var uri
:String
135 public var apiVersions
:Array = new Array()
137 public function ABCNamespace
(ns
:String, k
:int = 0x08 /* CONSTANT_Namespace */) {
139 uri
= ns
== null ? null : stripVersioningChars
(ns
)
142 public function clone
():ABCNamespace
{
143 var ns
:ABCNamespace
= new ABCNamespace
(uri
, kind
)
144 ns
.apiVersions
= apiVersions
.concat
()
148 function stripVersioningChars
(s
:String) {
149 var c
:int = s
.charCodeAt
(s
.length
-1)
152 apiVersions
.push
(apiVersionNames
[c
- 0xE294])
153 return stripVersioningChars
(s
.slice
(0,s
.length
-1))
158 public function toString
(useMD
:Boolean = false):String {
159 var vers
:Array = useMD
? getVersionMetadata
() : apiVersions
160 return (uri
== null ? "" : uri
) + (vers
.length
> 0 && doDumpAPI
? ("[api: " + vers
.join
(',') + "]") : "") // + ("(" + constantKinds[kind] + ")")
163 public function isHidden
():Boolean {
164 return (kind
== CONSTANT_PrivateNs
|| kind
== CONSTANT_PackageInternalNs
)
170 public var ns
:ABCNamespace
171 public var localname
:String
173 public function QualifiedName
(n
:ABCNamespace
, ln
:String) {
178 public function toString
(useMD
:Boolean = false):String {
179 var nsstr
= (ns
== null ? "" : ns
.toString
(useMD
))
180 return (nsstr
== "" ? "" : nsstr
+ "::") + localname
183 public function isHidden
():Boolean {
192 function Multiname
(nsset
:Array, name
:String)
198 public function toString
(useMD
:Boolean = false)
200 if (nsset
.length
== 1)
201 return (new QualifiedName
(nsset
[0], name
).toString
(useMD
))
203 return '{' + joinNsset
(nsset
, useMD
) + '}::' + toStringNull
(name
)
206 function joinNsset
(nsset
:Array, useMD
:Boolean):String {
208 for each (var ns
:ABCNamespace
in nsset
) {
209 s
+= (ns
.toString
(useMD
) + ", ")
214 public function isHidden
():Boolean {
215 for each(var ns
in nsset
)
221 public static function createMultiname
(nsset
:Array, name
:String, flatten
:Boolean) {
223 var cur
:ABCNamespace
= nsset
[0].clone
()
224 for(var i
:int=1; i
<nsset
.length
; i
++) {
225 var ns
:ABCNamespace
= nsset
[i
]
226 if (cur
.uri
== ns
.uri
) {
227 for each(var v
:String in ns
.apiVersions
)
228 if(cur
.apiVersions
.indexOf
(v
) == -1)
229 cur
.apiVersions
.push
(v
)
237 return new QualifiedName
(cur
, name
)
239 return new Multiname
(nsset
, name
)
247 function TypeName
(name
, types
)
253 public function toString
()
255 var s
: String = name
.toString
();
257 for( var i
= 0; i
< types
.length
; ++i
)
258 s
+= types
[i
] != null ? types
[i
].toString
() : "*" + " ";
266 public var key
:String
267 public var value
:String
269 function Tuple
(k
:String, v
:String) {
274 public function toString
() {
275 return key
+ "=" + value
281 public var name
:String
282 public var tuples
:Vector
.<Tuple
> = new Vector
.<Tuple
>()
284 public function toString
():String
287 var s
:String = last
= '['+name
+'('
288 for each (var t
:Tuple
in tuples
)
289 s
= (last
= s
+ t
.key
+ "=" + '"' + t
.value
+ '"') + ','
293 public function addPair
(k
:String, v
:String) {
294 tuples
.push
(new Tuple
(k
, v
))
306 dynamic class LabelInfo
309 function labelFor
(target
:int):String
313 return this[target
] = "L" + (++count
)
326 class MethodInfo
extends MemberInfo
341 var exceptions
// ExceptionInfo[]
342 var activation
:Traits
344 public function toString
():String
349 public function format
():String
351 var name
= this.name
? (this.name
is String ? this.name
: this.name
.toString
(useMetadataVersions
)) : "function"
353 return name
+ "(" + paramTypes
+ "):" + returnType
+ (doDumpAPI
? "" : "\t/* disp_id=" + id
+ " method_id=" + method_id
+ " */")
356 function dump
(abc
:Abc
, indent
:String, attr
:String="")
358 if(doDumpAPI
&& name
&& (name
is String || name
.isHidden
()))
364 if (metadata
&& !doDumpAPI
) {
365 for each (var md
in metadata
)
369 var mdpushed
:Boolean = pushVersionMetadata
(metadata
)
372 if (flags
& NATIVE
&& !doDumpAPI
)
374 s
+= traitKinds
[kind
] + " "
376 dumpPrint
(indent
+attr
+s
+format
())
377 if (code
&& !doDumpAPI
)
379 dumpPrint
(indent
+"{")
380 var oldindent
= indent
382 if (flags
& NEED_ACTIVATION
) {
383 dumpPrint
(indent
+"activation {")
384 activation
.dump
(abc
, indent
+TAB
, "")
385 dumpPrint
(indent
+"}")
387 dumpPrint
(indent
+"// local_count="+local_count
+
388 " max_scope=" + max_scope
+
389 " max_stack=" + max_stack
+
390 " framesize=" + (local_count
+ max_scope
+ max_stack
) +
391 " code_len=" + code
.length
+
392 " code_offset=" + code_offset
)
394 var labels
:LabelInfo
= new LabelInfo
()
395 while (code
.bytesAvailable
> 0)
397 var start
:int = code
.position
398 var s
= indent
+ start
399 while (s
.length
< 12) s
+= ' ';
400 var opcode
= code
.readUnsignedByte
()
402 if (opcode
== OP_label
|| ((code
.position
-1) in labels
)) {
404 dumpPrint
(indent
+ labels
.labelFor
(code
.position
-1) + ": ")
408 s
+= opNames
[opcode
].length
< 8 ? "\t\t" : "\t"
414 s
+= '"' + abc
.strings
[readU32
()].replace
(/\n/g
,"\\n").replace
(/\t/g
,"\\t") + '"'
416 case OP_pushnamespace
:
417 s
+= abc
.namespaces
[readU32
()]
420 var i
:int = abc
.ints
[readU32
()]
421 s
+= i
+ "\t// 0x" + i
.toString
(16)
424 var u
:uint = abc
.uints
[readU32
()]
425 s
+= u
+ "\t// 0x" + u
.toString
(16)
428 s
+= abc
.doubles
[readU32
()]
433 case OP_initproperty
:
436 case OP_findpropstrict
:
437 case OP_findproperty
:
439 case OP_deleteproperty
:
443 case OP_getdescendants
:
444 s
+= abc
.names
[readU32
()]
446 case OP_constructprop
:
447 case OP_callproperty
:
450 case OP_callsupervoid
:
451 case OP_callpropvoid
:
452 s
+= abc
.names
[readU32
()]
453 s
+= " (" + readU32
() + ")"
455 case OP_newfunction
: {
456 var method_id
= readU32
()
457 s
+= abc
.methods
[method_id
]
461 s
+= abc
.methods
[readU32
()]
462 s
+= " (" + readU32
() + ")"
465 s
+= abc
.instances
[readU32
()]
467 case OP_lookupswitch
:
468 var pos
= code
.position
-1;
469 var target
= pos
+ readS24
()
470 var maxindex
= readU32
()
471 s
+= "default:" + labels
.labelFor
(target
) // target + "("+(target-pos)+")"
472 s
+= " maxcase:" + maxindex
473 for (var i
:int=0; i
<= maxindex
; i
++) {
474 target
= pos
+ readS24
();
475 s
+= " " + labels
.labelFor
(target
) // target + "("+(target-pos)+")"
479 case OP_iftrue
: case OP_iffalse
:
480 case OP_ifeq
: case OP_ifne
:
481 case OP_ifge
: case OP_ifnge
:
482 case OP_ifgt
: case OP_ifngt
:
483 case OP_ifle
: case OP_ifnle
:
484 case OP_iflt
: case OP_ifnlt
:
485 case OP_ifstricteq
: case OP_ifstrictne
:
486 var offset
= readS24
()
487 var target
= code
.position
+offset
488 //s += target + " ("+offset+")"
489 s
+= labels
.labelFor
(target
)
490 if (!((code
.position
) in labels
))
502 case OP_getglobalslot
:
504 case OP_setglobalslot
:
508 case OP_getouterscope
:
512 s
+= code
.readUnsignedByte
()
514 s
+= " " + code
.readUnsignedByte
()
518 s
+= "{" + readU32
() + "}"
521 s
+= "[" + readU32
() + "]"
525 case OP_constructsuper
:
527 s
+= "(" + readU32
() + ")"
530 case OP_getscopeobject
:
534 s
+= readU32
() + " " + readU32
()
536 /*if (opNames[opcode] == ("0x"+opcode.toString(16).toUpperCase()))
537 s += " UNKNOWN OPCODE"*/
540 var size
:int = code
.position
- start
542 opSizes
[opcode
] = int(opSizes
[opcode
]) + size
546 for each (var ex
in exceptions
)
547 dumpPrint
(indent
+ "// handler [" + ex
.from
+ ", " + ex
.to
+ "] -> " + ex
.target
+
548 (ex
.name
? (" " + ex
.name
+ ":" + ex
.type
) : (" :" + ex
.type
)));
550 dumpPrint
(oldindent
+"}\n")
553 popVersionMetadata
(mdpushed
)
556 function readU32
():int
558 var result
:int = code
.readUnsignedByte
();
559 if (!(result
& 0x00000080))
561 result
= result
& 0x0000007f | code
.readUnsignedByte
()<<7;
562 if (!(result
& 0x00004000))
564 result
= result
& 0x00003fff | code
.readUnsignedByte
()<<14;
565 if (!(result
& 0x00200000))
567 result
= result
& 0x001fffff | code
.readUnsignedByte
()<<21;
568 if (!(result
& 0x10000000))
570 return result
& 0x0fffffff | code
.readUnsignedByte
()<<28;
573 function readS24
():int
575 var b
:int = code
.readUnsignedByte
()
576 b
|= code
.readUnsignedByte
()<<8
577 b
|= code
.readByte
()<<16
582 class SlotInfo
extends MemberInfo
586 public function format
():String
588 return traitKinds
[kind
] + " " + name
.toString
(useMetadataVersions
) + ":" + type
+
589 (value
!== undefined ? (" = " + (value
is String ? ('"'+value
+'"') : value
)) : "") +
590 (doDumpAPI
? "" : "\t/* slot_id " + id
+ " */")
592 function dump
(abc
:Abc
, indent
:String, attr
:String="")
594 if(doDumpAPI
&& name
.isHidden
())
597 var mdpushed
:Boolean = pushVersionMetadata
(metadata
)
599 if (kind
== TRAIT_Const
|| kind
== TRAIT_Slot
)
601 if (metadata
&& !doDumpAPI
) {
602 for each (var md
in metadata
)
605 dumpPrint
(indent
+attr
+format
())
606 popVersionMetadata
(mdpushed
)
611 var ct
:Traits
= value
612 var it
:Traits
= ct
.itraits
614 if (metadata
&& !doDumpAPI
) {
615 for each (var md
in metadata
)
619 if (it
.flags
& CLASS_FLAG_interface
)
623 if (!(it
.flags
& CLASS_FLAG_sealed
))
624 def
= "dynamic " + def
;
625 if (it
.flags
& CLASS_FLAG_final
)
626 def
= "final " + def
;
629 dumpPrint
(indent
+attr
+def
+" "+name
.toString
(useMetadataVersions
)+" extends "+it
.base
)
630 var oldindent
= indent
632 if (it
.interfaces
.length
> 0)
633 dumpPrint
(indent
+"implements "+it
.interfaces
)
636 var prefix
:String = indent
+attr
+def
+" "+name
.toString
(useMetadataVersions
)+" "
637 it
.init
.dump
(abc
,prefix
)
638 it
.dump
(abc
,indent
,prefix
)
639 ct
.dump
(abc
,indent
,prefix
+ "static ")
640 ct
.init
.dump
(abc
,indent
,prefix
+ "static ")
642 dumpPrint
(oldindent
+"{")
643 it
.init
.dump
(abc
,indent
)
645 ct
.dump
(abc
,indent
,"static ")
646 ct
.init
.dump
(abc
,indent
,"static ")
647 dumpPrint
(oldindent
+"}\n")
650 popVersionMetadata
(mdpushed
)
661 var protectedNs
:ABCNamespace
662 const interfaces
:Array = []
663 const names
:Object = {}
664 const slots
:Array = []
665 const methods
:Array = []
666 const members
:Array = []
668 public function toString
():String
673 public function dump
(abc
:Abc
, indent
:String, attr
:String="")
675 for each (var m
in members
)
676 m
.dump
(abc
, indent
, attr
)
682 private var data
:ByteArray
695 var defaults
:Array = new Array(constantKinds
.length
)
703 var publicNs
= new ABCNamespace
("")
704 var anyNs
= new ABCNamespace
("*")
708 function Abc
(data
:ByteArray)
712 magic
= data
.readInt
()
714 infoPrint
("magic " + magic
.toString
(16))
716 if (magic
!= (46<<16|14) && magic
!= (46<<16|15) && magic
!= (46<<16|16))
717 throw new Error("not an abc file. magic=" + magic
.toString
(16))
721 defaults
[CONSTANT_Utf8
] = strings
722 defaults
[CONSTANT_Int
] = ints
723 defaults
[CONSTANT_UInt
] = uints
724 defaults
[CONSTANT_Double
] = doubles
725 defaults
[CONSTANT_Int
] = ints
726 defaults
[CONSTANT_False
] = { 10:false }
727 defaults
[CONSTANT_True
] = { 11:true }
728 defaults
[CONSTANT_Namespace
] = namespaces
729 defaults
[CONSTANT_PrivateNs
] = namespaces
730 defaults
[CONSTANT_PackageNs
] = namespaces
731 defaults
[CONSTANT_PackageInternalNs
] = namespaces
732 defaults
[CONSTANT_ProtectedNs
] = namespaces
733 defaults
[CONSTANT_StaticProtectedNs
] = namespaces
734 defaults
[CONSTANT_StaticProtectedNs2
] = namespaces
735 defaults
[CONSTANT_Null
] = { 12: null }
744 if (doExtractAbc
==true)
745 File.writeByteArray
(nextAbcFname
(), data
);
748 function readU32
():int
750 var result
:int = data
.readUnsignedByte
();
751 if (!(result
& 0x00000080))
753 result
= result
& 0x0000007f | data
.readUnsignedByte
()<<7;
754 if (!(result
& 0x00004000))
756 result
= result
& 0x00003fff | data
.readUnsignedByte
()<<14;
757 if (!(result
& 0x00200000))
759 result
= result
& 0x001fffff | data
.readUnsignedByte
()<<21;
760 if (!(result
& 0x10000000))
762 return result
& 0x0fffffff | data
.readUnsignedByte
()<<28;
765 function dumpPool
(name
:String, pool
:Array)
770 for(var i
:int = 0; i
<pool
.length
; i
++)
771 infoPrint
(name
+ "[" + i
+ "] = " + pool
[i
])
774 function padString
(s
:String, l
:uint)
777 return padString
(s
+ " ", l
)
781 function parseCpool
()
787 var start
:int = data
.position
792 for (i
=1; i
< n
; i
++)
794 dumpPool
("int", ints
)
799 for (i
=1; i
< n
; i
++)
800 uints
[i
] = uint(readU32
())
801 dumpPool
("uint", uints
)
806 for (i
=1; i
< n
; i
++)
807 doubles
[i
] = data
.readDouble
()
808 dumpPool
("double", doubles
)
810 infoPrint
("Cpool numbers size "+(data
.position
-start
)+" "+int(100*(data
.position
-start
)/data
.length
)+" %")
811 start
= data
.position
816 for (i
=1; i
< n
; i
++)
817 strings
[i
] = data
.readUTFBytes
(readU32
())
818 dumpPool
("string", strings
)
820 infoPrint
("Cpool strings count "+ n
+" size "+(data
.position
-start
)+" "+int(100*(data
.position
-start
)/data
.length
)+" %")
821 start
= data
.position
825 namespaces
= [publicNs
]
827 for (i
=1; i
< n
; i
++) {
828 switch (nskind
= data
.readByte
())
830 case CONSTANT_Namespace
:
831 case CONSTANT_PackageNs
:
832 case CONSTANT_PackageInternalNs
:
833 case CONSTANT_ProtectedNs
:
834 case CONSTANT_StaticProtectedNs
:
835 case CONSTANT_StaticProtectedNs2
:
837 namespaces
[i
] = new ABCNamespace
(strings
[readU32
()], nskind
)
840 case CONSTANT_PrivateNs
:
842 namespaces
[i
] = new ABCNamespace
("private", nskind
)
846 infoPrint
("namespace[" + i
+ "] = " + padString
(constantKinds
[nskind
], 20) + ": " + namespaces
[i
].uri
)
849 infoPrint
("Cpool namespaces count "+ n
+" size "+(data
.position
-start
)+" "+int(100*(data
.position
-start
)/data
.length
)+" %")
850 start
= data
.position
855 for (i
=1; i
< n
; i
++)
857 var count
:int = readU32
()
858 var nsset
= nssets
[i
] = []
860 for (j
=0; j
< count
; j
++) {
863 nsset
[j
] = namespaces
[nsid
]
866 infoPrint
("nsset[" + i
+ "] = {" + nsids
.join
(", ") + "}")
869 infoPrint
("Cpool nssets count "+ n
+" size "+(data
.position
-start
)+" "+int(100*(data
.position
-start
)/data
.length
)+" %")
870 start
= data
.position
875 namespaces
[0] = anyNs
876 strings
[0] = "*" // any name
877 for (i
=1; i
< n
; i
++) {
878 var nametype
= data
.readByte
()
882 case CONSTANT_QnameA
:
883 names
[i
] = new QualifiedName
(namespaces
[readU32
()], strings
[readU32
()])
886 case CONSTANT_RTQname
:
887 case CONSTANT_RTQnameA
:
888 names
[i
] = new QualifiedName
(null, strings
[readU32
()])
891 case CONSTANT_RTQnameL
:
892 case CONSTANT_RTQnameLA
:
897 case CONSTANT_NameLA
:
898 names
[i
] = new QualifiedName
(publicNs
, null)
901 case CONSTANT_Multiname
:
902 case CONSTANT_MultinameA
:
903 var name
= strings
[readU32
()]
904 names
[i
] = Multiname
.createMultiname
(nssets
[readU32
()], name
, doDumpAPI
)
907 case CONSTANT_MultinameL
:
908 case CONSTANT_MultinameLA
:
909 names
[i
] = Multiname
.createMultiname
(nssets
[readU32
()], null, doDumpAPI
)
912 case CONSTANT_TypeName
:
913 var name
= names
[readU32
()];
914 var count
= readU32
();
916 for( var t
=0; t
< count
; ++t
)
917 types
.push
(names
[readU32
()]);
918 names
[i
] = new TypeName
(name
, types
);
922 throw new Error("invalid kind " + data
[data
.position
-1])
925 infoPrint
("name[" + i
+ "] = " + padString
(constantKinds
[nametype
], 12) + ": " + names
[i
])
928 infoPrint
("Cpool names count "+ n
+" size "+(data
.position
-start
)+" "+int(100*(data
.position
-start
)/data
.length
)+" %")
929 start
= data
.position
931 namespaces
[0] = publicNs
935 function parseMethodInfos
()
937 var start
:int = data
.position
938 names
[0] = new QualifiedName
(publicNs
, "*")
939 var method_count
:int = readU32
()
941 for (var i
:int=0; i
< method_count
; i
++)
943 var m
= methods
[i
] = new MethodInfo
()
945 var param_count
:int = readU32
()
946 m
.returnType
= names
[readU32
()]
948 for (var j
:int=0; j
< param_count
; j
++)
949 m
.paramTypes
[j
] = names
[readU32
()]
950 m
.debugName
= strings
[readU32
()]
951 m
.flags
= data
.readByte
()
952 if (m
.flags
& HAS_OPTIONAL
)
955 var optional_count
:int = readU32
();
956 m
.optionalValues
= []
957 for( var k
:int = param_count
-optional_count
; k
< param_count
; ++k
)
959 var index
= readU32
() // optional value index
960 var kind
:int = data
.readByte
() // kind byte for each default value
963 // kind is ignored, default value is based on type
964 m
.optionalValues
[k
] = undefined
969 print
("ERROR kind="+kind
+" method_id " + i
)
971 m
.optionalValues
[k
] = defaults
[kind
][index
]
975 if (m
.flags
& HAS_ParamNames
)
978 for( var k
:int = 0; k
< param_count
; ++k
)
984 infoPrint
("MethodInfo count " +method_count
+ " size "+(data
.position
-start
)+" "+int(100*(data
.position
-start
)/data
.length
)+" %")
987 function parseMetadataInfos
()
989 var start
:int = data
.position
990 var count
:int = readU32
()
992 for (var i
:int=0; i
< count
; i
++)
995 var m
= metadata
[i
] = new MetaData
()
996 m
.name
= strings
[readU32
()];
997 var values_count
:int = readU32
();
1000 var values
:Array = []
1002 for(var q
:int = 0; q
< values_count
; ++q
)
1003 keys
[q
] = strings
[readU32
()]
1004 for(var q
:int = 0; q
< values_count
; ++q
)
1005 values
[q
] = strings
[readU32
()]
1007 for(var q
:int = 0; q
< values_count
; ++q
)
1008 m
.addPair
(keys
[q
], values
[q
])
1011 infoPrint
("metadata[" + i
+ "] = {" + m
.tuples
.join
(", ") + "}")
1013 infoPrint
("MetadataInfo count " +values_count
+ " size "+(data
.position
-start
)+" "+int(100*(data
.position
-start
)/data
.length
)+" %")
1016 function parseInstanceInfos
()
1018 var start
:int = data
.position
1019 var count
:int = readU32
()
1021 for (var i
:int=0; i
< count
; i
++)
1023 var t
= instances
[i
] = new Traits
()
1024 t
.name
= names
[readU32
()]
1025 t
.base
= names
[readU32
()]
1026 t
.flags
= data
.readByte
()
1028 t
.protectedNs
= namespaces
[readU32
()]
1029 var interface_count
= readU32
()
1030 for (var j
:int=0; j
< interface_count
; j
++)
1031 t
.interfaces
[j
] = names
[readU32
()]
1032 var m
= t
.init
= methods
[readU32
()]
1034 m
.kind
= TRAIT_Method
1038 infoPrint
("InstanceInfo count " + count
+ " size "+(data
.position
-start
)+" "+int(100*(data
.position
-start
)/data
.length
)+" %")
1041 function parseTraits
(t
:Traits
)
1043 var namecount
= readU32
()
1044 for (var i
:int=0; i
< namecount
; i
++)
1046 var name
= names
[readU32
()]
1047 var tag
= data
.readByte
()
1048 var kind
= tag
& 0xf
1054 var slot
= member
= new SlotInfo
()
1056 t
.slots
[slot
.id
] = slot
1057 if (kind
==TRAIT_Slot
|| kind
==TRAIT_Const
)
1059 slot
.type
= names
[readU32
()]
1062 slot
.value
= defaults
[data
.readByte
()][index
]
1064 else // (kind == TRAIT_Class)
1066 slot
.value
= classes
[readU32
()]
1072 var disp_id
= readU32
()
1073 var method
= member
= methods
[readU32
()]
1074 t
.methods
[disp_id
] = method
1076 //print("\t",traitKinds[kind],name,disp_id,method,"// disp_id", disp_id)
1080 print
("error trait kind "+kind
)
1083 t
.names
[String(name
)] = t
.members
[i
] = member
1085 if ( (tag
>> 4) & ATTR_metadata
) {
1086 member
.metadata
= []
1087 for(var j
:int=0, mdCount
:int=readU32
(); j
< mdCount
; ++j
)
1088 member
.metadata
[j
] = metadata
[readU32
()]
1093 function parseClassInfos
()
1095 var start
:int = data
.position
1096 var count
:int = instances
.length
1098 for (var i
:int=0; i
< count
; i
++)
1100 var t
:Traits
= classes
[i
] = new Traits
()
1101 t
.init
= methods
[readU32
()]
1103 t
.itraits
= instances
[i
]
1104 t
.name
= t
.itraits
.name
+ "$"
1105 t
.init
.name
= t
.itraits
.name
+ "$cinit"
1106 t
.init
.kind
= TRAIT_Method
1109 infoPrint
("ClassInfo count " + count
+ " size "+(data
.position
-start
)+" "+int(100*(data
.position
-start
)/data
.length
)+"%")
1112 function parseScriptInfos
()
1114 var start
:int = data
.position
1115 var count
:int = readU32
()
1117 for (var i
:int=0; i
< count
; i
++)
1119 var t
= new Traits
()
1121 t
.name
= "script" + i
1122 t
.base
= names
[0] // Object
1123 t
.init
= methods
[readU32
()]
1124 t
.init
.name
= t
.name
+ "$init"
1125 t
.init
.kind
= TRAIT_Method
1128 infoPrint
("ScriptInfo size "+(data
.position
-start
)+" "+int(100*(data
.position
-start
)/data
.length
)+" %")
1131 function parseMethodBodies
()
1133 var start
:int = data
.position
1134 var count
:int = readU32
()
1135 for (var i
:int=0; i
< count
; i
++)
1137 var m
= methods
[readU32
()]
1138 m
.max_stack
= readU32
()
1139 m
.local_count
= readU32
()
1140 var initScopeDepth
= readU32
()
1141 var maxScopeDepth
= readU32
()
1142 m
.max_scope
= maxScopeDepth
- initScopeDepth
1143 var code_length
= readU32
()
1144 m
.code
= new ByteArray()
1145 m
.code
.endian
= "littleEndian"
1146 if (code_length
> 0) {
1147 m
.code_offset
= data
.position
;
1148 data
.readBytes
(m
.code
, 0, code_length
)
1150 var ex_count
= readU32
()
1153 for (var j
:int = 0; j
< ex_count
; j
++)
1155 var ex
= new ExceptionInfo
()
1156 m
.exceptions
.push
(ex
)
1159 ex
.target
= readU32
()
1160 ex
.type
= names
[readU32
()]
1161 //print("magic " + magic.toString(16))
1162 //if (magic >= (46<<16|16))
1163 ex
.name
= names
[readU32
()];
1164 //infoPrint("exception method_id=" + i + " [" + ex.from + ", " + ex.to + "] " + ex.type + " -> " + ex.target)
1167 parseTraits
(m
.activation
= new Traits
)
1169 infoPrint
("MethodBodies count " + count
+ " size "+(data
.position
-start
)+" "+int(100*(data
.position
-start
)/data
.length
)+" %")
1172 function dump
(indent
:String="")
1174 for each (var t
in scripts
)
1176 infoPrint
(indent
+t
.name
)
1178 t
.init
.dump
(this,indent
)
1181 for each (var m
in methods
)
1187 infoPrint
("OPCODE\tSIZE\t% OF "+totalSize
)
1192 var maxsize
:int = 0;
1193 for (var i
:int=0; i
< 256; i
++)
1195 if (opSizes
[i
] > maxsize
&& !done
[i
])
1198 maxsize
= opSizes
[i
];
1204 infoPrint
(opNames
[max
]+"\t"+int(opSizes
[max
])+"\t"+int(100*opSizes
[max
]/totalSize
)+"%")
1212 var xMin
:int, xMax
:int
1213 var yMin
:int, yMax
:int
1214 public function toString
()
1216 return "[Rect "+xMin
+" "+yMin
+" "+xMax
+" "+yMax
+"]"
1220 const stagDoABC
:int = 72; // embedded .abc (AVM+) bytecode
1221 const stagSymbolClass
:int = 76;
1222 const stagMetadata
:int = 77;
1223 const stagDoABC2
:int = 82; // revised ABC version with a name
1225 var tagNames
:Array = [
1228 "DefineShape", // 02
1229 "FreeCharacter", // 03
1230 "PlaceObject", // 04
1231 "RemoveObject", // 05
1233 "DefineButton", // 07
1235 "SetBackgroundColor", // 09
1240 "DefineFontInfo", // 13
1242 "DefineSound", // 14
1246 "DefineButtonSound", // 17
1248 "SoundStreamHead", // 18
1249 "SoundStreamBlock", // 19
1251 "DefineBitsLossless", // 20
1252 "DefineBitsJPEG2", // 21
1254 "DefineShape2", // 22
1255 "DefineButtonCxform", // 23
1259 "PathsArePostScript", // 25
1261 "PlaceObject2", // 26
1262 "27 (invalid)", // 27
1263 "RemoveObject2", // 28
1266 "30 (invalid)", // 30
1269 "DefineShape3", // 32
1270 "DefineText2", // 33
1271 "DefineButton2", // 34
1272 "DefineBitsJPEG3", // 35
1273 "DefineBitsLossless2", // 36
1274 "DefineEditText", // 37
1276 "DefineVideo", // 38
1278 "DefineSprite", // 39
1279 "NameCharacter", // 40
1280 "ProductInfo", // 41
1281 "DefineTextFormat", // 42
1283 "DefineBehavior", // 44
1284 "SoundStreamHead2", // 45
1285 "DefineMorphShape", // 46
1287 "DefineFont2", // 48
1289 "DefineCommandObj", // 50
1290 "CharacterSet", // 51
1293 "DefineFunction", // 53
1294 "PlaceFunction", // 54
1296 "GenTagObject", // 55
1298 "ExportAssets", // 56
1299 "ImportAssets", // 57
1301 "EnableDebugger", // 58
1303 "DoInitAction", // 59
1304 "DefineVideoStream", // 60
1307 "DefineFontInfo2", // 62
1309 "EnableDebugger2", // 64
1310 "ScriptLimits", // 65
1312 "SetTabIndex", // 66
1314 "DefineShape4", // 67
1315 "DefineMorphShape2", // 68
1317 "FileAttributes", // 69
1319 "PlaceObject3", // 70
1320 "ImportAssets2", // 71
1323 "DefineFontAlignZones", // 73
1324 "CSMSettings", // 74
1325 "DefineFont3", // 75
1326 "SymbolClass", // 76
1328 "DefineScalingGrid", // 78
1329 "DefineDeviceVideo", // 79
1330 "80 (invalid)", // 80
1331 "81 (invalid)", // 81
1333 "DefineShape4", // 83
1334 "DefineMorphShape2", // 84
1335 "PlaceImagePrivate", // 85
1336 "DefineSceneAndFrameLabelData", // 86
1337 "DefineBinaryData", // 87
1338 "DefineFontName", // 88
1340 "DefineBitsJPEG64", // 90
1341 "DefineFont4", // 91
1347 private var bitPos
:int
1348 private var bitBuf
:int
1350 private var data
:ByteArray
1352 function Swf
(data
:ByteArray)
1355 infoPrint
("size "+decodeRect
())
1356 infoPrint
("frame rate "+(data
.readUnsignedByte
()<<8|data
.readUnsignedByte
()))
1357 infoPrint
("frame count "+data
.readUnsignedShort
())
1361 private function decodeTags
()
1363 var type
:int, h
:int, length
:int
1366 while (data
.position
< data
.length
)
1368 type
= (h
= data
.readUnsignedShort
()) >> 6;
1370 if (((length
= h
& 0x3F) == 0x3F))
1371 length
= data
.readInt
();
1373 var tagN
= tagNames
[type
]
1374 if (type
>= tagNames
.length
)
1375 tagN
= type
+" (unknown)"
1377 infoPrint
(tagN
+" "+length
+"b "+int(100*length
/data
.length
)+"%")
1382 var pos1
:int = data
.position
1384 infoPrint
("\nabc name "+readString
())
1385 length
-= (data
.position
-pos1
)
1388 var data2
= new ByteArray
1389 data2
.endian
= "littleEndian"
1390 data
.readBytes
(data2
,0,length
)
1391 new Abc
(data2
).dump
(" ")
1395 infoPrint
(new XML(readString
()));
1398 data
.position
+= length
1403 private function readString
():String
1408 while (c
=data
.readUnsignedByte
())
1409 s
+= String.fromCharCode
(c
)
1414 private function syncBits
()
1419 private function decodeRect
():Rect
1423 var rect
:Rect
= new Rect
();
1425 var nBits
:int = readUBits
(5)
1426 rect
.xMin
= readSBits
(nBits
);
1427 rect
.xMax
= readSBits
(nBits
);
1428 rect
.yMin
= readSBits
(nBits
);
1429 rect
.yMax
= readSBits
(nBits
);
1434 function readSBits
(numBits
:int):int
1437 throw new Error("Number of bits > 32");
1439 var num
:int = readUBits
(numBits
);
1440 var shift
:int = 32-numBits
;
1442 num
= (num
<< shift
) >> shift
;
1446 function readUBits
(numBits
:int):uint
1451 var bitsLeft
:int = numBits
;
1454 if (bitPos
== 0) //no value in the buffer - read a byte
1456 bitBuf
= data
.readUnsignedByte
()
1462 var shift
:int = bitsLeft
- bitPos
;
1465 // Consume the entire buffer
1466 result
|= bitBuf
<< shift
;
1469 // Get the next byte from the input stream
1470 bitBuf
= data
.readUnsignedByte
();
1475 // Consume a portion of the buffer
1476 result
|= bitBuf
>> -shift
;
1478 bitBuf
&= 0xff >> (8 - bitPos
); // mask off the consumed bits
1480 // if (print) System.out.println(" read"+numBits+" " + result);
1485 // unreachable, but fixes a spurious compiler warning
1496 function processArg
(arg
:String)
1499 doExtractAbc
= true;
1500 doExtractInfo
= false
1501 doExtractAbs
= false
1502 } else if (arg
== '-i') {
1503 // suppress abs output
1504 doExtractAbs
= false;
1505 } else if (arg
== '-abs') {
1506 // suppress info output
1507 doExtractInfo
= false
1508 } else if (arg
== '-api') {
1510 doExtractInfo
= false
1511 } else if (arg
== '-mdversions') {
1512 useMetadataVersions
= true
1513 } else if (arg
== '-pools') {
1516 print
('Unknown option '+arg
)
1521 function nextAbcFname
():String
1523 var s
= currentFname
1524 if (currentFcount
>0)
1525 s
= s
.concat
(currentFcount
);
1531 var doExtractAbc
= false
1532 var doExtractInfo
= true
1533 var doExtractAbs
= true
1534 var doDumpAPI
= false
1535 var doDumpPools
= false
1536 var useMetadataVersions
= false
1537 var currentFname
= ''
1538 var currentFcount
= 0
1539 for each (var file
in System.argv
)
1541 if (file
.indexOf
('-')==0)
1548 if ((x
= file
.lastIndexOf
(".swf")) != -1 || (x
= file
.lastIndexOf
(".swc")) != -1)
1549 currentFname
= file
.substring
(0,x
);
1551 currentFname
= file
;
1552 var data
:ByteArray = File.readByteArray
(file
)
1553 data
.endian
= "littleEndian"
1554 var version
:uint = data
.readUnsignedInt
()
1559 var abc
:Abc
= new Abc
(data
)
1562 case 67|87<<8|83<<16|10<<24: // SWC10
1563 case 67|87<<8|83<<16|9<<24: // SWC9
1564 case 67|87<<8|83<<16|8<<24: // SWC8
1565 case 67|87<<8|83<<16|7<<24: // SWC7
1566 case 67|87<<8|83<<16|6<<24: // SWC6
1567 var udata
:ByteArray = new ByteArray
1568 udata
.endian
= "littleEndian"
1570 data
.readBytes
(udata
,0,data
.length
-data
.position
)
1571 var csize
:int = udata
.length
1573 infoPrint
("decompressed swf "+csize
+" -> "+udata
.length
)
1575 /*var swf:Swf =*/ new Swf
(udata
)
1577 case 70|87<<8|83<<16|10<<24: // SWF10
1578 case 70|87<<8|83<<16|9<<24: // SWF9
1579 case 70|87<<8|83<<16|8<<24: // SWF8
1580 case 70|87<<8|83<<16|7<<24: // SWF7
1581 case 70|87<<8|83<<16|6<<24: // SWF6
1582 case 70|87<<8|83<<16|5<<24: // SWF5
1583 case 70|87<<8|83<<16|4<<24: // SWF4
1584 data
.position
= 8 // skip header and length
1585 /*var swf:Swf =*/ new Swf
(data
)
1588 print
('unknown format '+version
)
1593 if (System.argv
.length
< 1)