Exemplo n.º 1
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;
        }