/// <summary> /// Writes the contents of this SwfFile instance to a stream. /// Compression is used if configured. /// </summary> /// <param name="output">The destination stream to write to</param> public void Write(Stream output) { if (SwfFile.Configuration.WriteCompressed) { CwsFile cws = new CwsFile(); cws.CompressionLevel = SwfFile.Configuration.WriteCompressionLevel; cws.WriteContent = new MemoryStream(); WriteContent(cws.WriteContent); cws.Version = this.Version; // copy frame information from old FWS record cws.FrameHeader = FwsSource.FrameHeader; cws.Write(output); } else { FwsFile fws = new FwsFile(); fws.WriteContent = new MemoryStream(); WriteContent(fws.WriteContent); fws.Version = this.Version; // copy frame information from old FWS record fws.FrameHeader = FwsSource.FrameHeader; fws.Write(output); } }
/// <summary> /// Parses a Swf file tag by tag /// </summary> /// <param name="input">The Swf file as stream</param> /// <returns>The next tag</returns> public Stream Read(Stream input) { CwsSource = new CwsFile(); FwsSource = new FwsFile(); List<Tag> tags = new List<Tag>(); Stream next = CwsSource.Read(input); if (this.CwsSource.Compressed) { // Fire compressed event if (null != SwfFileCompressed) SwfFileCompressed(this, new CompressedEventArgs(true)); } next = FwsSource.Read(next); HeaderDeclaredLength = FwsSource.Length; #region Reading tags Tag t; int tagNumber = 1; uint tagsLenghts = (uint)next.Position; do { t = new Tag(); try { next = t.Read(next); Log.Debug(this, "Reading Tag #" + tagNumber + "(" + t.TagTypeName +")" + " Offset : 0x" + t.Offset.ToString("X08") + " Total-Length : 0x" + t.LengthTotal.ToString("X08")); // Fire TagReadCompleted, ReadProgressChanged, if protected SwfFileProtected events if (null != TagReadCompleted) TagReadCompleted(this, new TagHandlerReadCompleteEventArgs(t.TagType)); if (null != this.ReadProgressChanged) ReadProgressChanged(this, new SwfReadProgressChangedEventArgs(next.Length, next.Position)); if (null != SwfFileProtected && t.TagType == TagTypes.Protect) SwfFileProtected(this, new ProtectionEventArgs("")); // Knowing if the offset end is longer than header declared length is enough to verfiy if (t.OffsetEnd > this.FwsSource.Length) { if ((SwfFile.Configuration.HandleHeadSizeIssue == HandleHeadSizeIssueBy.Fix) && t.OffsetEnd <= (ulong)input.Length) { this.FwsSource.Length = (uint)t.OffsetEnd; Log.Warn(this, "Tag #" + tagNumber + " ends outside (0x" + t.OffsetEnd.ToString("X08") + ") the declared Swf content range 0x" + this.FwsSource.Length.ToString("X08") + " Fixing."); } if ((SwfFile.Configuration.HandleHeadSizeIssue == HandleHeadSizeIssueBy.Ignore) && t.OffsetEnd <= (ulong)input.Length) { Log.Warn(this, "Tag #" + tagNumber + " ends outside (0x" + t.OffsetEnd.ToString("X08") + ") the declared Swf content range 0x" + this.FwsSource.Length.ToString("X08") + " Ignoring."); } else { SwfFormatException e = new SwfFormatException("Tag #" + tagNumber + " ends outside (0x" + t.OffsetEnd.ToString("X08") + ") the declared Swf content range 0x" + this.FwsSource.Length.ToString("X08")); Log.Error(this, e); throw e; } } tagsLenghts += t.LengthTotal; tagNumber++; tags.Add(t); } catch (IOException ioe) { //This is the point where we find no end tag which basically means that a tag declared more memory than the stream actaully has Log.Error(this, ioe); SwfFormatException e = new SwfFormatException("Tag list is incomplete, does not end with an END tag or a tag length exceeds the file size."); Log.Error(this, e); throw e; } } while (t.TagType != TagTypes.End); #endregion #region Length checking // Performing length checks now // // 1. Do the length of all tags match the stream length if (tagsLenghts != next.Length) { SwfFormatException e = new SwfFormatException("The length of tags (" + tagsLenghts.ToString() + ") does not match the stream size(" + next.Length.ToString() + ")."); Log.Error(this, e); throw e; } // 2. Does the tags lengths do match the header declared length if (tagsLenghts != this.CwsSource.Length) { if (SwfFile.Configuration.HandleHeadSizeIssue == HandleHeadSizeIssueBy.Fix) { this.CwsSource.Length = tagsLenghts; Log.Warn(this, "The length of tags (" + tagsLenghts.ToString() + ") does not match the header declared length(" + this.CwsSource.Length.ToString() + "). Stream size will be fixed."); } else if (SwfFile.Configuration.HandleHeadSizeIssue == HandleHeadSizeIssueBy.RaiseError) { SwfFormatException e = new SwfFormatException("The length of tags (" + tagsLenghts.ToString() + ") does not match the header declared length(" + this.CwsSource.Length.ToString() + ")."); Log.Error(this, e); throw e; } else { Log.Warn(this, "The length of tags (" + tagsLenghts.ToString() + ") does not match the header declared length(" + this.CwsSource.Length.ToString() + "). Stream size will be fixed."); } } // 3. If stream and header length match has already been checked in FWSFile class // 4. Has the stream been consumed completely if (next.Position != next.Length) { if (SwfFile.Configuration.HandleStreamOversize == HandleStreamOversizeBy.Resize) { this.FixIncorrectStreamSize(next, next.Position); Log.Warn(this, "Trailing garbage after END tag detected. Position 0x" + input.Position.ToString("X08") + ", Length " + input.Length.ToString() + ". Dumping Trailing Garbage."); } else if (SwfFile.Configuration.HandleStreamOversize == HandleStreamOversizeBy.Ignore) { Log.Warn(this, "Trailing garbage after END tag detected. Position 0x" + input.Position.ToString("X08") + ", Length " + input.Length.ToString()); } else { SwfFormatException e = new SwfFormatException("Trailing garbage after END tag detected. Position 0x" + input.Position.ToString("X08") + ", Length " + input.Length.ToString()); Log.Error(this, e); } } #endregion #region Producing tag handlers TagHandlers = new List<Recurity.Swf.TagHandler.AbstractTagHandler>(); for (int i = 0; i < tags.Count; i++) { // // Only accept tag types that are documented by Adobe // if (!tags[i].IsTagTypeKnown) { string msg = "Tag type " + ((UInt16)tags[i].TagType).ToString("d") + " not known/documented"; if (SwfFile.Configuration.AllowUnknownTagTypes) { Log.Warn(this, msg); } else { SwfFormatException e = new SwfFormatException(msg); Log.Error(this, e); throw e; } } // // The factory automatically fires .Read() on the produced class. Therefore, // we catch Exceptions here (Stream too short) and convert them to SwfFormatExceptions // try { TagHandlers.Add(TagHandlerFactory.Create(tags[i], this, next)); // Fire TagProduced event if (null != TagProduced)//If a handler is attached TagProduced(this, new TagHandlerProducedEventArgs(tags[i].TagType, (Int64)tags.Count, (Int64)i)); } catch (Exception e) { SwfFormatException swfE = new SwfFormatException("Tag handler #" + i + " (" + tags[i].TagTypeName + ") failed parsing: " + e.Message); throw swfE; } if (tags[i].TagType.Equals(TagTypes.ST_GLYPHNAMES) || tags[i].TagType.Equals(TagTypes.ST_REFLEX)) { //this.CWSSource._GeneratorSoftware = "SwfTools"; } // // Verify the required Version of each Tag against the header declared // Version. // It may be considered to make failing this test fatal. // if (TagHandlers[i].MinimumVersionRequired > this.Version) { Log.Warn(this, "Tag " + (tags[i].IsTagTypeKnown ? tags[i].TagTypeName : tags[i].TagType.ToString()) + " requires Swf version " + TagHandlers[i].MinimumVersionRequired.ToString() + ", header declares " + this.Version.ToString()); } } #endregion return next; }