/// <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> /// Processes a text replacement tag /// </summary> /// <param name="nav">The text replacement node.</param> /// <param name="swf">The SWF being processed.</param> private void TextReplace(XPathNavigator nav, SWF swf) { XPathNavigator findNode = Xml.SelectNode(nav, @"swf:find/text()"); if (findNode == null) { throw new SwiffotronException(SwiffotronError.BadInputXML, this.Context, "The find element in textreplace operations cannot be empty."); } string find = findNode.Value; XPathNavigator replaceNode = Xml.SelectNode(nav, @"swf:replace/text()"); string replace = replaceNode == null ? string.Empty : replaceNode.Value; foreach (XPathNavigator loc in Xml.SelectChildren(nav, @"location")) { string type = loc.GetAttribute(XMLHelper.AttrType, string.Empty); switch (type) { case XMLHelper.ValActionscript: swf.TextReplaceInCode(find, replace); break; case XMLHelper.ValMovieClip: string path = loc.GetAttribute(XMLHelper.AttrPath, string.Empty); Timeline[] clips = new Timeline[] { swf }; if (path != "*") { clips = swfProc.SpritesFromQname(path, swf, true); } foreach (Timeline clip in clips) { clip.CharacterProc(delegate(ICharacter ch) { if (ch is IText) { IText t = (IText)ch; string text = t.Text; if (text.Contains(find)) { /* The Contains test may seem redundant here, but the cost of the * assignment, even if there was nothing replaced is potentially * quite high. */ t.Text = text.Replace(find, replace); } } }); } break; default: throw new SwiffotronException(SwiffotronError.BadInputXML, this.Context, "Bad text replace location type: " + type); } } }
/// <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; }
/// <summary> /// Initializes a new instance of a sprite by cloning another timeline. /// </summary> /// <param name="srcTimeline">The timeline to clone.</param> /// <param name="className">If the cloned timeline is a SWF, then /// you should pass in a class name here. The MainTimeline class /// will be renamed in here to this new name.</param> public Sprite(Timeline srcTimeline, SWF root, string className = null) { this._root = root; /* Layers are just objects that exist purely to be arranged in some * kind of order and be pointed at by more meaningful, other things. * To clone layers, we need to simply copy the list and map old * layer refs to our new ones. */ Dictionary<Layer, Layer> newLayers = new Dictionary<Layer, Layer>(srcTimeline.LayerCount); foreach (Layer l in srcTimeline.Layers) { Layer newLayer = new Layer(this); LayerList.Add(newLayer); newLayers.Add(l, newLayer); } FrameList = new List<Frame>((int)srcTimeline.FrameCount); foreach (Frame f in srcTimeline.Frames) { Frame newFrame = new Frame(); foreach (IDisplayListItem dli in f.DisplayList) { newFrame.AddTag(dli.Clone(newLayers[dli.Layer], false)); } FrameList.Add(newFrame); } if (srcTimeline is SWF) { SWF srcSWF = (SWF)srcTimeline; if (className != null) { if (srcSWF.Class != null) { srcSWF.RenameMainTimelineClass(className); } /* Else the class will be generated later */ } RemapFonts(srcSWF, root); if (className != null) { foreach (DoABC abc in srcSWF.Scripts) { root.MergeScript(abc); } } if (className == null) { /* It's tempting to use ClassByName("flash.display.MovieClip") but * remember that that class exists in the player, not the SWF. What * we need in this case is just the name of the class, not a reference * to the class itself. Because that's complicated, we assign a * dummy class and watch for it when we write the class out. */ this.Class = AdobeClass.CreateFlashDisplayMovieClip(root.FirstScript.Code); } else { this.Class = srcSWF.Class; } } }
private string RegisterTimeline(Timeline t) { int num = TimelineIDs.Count; TimelineIDs.Add(t, num); string name = "s" + num; this.NameTimelineMap.Add(name, t); return name; }
private void BuildDictionary(Timeline timeline, StringBuilder buff) { if (this.OutputComments) { buff.AppendLine(" /* timeline for "+timeline.ToString()+" */"); } foreach (Frame f in Swf.Frames) { foreach (IDisplayListItem dli in f.DisplayList) { if (!Dict.ContainsKey(dli) && dli.Type == DisplayListItemType.PlaceObjectX) { string name = "mc" + Dict.Count + 1; Dict.Add(dli, name); PlaceObject po = dli as PlaceObject; ICharacter ch = po.Character; if (ch is Shape) { buff.AppendLine(" dict['" + name + "'] = \"" + ShapeToJS(ch as Shape) + "\";"); } else if (ch is Sprite) { string clipName = RegisterTimeline((Timeline)ch); buff.AppendLine(" var " + clipName + " = swiffoid.createMovieClipClass([o,o,o,o,o]);"); buff.AppendLine(" swiffoid.addClip('" + clipName + "', " + clipName + ");"); buff.AppendLine(" var instance = swiffoid.instantiateClip('" + clipName + "');"); html.JQueryAppendNew(buff, " ", "$root", "canvas", new string[][] { new string[] {"width", this.Width + "px"}, new string[] {"height", this.Height + "px"}, }); BuildDictionary((Sprite)ch, buff); } } } } }
private void ReadSprite() { int characterID = this.sdtr.ReadUI16(); uint frameCount = this.sdtr.ReadUI16(); #if DEBUG this.Log("char id=" + characterID + ", frames=" + frameCount); #endif Sprite sprite = this.swf.NewSprite(CID_PREFIX + characterID, frameCount, (this.frameCursor == 1)); this.currentTimeline = sprite; this.characterUnmarshaller.Add(characterID, sprite); int currentFrame = 1; for (; ; ) { int type; uint followingOffset; this.sdtr.ReadRECORDHEADER(out type, out followingOffset); #if DEBUG Tag _tag = (Tag)type; bool isDefine = _tag == Tag.DefineShape || _tag == Tag.DefineShape3 || _tag == Tag.DefineShape4 || _tag == Tag.DefineSprite; this.MarkDumpOffset( "Body of " + _tag + " (" + type + ") len=" + (followingOffset - this.sdtr.Offset), isDefine); this.binaryDumpNest++; #endif switch ((Tag)type) { case Tag.ShowFrame: #if DEBUG this.MarkDumpOffset(""); #endif currentFrame++; break; case Tag.End: if ((currentFrame - 1) != frameCount) { throw new SWFModellerException( SWFModellerError.SWFParsing, @"Frame count mismatch in sprite " + characterID, swf.Context); } this.currentTimeline = this.swf; #if DEBUG this.binaryDumpNest--; #endif return; case Tag.PlaceObject2: sprite.GetFrame(currentFrame).AddTag(this.ReadPlaceObject2()); break; case Tag.PlaceObject: sprite.GetFrame(currentFrame).AddTag(this.ReadPlaceObject(followingOffset)); break; case Tag.FrameLabel: sprite.GetFrame(currentFrame).Label = this.sdtr.ReadString(); #if DEBUG this.Log("Frame label = " + sprite.GetFrame(currentFrame).Label); #endif break; case Tag.RemoveObject2: sprite.GetFrame(currentFrame).AddTag(this.ReadRemoveObject2()); break; case Tag.RemoveObject: case Tag.StartSound: case Tag.SoundStreamHead: case Tag.SoundStreamHead2: case Tag.SoundStreamBlock: case Tag.DoAction: /* ISSUE 73 */ throw new SWFModellerException( SWFModellerError.UnimplementedFeature, @"Unsupported tag within a sprite definition: " + ((Tag)type).ToString(), swf.Context); default: throw new SWFModellerException( SWFModellerError.SWFParsing, @"Bad SWF; A " + ((Tag)type).ToString() + @" tag is not permitted within a sprite definition", swf.Context); } #if DEBUG this.binaryDumpNest--; #endif } }
/// <summary> /// Reads a SWF from the stream. /// </summary> /// <returns>A parsed SWF object</returns> public SWF ReadSWF(SWFContext ctx) { #if DEBUG this.MarkDumpOffset("Start of file"); #endif this.jpegTable = null; this.sceneNotes = new List<FrameNote>(); this.frameLabelNotes = new List<FrameNote>(); this.ReadHeader(ctx); this.fontDict = new Dictionary<int, SWFFont>(); this.frameCursor = 1; bool as3 = false; if (this.version >= 8) { #if DEBUG this.MarkDumpOffset("Start of file attributes tag"); #endif this.ReadFileAttributesTag(out as3); } if (!as3) { throw new SWFModellerException( SWFModellerError.SWFParsing, @"AS2 and under is not supported.", ctx); } this.swf = new SWF(ctx, false); this.swf.FrameWidth = this.frameSize.Width; this.swf.FrameHeight = this.frameSize.Height; this.swf.Fps = this.fps; this.swf.FrameCount = this.frameCount; this.currentTimeline = this.swf; bool hasMore = true; do { hasMore = this.ReadTag(); } while (hasMore); foreach (FrameNote note in this.sceneNotes) { this.swf.GetFrame((int)note.frame).SceneName = note.note; } foreach (FrameNote note in this.frameLabelNotes) { this.swf.GetFrame((int)note.frame).Label = note.note; } foreach (string className in this.LateClassResolutions.Keys) { swf.MapClassnameToClip(className, this.LateClassResolutions[className]); } return this.swf; }