Пример #1
0
        /// <summary>
        /// Writes out the constants to the SWF file. This will also re-set the tables in the
        /// code object, so be sure you don't have anything in there that you need.
        /// </summary>
        /// <param name="writer">Where to write the constants to.</param>
        /// <param name="code">The code object with the tables in it, that we'll
        /// overwrite.</param>
        private void WriteConstantPool(ABCDataTypeWriter writer, AbcCode code)
        {
            /* Integer constants */
            int[] ints = this.intMarshal.ToArray();
            writer.WriteU30Packed((uint)(ints.Length == 1 ? 0 : ints.Length));
            for (int i = 1; i < ints.Length; i++) /* Omit value at [0] */
            {
#if DEBUG
                this.writeLog.AppendLine("Const int #" + i + ": " + ints[i]);
#endif

                writer.WriteSI32(ints[i]);
            }

            code.IntConsts = ints;

            /* Unsigned integer constants */
            uint[] uints = this.uintMarshal.ToArray();
            writer.WriteU30Packed((uint)(uints.Length == 1 ? 0 : uints.Length));
            for (int i = 1; i < uints.Length; i++) /* Omit value at [0] */
            {
#if DEBUG
                this.writeLog.AppendLine("Const uint #" + i + ": " + uints[i]);
#endif
                writer.WriteUI32(uints[i]);
            }

            code.UIntConsts = uints;

            /* Double constants */
            ulong[] doubles = this.doubleMarshal.ToArray();
            writer.WriteU30Packed((uint)(doubles.Length == 1 ? 0 : doubles.Length));
            for (int i = 1; i < doubles.Length; i++) /* Omit value at [0] */
            {
#if DEBUG
                this.writeLog.AppendLine("Const double (bits) #" + i + ": " + doubles[i]);
#endif

                /* We hack this here instead of having a U64 type, because it's a hack around not
                 * treating double properly. There's no such thing as U64 in SWF. */
                ulong d   = doubles[i];
                uint  low = (uint)(d & 0x00000000FFFFFFFF);
                d >>= 32;
                uint high = (uint)(d & 0x00000000FFFFFFFF);

                writer.WriteUI32(high);
                writer.WriteUI32(low);
            }

            code.DoubleConsts = doubles;

            /* String constants */
            string[] strings = this.stringMarshal.ToArray();
            writer.WriteU30Packed((uint)(strings.Length == 1 ? 0 : strings.Length));
            for (int i = 1; i < strings.Length; i++) /* Omit value at [0] */
            {
#if DEBUG
                this.writeLog.AppendLine("Const string #" + i + ": \"" + strings[i] + "\"");
#endif
                writer.WriteString(strings[i]);
            }

            code.StringConsts = strings;

            /* Namespace constants */
            Namespace[] namespaces = this.nsMarshal.ToArray();
            writer.WriteU30Packed((uint)(namespaces.Length == 1 ? 0 : namespaces.Length));
            for (int i = 1; i < namespaces.Length; i++) /* Omit value at [0] */
            {
#if DEBUG
                this.writeLog.AppendLine("Const ns #" + i + ": " + namespaces[i]);
#endif
                Namespace ns = namespaces[i];
                writer.WriteUI8((uint)ns.Kind);
                writer.WriteU30Packed((uint)this.stringMarshal.GetExistingIDFor(ns.Name));
            }

            code.SetNamespaces(namespaces);

            /* Namespace set constants */
            NamespaceSet[] namespaceSets = this.nsSetMarshal.ToArray();
            writer.WriteU30Packed((uint)(namespaceSets.Length == 1 ? 0 : namespaceSets.Length));
            for (int i = 1; i < namespaceSets.Length; i++) /* Omit value at [0] */
            {
#if DEBUG
                this.writeLog.AppendLine("Const ns set #" + i + ": " + namespaceSets[i]);
#endif
                NamespaceSet nss = namespaceSets[i];

                writer.WriteU30Packed((uint)nss.Count);

                foreach (Namespace ns in nss)
                {
                    writer.WriteU30Packed((uint)this.nsMarshal.GetExistingIDFor(ns));
                }
            }

            code.SetNamespaceSets(namespaceSets);

            /* Multiname constants */
            Multiname[] multinames = this.multinameMarshal.ToArray();
            writer.WriteU30Packed((uint)(multinames.Length == 1 ? 0 : multinames.Length));
            for (int i = 1; i < multinames.Length; i++) /* Omit value at [0] */
            {
#if DEBUG
                this.writeLog.AppendLine("Const mn set #" + i + ": " + multinames[i]);
#endif
                Multiname mn = multinames[i];

                writer.WriteUI8((uint)mn.Kind);

                switch (mn.Kind)
                {
                case Multiname.MultinameKind.QName:
                case Multiname.MultinameKind.QNameA:
                    uint nsIdx   = (uint)this.nsMarshal.GetExistingIDFor(mn.NS);
                    uint nameIdx = (uint)this.stringMarshal.GetExistingIDFor(mn.Name);
                    writer.WriteU30Packed(nsIdx);
                    writer.WriteU30Packed(nameIdx);
                    break;

                case Multiname.MultinameKind.RTQName:
                case Multiname.MultinameKind.RTQNameA:
                    writer.WriteU30Packed((uint)this.stringMarshal.GetExistingIDFor(mn.Name));
                    break;

                case Multiname.MultinameKind.RTQNameL:
                case Multiname.MultinameKind.RTQNameLA:
                    /* No data */
                    break;

                case Multiname.MultinameKind.Multiname:
                case Multiname.MultinameKind.MultinameA:
                    writer.WriteU30Packed((uint)this.stringMarshal.GetExistingIDFor(mn.Name));
                    writer.WriteU30Packed((uint)this.nsSetMarshal.GetExistingIDFor(mn.Set));
                    break;

                case Multiname.MultinameKind.MultinameL:
                case Multiname.MultinameKind.MultinameLA:
                    writer.WriteU30Packed((uint)this.nsSetMarshal.GetExistingIDFor(mn.Set));
                    break;

                default:
                    break;
                }
            }

            code.SetMultinames(multinames);
        }
