 
 package abcdump
 {
-	import flash.utils.ByteArray
-	import avmplus.System
-
-	include "abc-constants.as"
-	
-	var usage = [
-	"Displays the contents of abc or swf files",
-	"",
-	"Usage:",
-	"",
-	"    abcdump [options] file ...",
-	"",
-	"Each file can be an ABC or SWF/SWC format file",
-	"",
-	"Options:",
-	"",
-	" -a   Extract the ABC blocks from the SWF/SWC, but do not",
-	"      otherwise display their contents.  The file names are",
-	"      of the form file<n>.abc where \"file\" is the name",
-	"      of the input file minus the .swf/.swc extension;",
-	"      and <n> is omitted if it is 0.",
-	"",
-	" -i   Print information about the ABC, but do not dump the",
-	"      byte code.",
-	].join("\n");
-
-	const TAB = "  "
-	
-	var totalSize:int
-	var opSizes:Array = new Array(256)
-
-	function dumpPrint(s) {
-	    if (!(doExtractAbc || doExtractInfo))
-		    print(s);
-    }
-
-	function infoPrint(s) {
-	    if (doExtractInfo || !doExtractAbc)
-		    print(s);
-	}
-
-	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
-		}
-	}
-	
-	class TypeName
+    import flash.utils.ByteArray
+    import avmplus.System
+
+    include "abc-constants.as"
+    
+    var usage = [
+    "Displays the contents of abc or swf files",
+    "",
+    "Usage:",
+    "",
+    "    abcdump [options] file ...",
+    "",
+    "Each file can be an ABC or SWF/SWC format file",
+    "",
+    "Options:",
+    "",
+    " -a   Extract the ABC blocks from the SWF/SWC, but do not",
+    "      otherwise display their contents.  The file names are",
+    "      of the form file<n>.abc where \"file\" is the name",
+    "      of the input file minus the .swf/.swc extension;",
+    "      and <n> is omitted if it is 0.",
+    "",
+    " -i   Print information about the ABC, but do not dump the",
+    "      byte code.",
+    ].join("\n");
+
+    const TAB = "  "
+    
+    var totalSize:int
+    var opSizes:Array = new Array(256)
+
+    function dumpPrint(s) {
+        if (!(doExtractAbc || doExtractInfo))
+            print(s);
+    }
+
+    function infoPrint(s) {
+        if (doExtractInfo || !doExtractAbc)
+            print(s);
+    }
+
+    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
+        }
+    }
+    
+    class TypeName
     {
         var name;
         var types:Array;

/* -*- tab-width: 4 -*- */
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1

                    names[i] = new TypeName(name, types);
                    break;
                    
                default:
                    throw new Error("invalid kind " + data[data.position-1])
                }

            infoPrint("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();
                    }
                }
            }
            infoPrint("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)
            }
            infoPrint("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)
            }           
            infoPrint("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)
            }
            infoPrint("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)
            }
            infoPrint("MethodBodies size "+(data.position-start)+" "+int(100*(data.position-start)/data.length)+" %")
        }
        
        function dump(indent:String="")
        {
            for each (var t in scripts)
            {
                dumpPrint(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)
                }
            }

            infoPrint("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;
                infoPrint(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
