 
 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;

                    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

/* -*- indent-tabs-mode: nil; 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