Пример #2
0
        /// <summary>
        /// Writes out the constants to the SWF file. This will also re-set the tables in the
        /// code object, so be sure you don't have anything in there that you need.
        /// </summary>
        /// <param name="writer">Where to write the constants to.</param>
        /// <param name="code">The code object with the tables in it, that we'll
        /// overwrite.</param>
        private void WriteConstantPool(ABCDataTypeWriter writer, AbcCode code)
        {
            /* Integer constants */
            int[] ints = this.intMarshal.ToArray();
            writer.WriteU30Packed((uint)(ints.Length == 1 ? 0 : ints.Length));
            for (int i = 1; i < ints.Length; i++) /* Omit value at [0] */
            {
            #if DEBUG
                this.writeLog.AppendLine("Const int #" + i + ": " + ints[i]);
            #endif

                writer.WriteSI32(ints[i]);
            }

            code.IntConsts = ints;

            /* Unsigned integer constants */
            uint[] uints = this.uintMarshal.ToArray();
            writer.WriteU30Packed((uint)(uints.Length == 1 ? 0 : uints.Length));
            for (int i = 1; i < uints.Length; i++) /* Omit value at [0] */
            {
            #if DEBUG
                this.writeLog.AppendLine("Const uint #" + i + ": " + uints[i]);
            #endif
                writer.WriteUI32(uints[i]);
            }

            code.UIntConsts = uints;

            /* Double constants */
            ulong[] doubles = this.doubleMarshal.ToArray();
            writer.WriteU30Packed((uint)(doubles.Length == 1 ? 0 : doubles.Length));
            for (int i = 1; i < doubles.Length; i++) /* Omit value at [0] */
            {
            #if DEBUG
                this.writeLog.AppendLine("Const double (bits) #" + i + ": " + doubles[i]);
            #endif
                /* We hack this here instead of having a U64 type, because it's a hack around not
                 * treating double properly. There's no such thing as U64 in SWF. */
                ulong d = doubles[i];
                uint low = (uint)(d & 0x00000000FFFFFFFF);
                d >>= 32;
                uint high = (uint)(d & 0x00000000FFFFFFFF);

                writer.WriteUI32(high);
                writer.WriteUI32(low);
            }

            code.DoubleConsts = doubles;

            /* String constants */
            string[] strings = this.stringMarshal.ToArray();
            writer.WriteU30Packed((uint)(strings.Length == 1 ? 0 : strings.Length));
            for (int i = 1; i < strings.Length; i++) /* Omit value at [0] */
            {
            #if DEBUG
                this.writeLog.AppendLine("Const string #" + i + ": \"" + strings[i] + "\"");
            #endif
                writer.WriteString(strings[i]);
            }

            code.StringConsts = strings;

            /* Namespace constants */
            Namespace[] namespaces = this.nsMarshal.ToArray();
            writer.WriteU30Packed((uint)(namespaces.Length == 1 ? 0 : namespaces.Length));
            for (int i = 1; i < namespaces.Length; i++) /* Omit value at [0] */
            {
            #if DEBUG
                this.writeLog.AppendLine("Const ns #" + i + ": " + namespaces[i]);
            #endif
                Namespace ns = namespaces[i];
                writer.WriteUI8((uint)ns.Kind);
                writer.WriteU30Packed((uint)this.stringMarshal.GetExistingIDFor(ns.Name));
            }

            code.SetNamespaces(namespaces);

            /* Namespace set constants */
            NamespaceSet[] namespaceSets = this.nsSetMarshal.ToArray();
            writer.WriteU30Packed((uint)(namespaceSets.Length == 1 ? 0 : namespaceSets.Length));
            for (int i = 1; i < namespaceSets.Length; i++) /* Omit value at [0] */
            {
            #if DEBUG
                this.writeLog.AppendLine("Const ns set #" + i + ": " + namespaceSets[i]);
            #endif
                NamespaceSet nss = namespaceSets[i];

                writer.WriteU30Packed((uint)nss.Count);

                foreach (Namespace ns in nss)
                {
                    writer.WriteU30Packed((uint)this.nsMarshal.GetExistingIDFor(ns));
                }
            }

            code.SetNamespaceSets(namespaceSets);

            /* Multiname constants */
            Multiname[] multinames = this.multinameMarshal.ToArray();
            writer.WriteU30Packed((uint)(multinames.Length == 1 ? 0 : multinames.Length));
            for (int i = 1; i < multinames.Length; i++) /* Omit value at [0] */
            {
            #if DEBUG
                this.writeLog.AppendLine("Const mn set #" + i + ": " + multinames[i]);
            #endif
                Multiname mn = multinames[i];

                writer.WriteUI8((uint)mn.Kind);

                switch (mn.Kind)
                {
                    case Multiname.MultinameKind.QName:
                    case Multiname.MultinameKind.QNameA:
                        uint nsIdx = (uint)this.nsMarshal.GetExistingIDFor(mn.NS);
                        uint nameIdx = (uint)this.stringMarshal.GetExistingIDFor(mn.Name);
                        writer.WriteU30Packed(nsIdx);
                        writer.WriteU30Packed(nameIdx);
                        break;

                    case Multiname.MultinameKind.RTQName:
                    case Multiname.MultinameKind.RTQNameA:
                        writer.WriteU30Packed((uint)this.stringMarshal.GetExistingIDFor(mn.Name));
                        break;

                    case Multiname.MultinameKind.RTQNameL:
                    case Multiname.MultinameKind.RTQNameLA:
                        /* No data */
                        break;

                    case Multiname.MultinameKind.Multiname:
                    case Multiname.MultinameKind.MultinameA:
                        writer.WriteU30Packed((uint)this.stringMarshal.GetExistingIDFor(mn.Name));
                        writer.WriteU30Packed((uint)this.nsSetMarshal.GetExistingIDFor(mn.Set));
                        break;

                    case Multiname.MultinameKind.MultinameL:
                    case Multiname.MultinameKind.MultinameLA:
                        writer.WriteU30Packed((uint)this.nsSetMarshal.GetExistingIDFor(mn.Set));
                        break;

                    default:
                        break;
                }
            }

            code.SetMultinames(multinames);
        }
