private void ProcessClass(AS3ClassDef clazz) { using (IEnumerator <Trait> i = clazz.ClassTraits) { while (i.MoveNext()) { this.ProcessTrait(i.Current); } } using (IEnumerator <Trait> i = clazz.InstanceTraits) { while (i.MoveNext()) { this.ProcessTrait(i.Current); } } if (clazz.Iinit != null) { this.AssembleMethod(clazz.Iinit); } if (clazz.Cinit != null) { this.AssembleMethod(clazz.Cinit); } }
/// <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); }
/// <summary> /// Maps the classname to a clip. /// </summary> /// <param name="className">Name of the class.</param> /// <param name="tl">The timeline to bind the class to.</param> internal void MapClassnameToClip(string className, Timeline tl) { AS3ClassDef clazz = this.ClassByName(className); tl.Class = clazz; this.clipClassMap[clazz] = tl; }
/// <summary> /// Generates a main timeline script for a new SWF /// </summary> /// <param name="qClassName">Qualified class name for the MainTimeline class, /// e.g. mygeneratedswf_fla.MainTimeline</param> /// <returns>A DoABC tag that can be inserted into a new SWF, which may be the one /// from the timeline (And so may already be in the SWF).</returns> public static DoABC GenerateDefaultScript(string qClassName, Timeline timeline) { DoABC abc = timeline.Root.FirstScript; if (abc == null) { abc = new DoABC(true, string.Empty, null, null); abc.code = new AbcCode(); } AS3ClassDef classDef = GenerateTimelineClass(abc.code, qClassName, timeline.Root.Context); timeline.Class = classDef; Script s = new Script() { Method = GenerateTimelineScript(abc.code, classDef) }; abc.code.AddScript(s); s.AddTrait(new ClassTrait() { As3class = classDef, Kind = TraitKind.Class, Name = timeline.Class.Name }); return(abc); }
internal AS3ClassDef CreateClass() { AS3ClassDef c = new AS3ClassDef(this); this.classes.Add(c); return(c); }
/// <summary> /// Finds the movieclip that has been bound to a class. /// </summary> /// <param name="clazz">The class to look up</param> /// <returns>The clip, or null if the classname is not bound to a clip.</returns> public Timeline ClipFromClass(AS3ClassDef clazz) { if (this.clipClassMap.ContainsKey(clazz)) { return(this.clipClassMap[clazz]); } return(null); }
/// <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))); }
/// <summary> /// Find a class by name. /// </summary> /// <param name="name">The class name.</param> /// <returns>A class, or null if none match</returns> public AS3ClassDef ClassByName(string name) { if (name == null) { return(null); } foreach (DoABC script in this.scripts) { AS3ClassDef c = script.Code.GetClassByQName(name); if (c != null) { /* ISSUE 25: The chance for different classes with the same name to appear in * different DoABC tags is enough to convince us that we should only really * have one tag, not this silly list of "scripts" */ return(c); } } return(null); }
/// <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); } }
/// <summary> /// Adds a class to the code. /// </summary> /// <param name="c">The class to add.</param> public void AddClass(AS3ClassDef c) { this.classes.Add(c); }
/// <summary> /// Finds the movieclip that has been bound to a class. /// </summary> /// <param name="clazz">The class to look up</param> /// <returns>The clip, or null if the classname is not bound to a clip.</returns> public Timeline ClipFromClass(AS3ClassDef clazz) { if (this.clipClassMap.ContainsKey(clazz)) { return this.clipClassMap[clazz]; } return null; }
/// <summary> /// Read in the class definitions. /// </summary> private void ReadClasses() { uint classCount = this.abcdtr.ReadU30(); for (int i = 0; i < classCount; i++) { AS3ClassDef c = this.code.CreateClass(); uint nameIdx = this.abcdtr.ReadU30(); c.Name = this.code.GetMultiname((int)nameIdx); uint superIdx = this.abcdtr.ReadU30(); c.Supername = this.code.GetMultiname((int)superIdx); c.Flags = this.abcdtr.ReadUI8(); #if DEBUG if (this.ReadLog != null) { this.ReadLog.AppendLine("Class #" + (i + 1) + " name '" + c.Name + "', super '" + c.Supername + "', flags: " + c.Flags); } #endif if (c.IsProtectedNS) { c.ProtectedNS = this.code.GetNamespace((int)this.abcdtr.ReadU30()); #if DEBUG if (this.ReadLog != null) { this.ReadLog.AppendLine(" protected ns " + c.ProtectedNS); } #endif } uint interfaceCount = this.abcdtr.ReadU30(); while (interfaceCount-- > 0) { Multiname iName = this.code.GetMultiname((int)this.abcdtr.ReadU30()); c.AddInterface(iName); #if DEBUG if (this.ReadLog != null) { this.ReadLog.AppendLine(" implements " + iName); } #endif } c.Iinit = this.code.GetMethod((int)this.abcdtr.ReadU30()); #if DEBUG if (this.ReadLog != null) { this.ReadLog.AppendLine(" iinit " + c.Iinit); } #endif uint traitCount = this.abcdtr.ReadU30(); #if DEBUG if (this.ReadLog != null) { this.ReadLog.AppendLine(" instance traits: " + traitCount); } #endif while (traitCount-- > 0) { c.AddInstanceTrait(this.ReadTrait()); } } for (int i = 0; i < classCount; i++) { AS3ClassDef c = this.code.GetClass(i); c.Cinit = this.code.GetMethod((int)this.abcdtr.ReadU30()); uint traitCount = this.abcdtr.ReadU30(); #if DEBUG if (this.ReadLog != null) { this.ReadLog.AppendLine(" class " + c + " has " + traitCount + " static traits"); } #endif while (traitCount-- > 0) { c.AddClassTrait(this.ReadTrait()); } } }
private void ProcessClass(AS3ClassDef clazz) { using (IEnumerator<Trait> i = clazz.ClassTraits) { while (i.MoveNext()) { this.ProcessTrait(i.Current); } } using (IEnumerator<Trait> i = clazz.InstanceTraits) { while (i.MoveNext()) { this.ProcessTrait(i.Current); } } if (clazz.Iinit != null) { this.AssembleMethod(clazz.Iinit); } if (clazz.Cinit != null) { this.AssembleMethod(clazz.Cinit); } }
internal AS3ClassDef CreateClass() { AS3ClassDef c = new AS3ClassDef(this); this.classes.Add(c); return c; }
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()); }
/// <summary> /// Renames the main timeline class. /// </summary> /// <param name="classQName">New name of the class.</param> internal void RenameMainTimelineClass(string classQName) { if (this.Class == null) { throw new SWFModellerException(SWFModellerError.Internal, "Can't rename non-existant timeline class."); } AS3ClassDef classDef = this.Class as AS3ClassDef; if (classDef == null) { throw new SWFModellerException(SWFModellerError.Internal, "MainTimeline class is an in-built class, which is impossible."); } int splitPos = classQName.LastIndexOf('.'); string className = classQName; string newPackageName = string.Empty; if (splitPos != -1) { newPackageName = classQName.Substring(0, splitPos); className = classQName.Substring(splitPos + 1); } /* Class name will be a QName, so won't have a NS set */ Multiname oldName = classDef.Name; Namespace oldNameNS = oldName.NS; Multiname newName = this.scripts[0].Code.CreateMultiname( oldName.Kind, className, this.scripts[0].Code.CreateNamespace(oldNameNS.Kind, newPackageName), null); Namespace oldProtectedNS = classDef.ProtectedNS; Namespace newProtectedNS = null; if (oldProtectedNS != null) { newProtectedNS = this.scripts[0].Code.CreateNamespace(oldProtectedNS.Kind, newPackageName + ":" + className); } this.ClassProc(delegate(AS3ClassDef c) { bool inRenamedClass = false; if (c.Name == oldName) { inRenamedClass = true; c.Name = newName; } if (c.Supername == oldName) { c.Supername = newName; } if (c.ProtectedNS == oldProtectedNS) { c.ProtectedNS = newProtectedNS; } c.TraitProc(delegate(ref Trait t, AbcCode abc) { Namespace traitNS = t.Name.NS; if (traitNS == null) { return; } if (!t.Name.IsEmptySet) { /* ISSUE 32: Delete this once confidence is felt. */ throw new SWFModellerException( SWFModellerError.UnimplementedFeature, "Trait name has a set. I didn't think that was possible! Following code needs fixed!!!"); } switch (traitNS.Kind) { case Namespace.NamespaceKind.PackageInternal: case Namespace.NamespaceKind.Package: if (inRenamedClass && traitNS.Name == oldNameNS.Name) { t.Name = this.scripts[0].Code.CreateMultiname( t.Name.Kind, t.Name.Name, this.scripts[0].Code.CreateNamespace(traitNS.Kind, newPackageName), null); } break; default: /* ISSUE 73 */ throw new SWFModellerException( SWFModellerError.UnimplementedFeature, "As yet unsupported namespace (" + traitNS.Kind + ") when remapping a class trait (" + c.Name.Name + "::" + t.Name + ")"); } }); }); this.MethodProc(delegate(Method m, AS3ClassDef c) { bool inRenamedClass = c.Name == newName; m.OpcodeFilter(delegate(ref Opcode op, AbcCode abc) { if (op.Args == null) { return; } for (int i = 0; i < op.Args.Length; i++) { object arg = op.Args[i]; if (arg is Multiname) { Multiname mn = (Multiname)arg; if (mn == oldName) { op.Args[i] = newName; } else if (inRenamedClass) { bool isMnModified = false; Namespace multinameNS = mn.NS; NamespaceSet multinameSet = mn.Set; if (multinameNS != null) { switch (multinameNS.Kind) { case Namespace.NamespaceKind.Package: case Namespace.NamespaceKind.PackageInternal: if (inRenamedClass && multinameNS.Name == oldNameNS.Name) { multinameNS = this.scripts[0].Code.CreateNamespace( multinameNS.Kind, newPackageName); isMnModified = true; } break; default: /* ISSUE 73 */ throw new SWFModellerException( SWFModellerError.UnimplementedFeature, "As yet unsupported multiname's NS kind (" + multinameNS.Kind.ToString() + ") in op's Multiname arg during MethodProc"); } } if (multinameSet != null) { List <Namespace> newSet = new List <Namespace>(multinameSet.Count); bool isSetModified = false; foreach (Namespace ns in multinameSet) { switch (ns.Kind) { case Namespace.NamespaceKind.Protected: case Namespace.NamespaceKind.StaticProtected: if (ns.Name == oldProtectedNS.Name) { newSet.Add(this.scripts[0].Code.CreateNamespace( ns.Kind, newProtectedNS.Name)); isSetModified = true; continue; } break; case Namespace.NamespaceKind.Package: case Namespace.NamespaceKind.PackageInternal: case Namespace.NamespaceKind.Private: if (inRenamedClass && ns.Name == oldNameNS.Name) { newSet.Add(this.scripts[0].Code.CreateNamespace( ns.Kind, newPackageName)); isSetModified = true; continue; } break; case Namespace.NamespaceKind.Ns: if (ns.Name == oldNameNS.Name) { newSet.Add(this.scripts[0].Code.CreateNamespace( ns.Kind, newPackageName)); isSetModified = true; continue; } break; default: /* ISSUE 73 */ throw new SWFModellerException( SWFModellerError.UnimplementedFeature, "As yet unsupported multiname NS set entry kind (" + ns.Kind.ToString() + ") in op's Multiname arg during MethodProc"); } newSet.Add(ns); } if (isSetModified) { isMnModified = true; multinameSet = new NamespaceSet(newSet.ToArray()); } } if (isMnModified) { op.Args[i] = this.scripts[0].Code.CreateMultiname( mn.Kind, mn.Name, multinameNS, multinameSet); } } } else if (arg is Namespace) { /* ISSUE 73 */ throw new SWFModellerException( SWFModellerError.UnimplementedFeature, "As yet unsupported op arg in MethodProc: Namespace"); } else if (arg is AS3Class) { /* ISSUE 73 */ throw new SWFModellerException( SWFModellerError.UnimplementedFeature, "As yet unsupported op arg in MethodProc: AS3Class"); } } }); }); }
/// <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)); }
/// <summary> /// Replaces the classes with a new set of classes /// </summary> /// <param name="as3Classes">An array of classes to set in the code.</param> internal void SetClasses(AS3ClassDef[] as3Classes) { this.classes = new List<AS3ClassDef>(); this.classes.AddRange(as3Classes); }