Represents parsed ABC bytecode, and all that it contains.
Example #1
0
        /// <summary>
        /// Merges some code into this code.
        /// </summary>
        /// <param name="abc">The code to merge into this object. Once merged, you should
        /// discard 'abc'.</param>
        internal void Merge(DoABC abc, SWFContext ctx)
        {
            /* Because we want everything to be object references... */

            AbcCode abcCode  = abc.Code; /* This is a kludge to force initial parsing of the abc data, if not done already */
            AbcCode thisCode = this.Code;

            abc.Disassemble(); /* This ensures that the code is disassembled into mergable form */
            this.Disassemble();

            foreach (AS3ClassDef clazz in abc.Code.Classes)
            {
                AS3ClassDef classCollision = thisCode.GetClassByQName(clazz.Name.QualifiedName);
                if (classCollision != null)
                {
                    throw new SWFModellerException(
                              SWFModellerError.CodeMerge,
                              "Class name collision on " + clazz.Name,
                              ctx.Sentinel("ClassNameCollision"));
                }

                thisCode.AddClass(clazz);
            }
        }
Example #2
0
 /// <summary>
 /// Runs a delegate function over every method in the SWF.
 /// </summary>
 /// <param name="mp">The delegate to run.</param>
 private void MethodProc(AbcCode.MethodProcessor mp)
 {
     foreach (DoABC script in this.scripts)
     {
         script.MethodProc(mp);
     }
 }
Example #3
0
        /// <summary>
        /// Factory method for a new timeline class.
        /// </summary>
        /// <param name="abc">The abc code to create the class within.</param>
        /// <param name="packageName">Name of the fla. You can make this up, since you probably don't have
        /// a fla.</param>
        /// <param name="className">Name of the class.</param>
        /// <returns>A bew timeline class.</returns>
        private static AS3ClassDef GenerateTimelineClass(AbcCode abc, string qClassName, SWFContext ctx)
        {
            int splitPos = qClassName.LastIndexOf('.');
            if (splitPos < 0)
            {
                throw new SWFModellerException(SWFModellerError.CodeMerge,
                        "A generated timeline class must have a package name.",
                        ctx.Sentinel("TimelineDefaultPackage"));
            }

            string packageName = qClassName.Substring(0, splitPos);
            string className = qClassName.Substring(splitPos + 1);

            /* Class name: */
            Namespace flaNS = abc.CreateNamespace(Namespace.NamespaceKind.Package, packageName);
            Multiname classMultinameName = abc.CreateMultiname(Multiname.MultinameKind.QName, className, flaNS, null);

            /* Superclass: */
            Namespace nsFlashDisplay = abc.CreateNamespace(Namespace.NamespaceKind.Package, "flash.display");
            Multiname mnMovieClip = abc.CreateMultiname(Multiname.MultinameKind.QName, "MovieClip", nsFlashDisplay, null);

            AS3ClassDef newClass = abc.CreateClass();

            newClass.Name = classMultinameName;
            newClass.Supername = mnMovieClip;

            Namespace protectedNS = abc.CreateNamespace(Namespace.NamespaceKind.Protected, packageName + ":" + className);

            newClass.ProtectedNS = protectedNS;

            newClass.Cinit = abc.CreateMethod(className + "Constructor.abc", 1, 1, 9, 10,

                /* The above magic numbers come from the numbers generated by IDE versions of this function.
                 * I have no real ideal about how I'd work them out for myself, which would obviously be
                 * more ideal. */

                /* AFAICT, this is always generated by the IDE because the abc file format
                 * doesn't allow for classes with no static initialiser. It doesn't seem
                 * to actually do anything. */

                abc.Op(Opcode.Mnemonics.GetLocal0),
                abc.Op(Opcode.Mnemonics.PushScope),
                abc.Op(Opcode.Mnemonics.ReturnVoid));

            newClass.Iinit = abc.CreateMethod(className + "ClassInit.abc", 1, 1, 10, 11,

                /* The above magic numbers come from the numbers generated by IDE versions of this function.
                 * I have no real ideal about how I'd work them out for myself, which would obviously be
                 * more ideal. */

                abc.Op(Opcode.Mnemonics.GetLocal0),
                abc.Op(Opcode.Mnemonics.PushScope),
                abc.Op(Opcode.Mnemonics.GetLocal0),
                abc.Op(Opcode.Mnemonics.ConstructSuper, 0U),

                abc.Op(Opcode.Mnemonics.ReturnVoid));

            return newClass;
        }