Пример #3
0
        private void AssembleMethod(Method method)
        {
            MemoryStream      buf    = new MemoryStream();
            ABCDataTypeWriter writer = new ABCDataTypeWriter(buf);

            this.methodMarshal.Register(method);

            using (IEnumerator <ExceptionHandler> i = method.ExceptionHandlers)
            {
                while (i.MoveNext())
                {
                    ExceptionHandler eh = i.Current;
                    this.RegisterMultiname(eh.CatchType);
                    this.RegisterMultiname(eh.VarName);
                }
            }

            bool insertDebugCodes = this.InsertDebugCodes;

            if (insertDebugCodes)
            {
                /* Quick check to see if the code already has them, in which case we
                 * won't bother. */
                foreach (Opcode op in method.Opcodes)
                {
                    if (op.Mnemonic == Opcode.Mnemonics.DebugFile || op.Mnemonic == Opcode.Mnemonics.DebugLine)
                    {
                        insertDebugCodes = false;
                        break;
                    }
                }
            }

            IEnumerable <Opcode> opcodes = method.Opcodes;

            if (insertDebugCodes)
            {
                List <Opcode> debugged = new List <Opcode>();

                debugged.Add(Opcode.CreateDebugFile(method.SourceFile));

                /* Let's just check this string won't break things... */
                uint srcPos = (uint)this.stringMarshal.GetIDFor(method.SourceFile);
                if (srcPos > 255)
                {
                    /* ISSUE 10: Best fix may be to strip out debug opcodes. */
                    throw new SWFModellerException(
                              SWFModellerError.CodeMerge,
                              "Marshaller failed to keep debug string at low index");
                }

                uint lineNumber = 1; /* For our fake debug info. */
                foreach (Opcode op in opcodes)
                {
                    debugged.Add(Opcode.CreateDebugLine(lineNumber++));
                    debugged.Add(op);
                }

                opcodes = debugged;
            }

            Dictionary <Opcode, int> offsetMap = new Dictionary <Opcode, int>();
            Dictionary <Opcode, int> lenMap    = new Dictionary <Opcode, int>();
            List <KeyValuePair <Opcode, KeyValuePair <Opcode, int> > > unresolvedOffsets = new List <KeyValuePair <Opcode, KeyValuePair <Opcode, int> > >();

            foreach (Opcode op in opcodes)
            {
                int startOffset = (int)writer.Offset;
                offsetMap.Add(op, startOffset);

                writer.WriteUI8(op.Instruction);

                if (op.Mnemonic == Opcode.Mnemonics.LookupSwitch)
                {
                    for (int i = 0; i < op.Args.Length; i++)
                    {
                        int argOffset = (int)writer.Offset - startOffset;
                        KeyValuePair <Opcode, int> sourceInfo = new KeyValuePair <Opcode, int>(op, argOffset);
                        object argOb = op.Args[i];
                        if (i == 1)
                        {
                            writer.WriteU30Packed((uint)(op.Args.Length - 3));
                        }
                        else
                        {
                            unresolvedOffsets.Add(new KeyValuePair <Opcode, KeyValuePair <Opcode, int> >((Opcode)argOb, sourceInfo));
                            writer.WriteSI24(0x00FFDEAD); /* Because dead beef won't fit in 3 bytes. */
                        }
                    }

                    lenMap.Add(op, 0);
                    continue;
                }

                Opcode.ArgType[] types = op.ArgTypes;
                if (types == null)
                {
                    /* done. */
                    lenMap.Add(op, (int)writer.Offset - startOffset);
                    continue;
                }

                if (types.Length != op.Args.Length)
                {
                    throw new SWFModellerException(
                              SWFModellerError.Internal,
                              "Arg mismatch in op " + op + " (" + types.Length + " expected)");
                }

                for (int i = 0; i < op.Args.Length; i++)
                {
                    object         argOb   = op.Args[i];
                    Opcode.ArgType argType = types[i];

                    switch (argType)
                    {
                    case Opcode.ArgType.MultinameU30:
                        writer.WriteU30Packed((uint)this.MultinameID((Multiname)argOb));
                        break;

                    case Opcode.ArgType.CountU30:
                    case Opcode.ArgType.UintU30:
                    case Opcode.ArgType.IntU30:
                    case Opcode.ArgType.LineNumberU30:
                    case Opcode.ArgType.RegisterU30:
                    case Opcode.ArgType.ObjectRegisterU30:
                    case Opcode.ArgType.PropertyRegisterU30:
                    case Opcode.ArgType.ShortU30:
                    case Opcode.ArgType.DoubleU30:
                        writer.WriteU30Packed((uint)argOb);
                        break;

                    case Opcode.ArgType.ByteU8:
                    case Opcode.ArgType.DebugU8:
                    case Opcode.ArgType.StackU8:
                        writer.WriteUI8((byte)argOb);
                        break;

                    case Opcode.ArgType.StringU8:
                        uint spos = (uint)this.stringMarshal.GetIDFor((string)argOb);
                        if (spos > 255)
                        {
                            /* ISSUE 10: Best fix may be to strip out debug opcodes. */
                            throw new SWFModellerException(
                                      SWFModellerError.Internal,
                                      "Marshaller failed to keep debug string at low index");
                        }

                        writer.WriteUI8(spos);
                        break;

                    case Opcode.ArgType.StringU30:
                        writer.WriteU30Packed((uint)this.stringMarshal.GetIDFor((string)argOb));
                        break;

                    case Opcode.ArgType.ClassU30:
                        writer.WriteU30Packed((uint)this.classMarshal.GetIDFor((AS3ClassDef)argOb));
                        break;

                    case Opcode.ArgType.ByteS8:
                        writer.WriteSI8((int)argOb);
                        break;

                    case Opcode.ArgType.ShortS30:
                        writer.WriteSI32((int)argOb);     /* Spec says this signed value is a U30. Stupid spec. */
                        break;

                    case Opcode.ArgType.OffsetS24:
                        if (argOb is Opcode)
                        {
                            int argOffset = (int)writer.Offset - startOffset;
                            KeyValuePair <Opcode, int> sourceInfo = new KeyValuePair <Opcode, int>(op, argOffset);
                            unresolvedOffsets.Add(new KeyValuePair <Opcode, KeyValuePair <Opcode, int> >((Opcode)argOb, sourceInfo));
                            writer.WriteSI24(0x00FFDEAD);     /* Because dead beef won't fit in 3 bytes. */
                        }
                        else
                        {
                            /* ISSUE 73 */
                            throw new SWFModellerException(
                                      SWFModellerError.UnimplementedFeature,
                                      "Unsupported op arg type in " + op.Mnemonic.ToString() + ": " + argType);
                        }

                        break;

                    case Opcode.ArgType.ExceptionU30:
                        writer.WriteU30Packed((uint)argOb);     /* Reference into the fixed list of exception handlers. TODO: Make it not so fixed. */
                        break;

                    case Opcode.ArgType.SlotU30:
                        writer.WriteU30Packed((uint)argOb);     /* Reference into the fixed list of exception handlers. TODO: Make it not so fixed. */
                        break;

                    case Opcode.ArgType.NamespaceU30:
                    case Opcode.ArgType.MethodU30:
                    case Opcode.ArgType.DebugTypeU30:
                    default:
                        /* ISSUE 73 */
                        throw new SWFModellerException(
                                  SWFModellerError.UnimplementedFeature,
                                  "Unsupported op arg type in " + op.Mnemonic.ToString() + ": " + argType);
                    }
                }

                lenMap.Add(op, (int)writer.Offset - startOffset);
            }

            using (IEnumerator <ExceptionHandler> i = method.ExceptionHandlers)
            {
                while (i.MoveNext())
                {
                    ExceptionHandler eh = i.Current;
                    eh.From   = offsetMap[eh.From];
                    eh.To     = offsetMap[eh.To];
                    eh.Target = offsetMap[eh.Target];
                }
            }

            writer.Close(); /* Also closes the buffer. */

            byte[] byteBuffer = buf.ToArray();

            foreach (KeyValuePair <Opcode, KeyValuePair <Opcode, int> > link in unresolvedOffsets)
            {
                KeyValuePair <Opcode, int> sourceInfo = link.Value;
                int srcOffset = offsetMap[sourceInfo.Key];
                int argOffset = srcOffset + sourceInfo.Value;
                int val       = offsetMap[link.Key] - srcOffset - lenMap[sourceInfo.Key];
                new ABCDataTypeWriter(new MemoryStream(byteBuffer, argOffset, 3)).WriteSI24(val);
            }

            method.Bytes = byteBuffer;
        }
