private void WriteImage(IImage image) { if (characterMarshal.HasMarshalled(image)) { /* Been there, done that. */ return; } ImageBlob blob = image as ImageBlob; if (blob == null) { throw new SWFModellerException(SWFModellerError.Internal, "Can't write " + image.ToString()); } switch (blob.DataFormat) { case Tag.DefineBitsJPEG2: case Tag.DefineBitsLossless: case Tag.DefineBitsLossless2: WriteBuffer blobBuffer = OpenTag(blob.DataFormat); blobBuffer.WriteUI16((uint)characterMarshal.GetIDFor(image)); blobBuffer.WriteBytes(blob.FormattedBytes); CloseTag(); break; case Tag.DefineBits: if (blob.JPEGTable != null) { if (writtenJPEGTable != null && writtenJPEGTable != blob.JPEGTable) { /* ISSUE 16 */ throw new SWFModellerException(SWFModellerError.UnimplementedFeature, "Can't process multiple JPEG encoding tables yet."); } WriteBuffer tables = OpenTag(Tag.JPEGTables); tables.WriteBytes(blob.JPEGTable.TableData); CloseTag(); writtenJPEGTable = blob.JPEGTable; } WriteBuffer bits = OpenTag(Tag.DefineBits); bits.WriteUI16((uint)characterMarshal.GetIDFor(image)); bits.WriteBytes(blob.FormattedBytes); CloseTag(); break; default: throw new SWFModellerException(SWFModellerError.Internal, "Can't write image format " + blob.DataFormat.ToString());; } }
/// <summary> /// Takes a SWF object and turns it into a .swf binary file. It might seem nicer to /// write it to a stream, but the stream has a file length at the start which we only /// know once we've written it all out to a byte array anyway. Returning it as a /// chunk of data is simply more honest; an output stream would promise streaminess behind /// the scenes that we cannot deliver. /// </summary> /// <returns>The .swf data is returned as a byte array.</returns> public byte[] ToByteArray() { /* We start writing things mid-way through the header, at the point * where compression comes into effect. Once we've created and perhaps * compressed the data, we can write the first part of the header and * concatenate the rest. */ writtenJPEGTable = null; /* The file contains tags, which can contain tags, each of which is prefixed with a length. * To track all this, we use a stack of writers, each with its own buffer. The first on the * stack is the buffer that will contain the file itself. */ this.writers = new Stack <WriteBuffer>(); this.swfOut = new WriteBuffer(Tag.None, "swf"); this.writers.Push(this.swfOut); this.swfOut.WriteRect(new Rect(0, this.swf.FrameWidth, 0, this.swf.FrameHeight)); this.swfOut.WriteFIXED8(this.swf.Fps); this.swfOut.WriteUI16(this.swf.FrameCount); this.WriteTags(); /* Ok, we basically have a SWF now. All we need to do is compress it and * stick a header on at the front... */ byte[] body = this.swfOut.Data; uint fileLen = (uint)(body.Length + 8); /* Add the 8 bytes of header we haven't done yet. */ if (this.options.Compressed) { MemoryStream zbytes = new MemoryStream(); DeflaterOutputStream zos = new DeflaterOutputStream(zbytes); zos.Write(body, 0, body.Length); zos.Close(); body = zbytes.ToArray(); } MemoryStream final = new MemoryStream(); SWFDataTypeWriter finalWriter = new SWFDataTypeWriter(final); finalWriter.WriteUI24(this.options.Compressed ? SIG_COMPRESSED : SIG_UNCOMPRESSED); /* ISSUE 27: Hard-coded SWF version 10. Technically this should be an option but * for now we don't want the headache of version-specific code. */ finalWriter.WriteUI8(SWF_VERSION); finalWriter.WriteUI32(fileLen); finalWriter.Write(body, 0, body.Length); return(final.ToArray()); }
private bool ReadTag() { int type; uint followingOffset; this.sdtr.ReadRECORDHEADER(out type, out followingOffset); uint startOffset = this.sdtr.Offset; #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++; this.taglog.Add(_tag.ToString()); #endif switch ((Tag)type) { case Tag.End: #if DEBUG this.binaryDumpNest--; #endif return(false); case Tag.ShowFrame: #if DEBUG this.MarkDumpOffset(""); #endif this.frameCursor++; break; case Tag.Protect: this.sdtr.Align8(); if (followingOffset > this.sdtr.Offset) { /*(void)*/ this.sdtr.ReadUI16(); /* Reserved. Assumed 0. */ this.swf.ProtectHash = this.sdtr.ReadString(); #if DEBUG this.Log("Protect hash = " + this.swf.ProtectHash); #endif } break; case Tag.SetBackgroundColor: this.swf.BackgroundColor = this.sdtr.ReadRGB(); break; case Tag.PlaceObject: this.currentTimeline.GetFrame(this.frameCursor).AddTag(this.ReadPlaceObject(followingOffset)); break; case Tag.PlaceObject2: this.currentTimeline.GetFrame(this.frameCursor).AddTag(this.ReadPlaceObject2()); break; case Tag.RemoveObject2: this.currentTimeline.GetFrame(this.frameCursor).AddTag(this.ReadRemoveObject2()); break; case Tag.DefineBits: case Tag.DefineBitsJPEG2: case Tag.DefineBitsLossless: case Tag.DefineBitsLossless2: this.ReadImageBlob((Tag)type, followingOffset); break; case Tag.JPEGTables: jpegTable = new JPEGTable(this.sdtr.ReadByteBlock((int)(followingOffset - this.sdtr.Offset))); break; case Tag.DefineSprite: this.ReadSprite(); break; case Tag.DefineShape: case Tag.DefineShape2: case Tag.DefineShape3: case Tag.DefineShape4: this.ReadDefineShapeN((Tag)type, followingOffset); break; case Tag.DefineMorphShape: case Tag.DefineMorphShape2: this.ReadDefineMorphShape((Tag)type, followingOffset); break; case Tag.DefineSceneAndFrameLabelData: this.ReadSceneAndFrameLabelData(); break; case Tag.DoABC: this.ReadDoABC(followingOffset); break; case Tag.SymbolClass: this.ReadSymbolClass(); break; case Tag.Metadata: this.ReadXMLMetadata(); break; case Tag.EnableDebugger2: this.ReadEnableDebugger2(); break; case Tag.FrameLabel: this.currentTimeline.GetFrame(this.frameCursor).Label = this.sdtr.ReadString(); #if DEBUG this.Log("Frame label = " + this.currentTimeline.GetFrame(this.frameCursor).Label); #endif break; case Tag.DefineFont3: this.ReadFont((Tag)type); break; case Tag.DefineFontAlignZones: this.ReadFontAlignZones(); break; case Tag.DefineFontName: this.ReadFontName(); break; case Tag.DefineText: case Tag.DefineText2: this.ReadText((Tag)type); break; case Tag.DefineEditText: this.ReadEditText(); break; default: /* ISSUE 73 */ throw new SWFModellerException( SWFModellerError.UnimplementedFeature, @"Unsupported tag type: " + type, swf.Context); } this.FinishTag(followingOffset); #if DEBUG this.binaryDumpNest--; #endif return(true); }
/// <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); }