Example #4
0
        /// <summary>
        /// Factory method for a new timeline script.
        /// </summary>
        /// <param name="abc">The abc object to create the script into.</param>
        /// <param name="timelineClass">A generated timeline class. See GenerateTimelineClass</param>
        /// <returns>The new method</returns>
        private static Method GenerateTimelineScript(AbcCode abc, AS3ClassDef timelineClass)
        {
            Multiname mnMovieClip = timelineClass.Supername;
            Namespace nsFlashDisplay = mnMovieClip.NS;

            Namespace nsEmptyPackage = abc.CreateNamespace(Namespace.NamespaceKind.Package, string.Empty);
            Namespace nsFlashEvents = abc.CreateNamespace(Namespace.NamespaceKind.Package, "flash.events");

            Multiname mnObject = abc.CreateMultiname(Multiname.MultinameKind.QName, "Object", nsEmptyPackage, null);
            Multiname mnEventDispatcher = abc.CreateMultiname(Multiname.MultinameKind.QName, "EventDispatcher", nsFlashEvents, null);
            Multiname mnDisplayObject = abc.CreateMultiname(Multiname.MultinameKind.QName, "DisplayObject", nsFlashDisplay, null);
            Multiname mnInteractiveObject = abc.CreateMultiname(Multiname.MultinameKind.QName, "InteractiveObject", nsFlashDisplay, null);
            Multiname mnDisplayObjectContainer = abc.CreateMultiname(Multiname.MultinameKind.QName, "DisplayObjectContainer", nsFlashDisplay, null);
            Multiname mnSprite = abc.CreateMultiname(Multiname.MultinameKind.QName, "Sprite", nsFlashDisplay, null);

            return abc.CreateMethod("Timeline.abc", 2, 1, 1, 9,

                /* The above magic numbers come from the numbers generated by IDE versions of this function.
                 * I have no real ideal about how I'd work them out for myself, which would obviously be
                 * more ideal. */
                abc.Op(Opcode.Mnemonics.GetLocal0),
                abc.Op(Opcode.Mnemonics.PushScope),
                abc.Op(Opcode.Mnemonics.GetScopeObject, (byte)0),
                abc.Op(Opcode.Mnemonics.GetLex, mnObject),
                abc.Op(Opcode.Mnemonics.PushScope),
                abc.Op(Opcode.Mnemonics.GetLex, mnEventDispatcher),
                abc.Op(Opcode.Mnemonics.PushScope),
                abc.Op(Opcode.Mnemonics.GetLex, mnDisplayObject),
                abc.Op(Opcode.Mnemonics.PushScope),
                abc.Op(Opcode.Mnemonics.GetLex, mnInteractiveObject),
                abc.Op(Opcode.Mnemonics.PushScope),
                abc.Op(Opcode.Mnemonics.GetLex, mnDisplayObjectContainer),
                abc.Op(Opcode.Mnemonics.PushScope),
                abc.Op(Opcode.Mnemonics.GetLex, mnSprite),
                abc.Op(Opcode.Mnemonics.PushScope),
                abc.Op(Opcode.Mnemonics.GetLex, mnMovieClip),
                abc.Op(Opcode.Mnemonics.PushScope),
                abc.Op(Opcode.Mnemonics.GetLex, mnMovieClip),
                abc.Op(Opcode.Mnemonics.NewClass, timelineClass),
                abc.Op(Opcode.Mnemonics.PopScope),
                abc.Op(Opcode.Mnemonics.PopScope),
                abc.Op(Opcode.Mnemonics.PopScope),
                abc.Op(Opcode.Mnemonics.PopScope),
                abc.Op(Opcode.Mnemonics.PopScope),
                abc.Op(Opcode.Mnemonics.PopScope),
                abc.Op(Opcode.Mnemonics.PopScope),
                abc.Op(Opcode.Mnemonics.InitProperty, timelineClass.Name),
                abc.Op(Opcode.Mnemonics.ReturnVoid));
        }