Пример #4
0
        private void AssembleMethod(Method method)
        {
            MemoryStream buf = new MemoryStream();
            ABCDataTypeWriter writer = new ABCDataTypeWriter(buf);

            this.methodMarshal.Register(method);

            using (IEnumerator<ExceptionHandler> i = method.ExceptionHandlers)
            {
                while (i.MoveNext())
                {
                    ExceptionHandler eh = i.Current;
                    this.RegisterMultiname(eh.CatchType);
                    this.RegisterMultiname(eh.VarName);
                }
            }

            bool insertDebugCodes = this.InsertDebugCodes;

            if (insertDebugCodes)
            {
                /* Quick check to see if the code already has them, in which case we
                 * won't bother. */
                foreach (Opcode op in method.Opcodes)
                {
                    if (op.Mnemonic == Opcode.Mnemonics.DebugFile || op.Mnemonic == Opcode.Mnemonics.DebugLine)
                    {
                        insertDebugCodes = false;
                        break;
                    }
                }
            }

            IEnumerable<Opcode> opcodes = method.Opcodes;

            if (insertDebugCodes)
            {
                List<Opcode> debugged = new List<Opcode>();

                debugged.Add(Opcode.CreateDebugFile(method.SourceFile));

                /* Let's just check this string won't break things... */
                uint srcPos = (uint)this.stringMarshal.GetIDFor(method.SourceFile);
                if (srcPos > 255)
                {
                    /* ISSUE 10: Best fix may be to strip out debug opcodes. */
                    throw new SWFModellerException(
                            SWFModellerError.CodeMerge,
                            "Marshaller failed to keep debug string at low index");
                }

                uint lineNumber = 1; /* For our fake debug info. */
                foreach (Opcode op in opcodes)
                {
                    debugged.Add(Opcode.CreateDebugLine(lineNumber++));
                    debugged.Add(op);
                }

                opcodes = debugged;
            }

            Dictionary<Opcode, int> offsetMap = new Dictionary<Opcode, int>();
            Dictionary<Opcode, int> lenMap = new Dictionary<Opcode, int>();
            List<KeyValuePair<Opcode, KeyValuePair<Opcode, int>>> unresolvedOffsets = new List<KeyValuePair<Opcode, KeyValuePair<Opcode, int>>>();

            foreach (Opcode op in opcodes)
            {
                int startOffset = (int)writer.Offset;
                offsetMap.Add(op, startOffset);

                writer.WriteUI8(op.Instruction);

                if (op.Mnemonic == Opcode.Mnemonics.LookupSwitch)
                {
                    for (int i = 0; i < op.Args.Length; i++)
                    {
                        int argOffset = (int)writer.Offset - startOffset;
                        KeyValuePair<Opcode, int> sourceInfo = new KeyValuePair<Opcode, int>(op, argOffset);
                        object argOb = op.Args[i];
                        if (i == 1)
                        {
                            writer.WriteU30Packed((uint)(op.Args.Length - 3));
                        }
                        else
                        {
                            unresolvedOffsets.Add(new KeyValuePair<Opcode, KeyValuePair<Opcode, int>>((Opcode)argOb, sourceInfo));
                            writer.WriteSI24(0x00FFDEAD); /* Because dead beef won't fit in 3 bytes. */
                        }
                    }

                    lenMap.Add(op, 0);
                    continue;
                }

                Opcode.ArgType[] types = op.ArgTypes;
                if (types == null)
                {
                    /* done. */
                    lenMap.Add(op, (int)writer.Offset - startOffset);
                    continue;
                }

                if (types.Length != op.Args.Length)
                {
                    throw new SWFModellerException(
                            SWFModellerError.Internal,
                            "Arg mismatch in op " + op + " (" + types.Length + " expected)");
                }

                for (int i = 0; i < op.Args.Length; i++)
                {
                    object argOb = op.Args[i];
                    Opcode.ArgType argType = types[i];

                    switch (argType)
                    {
                        case Opcode.ArgType.MultinameU30:
                            writer.WriteU30Packed((uint)this.MultinameID((Multiname)argOb));
                            break;

                        case Opcode.ArgType.CountU30:
                        case Opcode.ArgType.UintU30:
                        case Opcode.ArgType.IntU30:
                        case Opcode.ArgType.LineNumberU30:
                        case Opcode.ArgType.RegisterU30:
                        case Opcode.ArgType.ObjectRegisterU30:
                        case Opcode.ArgType.PropertyRegisterU30:
                        case Opcode.ArgType.ShortU30:
                        case Opcode.ArgType.DoubleU30:
                            writer.WriteU30Packed((uint)argOb);
                            break;

                        case Opcode.ArgType.ByteU8:
                        case Opcode.ArgType.DebugU8:
                        case Opcode.ArgType.StackU8:
                            writer.WriteUI8((byte)argOb);
                            break;

                        case Opcode.ArgType.StringU8:
                            uint spos = (uint)this.stringMarshal.GetIDFor((string)argOb);
                            if (spos > 255)
                            {
                                /* ISSUE 10: Best fix may be to strip out debug opcodes. */
                                throw new SWFModellerException(
                                        SWFModellerError.Internal,
                                        "Marshaller failed to keep debug string at low index");
                            }

                            writer.WriteUI8(spos);
                            break;

                        case Opcode.ArgType.StringU30:
                            writer.WriteU30Packed((uint)this.stringMarshal.GetIDFor((string)argOb));
                            break;

                        case Opcode.ArgType.ClassU30:
                            writer.WriteU30Packed((uint)this.classMarshal.GetIDFor((AS3ClassDef)argOb));
                            break;

                        case Opcode.ArgType.ByteS8:
                            writer.WriteSI8((int)argOb);
                            break;

                        case Opcode.ArgType.ShortS30:
                            writer.WriteSI32((int)argOb); /* Spec says this signed value is a U30. Stupid spec. */
                            break;

                        case Opcode.ArgType.OffsetS24:
                            if (argOb is Opcode)
                            {
                                int argOffset = (int)writer.Offset - startOffset;
                                KeyValuePair<Opcode, int> sourceInfo = new KeyValuePair<Opcode, int>(op, argOffset);
                                unresolvedOffsets.Add(new KeyValuePair<Opcode, KeyValuePair<Opcode, int>>((Opcode)argOb, sourceInfo));
                                writer.WriteSI24(0x00FFDEAD); /* Because dead beef won't fit in 3 bytes. */
                            }
                            else
                            {
                                /* ISSUE 73 */
                                throw new SWFModellerException(
                                        SWFModellerError.UnimplementedFeature,
                                        "Unsupported op arg type in " + op.Mnemonic.ToString() + ": " + argType);
                            }

                            break;

                        case Opcode.ArgType.ExceptionU30:
                            writer.WriteU30Packed((uint)argOb); /* Reference into the fixed list of exception handlers. TODO: Make it not so fixed. */
                            break;

                        case Opcode.ArgType.SlotU30:
                            writer.WriteU30Packed((uint)argOb); /* Reference into the fixed list of exception handlers. TODO: Make it not so fixed. */
                            break;

                        case Opcode.ArgType.NamespaceU30:
                        case Opcode.ArgType.MethodU30:
                        case Opcode.ArgType.DebugTypeU30:
                        default:
                            /* ISSUE 73 */
                            throw new SWFModellerException(
                                    SWFModellerError.UnimplementedFeature,
                                    "Unsupported op arg type in "+op.Mnemonic.ToString()+": " + argType);
                    }
                }

                lenMap.Add(op, (int)writer.Offset - startOffset);
            }

            using (IEnumerator<ExceptionHandler> i = method.ExceptionHandlers)
            {
                while (i.MoveNext())
                {
                    ExceptionHandler eh = i.Current;
                    eh.From = offsetMap[eh.From];
                    eh.To = offsetMap[eh.To];
                    eh.Target = offsetMap[eh.Target];
                }
            }

            writer.Close(); /* Also closes the buffer. */

            byte[] byteBuffer = buf.ToArray();

            foreach (KeyValuePair<Opcode, KeyValuePair<Opcode, int>> link in unresolvedOffsets)
            {
                KeyValuePair<Opcode, int> sourceInfo = link.Value;
                int srcOffset = offsetMap[sourceInfo.Key];
                int argOffset = srcOffset + sourceInfo.Value;
                int val = offsetMap[link.Key] - srcOffset - lenMap[sourceInfo.Key];
                new ABCDataTypeWriter(new MemoryStream(byteBuffer, argOffset, 3)).WriteSI24(val);
            }

            method.Bytes = byteBuffer;
        }