Example #5
0
 /// <summary>
 /// Process all the methods in this code block.
 /// </summary>
 /// <param name="mp">A delegate function that will process each method somehow.</param>
 internal void MethodProc(AbcCode.MethodProcessor mp)
 {
     this.Code.MethodProc(mp);
 }
Example #6
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);
        }
Example #7
0
        private void ReBuildTables(AbcCode code, string mainClassName)
        {
            /* These objects will keep track of the new IDs generated for all sorts of things... */

            this.intMarshal = new IDMarshaller<int>(0, 0);
            this.uintMarshal = new IDMarshaller<uint>(0, 0);
            this.stringMarshal = new IDMarshaller<string>(0, ABCValues.AnyName);
            this.doubleMarshal = new IDMarshaller<ulong>(0, 0L);
            this.nsMarshal = new IDMarshaller<Namespace>(0, Namespace.GlobalNS);
            this.nsSetMarshal = new IDMarshaller<NamespaceSet>(0, NamespaceSet.EmptySet);
            this.multinameMarshal = new IDMarshaller<Multiname>(0, Multiname.GlobalMultiname);
            this.classMarshal = new IDMarshaller<AS3ClassDef>(0);
            this.methodMarshal = new IDMarshaller<Method>(0);

            AS3ClassDef mainClass = null;
            foreach (AS3ClassDef clazz in code.Classes)
            {
                if (clazz.Name.QualifiedName == mainClassName && mainClassName != null)
                {
                    /* To make sure the main class is last.
                     *
                     * Note that we do this out of paranoia and observation, not out of
                     * any kind of understanding that it's necessary. As far as I know, it
                     * probably doesn't matter.
                     *
                     * Note that even without the check for the main class, we'd still need to take
                     * all the classes and register them in the marshal.
                     */
                    mainClass = clazz;
                }
                else
                {
                    this.classMarshal.Register(clazz);
                }
            }

            if (mainClass != null)
            {
                this.classMarshal.Register(mainClass);
            }

            code.SetClasses(this.classMarshal.ToArray());

            foreach (AS3ClassDef clazz in code.Classes)
            {
                this.ProcessClass(clazz);
            }

            foreach (Script s in code.Scripts)
            {
                this.AssembleMethod(s.Method);
                using (IEnumerator<Trait> i = s.Traits)
                {
                    while (i.MoveNext())
                    {
                        this.ProcessTrait(i.Current);
                    }
                }
            }

            code.SetMethods(this.methodMarshal.ToArray());
        }
Example #8
0
        private byte[] GenerateScriptInfo(AbcCode code)
        {
            MemoryStream buf = new MemoryStream();
            ABCDataTypeWriter writer = new ABCDataTypeWriter(buf);

            writer.WriteU30Packed((uint)code.ScriptCount);

            foreach (Script s in code.Scripts)
            {
                writer.WriteU30Packed((uint)this.methodMarshal.GetIDFor(s.Method));

                writer.WriteU30Packed((uint)s.TraitCount);
                using (IEnumerator<Trait> i = s.Traits)
                {
                    while (i.MoveNext())
                    {
                        this.WriteTraitInfo(writer, i.Current);
                    }
                }
            }

            writer.Close(); /* Closes the buffer */
            return buf.ToArray();
        }
Example #9
0
        private byte[] GenerateMetadata(AbcCode code)
        {
            MemoryStream buf = new MemoryStream();
            ABCDataTypeWriter writer = new ABCDataTypeWriter(buf);

            writer.WriteU30Packed((uint)code.MetadataCount);

            foreach (string key in code.MetadataKeys)
            {
                writer.WriteU30Packed((uint)this.stringMarshal.GetIDFor(key));
                Dictionary<string, string> itemInfo = code.GetMetadata(key);
                writer.WriteU30Packed((uint)itemInfo.Count);
                foreach (string itemKey in itemInfo.Keys)
                {
                    writer.WriteU30Packed((uint)this.stringMarshal.GetIDFor(itemKey));
                    writer.WriteU30Packed((uint)this.stringMarshal.GetIDFor(itemInfo[itemKey]));
                }
            }

            writer.Close(); /* Closes the buffer */
            return buf.ToArray();
        }