/// <summary> /// /// </summary> /// <param name="tag"></param> /// <param name="sourceFile"></param> /// <param name="inputStream"></param> /// <returns></returns> public static TagHandler.AbstractTagHandler Create(Tag tag, SwfFile sourceFile, Stream inputStream) { TagHandler.AbstractTagHandler product = null; // // Make parsing non-linear by explicitly placing the inputStream at the // OffsetData of the Tag. // inputStream.Seek((long)tag.OffsetData, SeekOrigin.Begin); long before = inputStream.Position; // // Produce TagHandler // bool enabled = false; try { enabled = SwfFile.Configuration.TagHandlers(tag.TagTypeName); } catch(Exception e) { Log.Error("TagHandlerFactory", "The tag" + tag.TagTypeName + "could not be found in the Dictionary"); throw e; } if (!enabled) { product = new TagHandler.GenericTag(sourceFile.Version); Log.Info(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType, "TagHandler for Tag type " + tag.TagTypeName + " disabled in configuration, using generic"); } if (null == product) { switch (tag.TagType) { // Actions section // case TagTypes.DoAction: product = new TagHandler.DoAction(sourceFile.Version); break; case TagTypes.DoInitAction: product = new TagHandler.DoInitAction(sourceFile.Version); break; case TagTypes.FileAttributes: product = new TagHandler.FileAttributes(sourceFile.Version); break; case TagTypes.PlaceObject: product = new TagHandler.PlaceObject(sourceFile.Version); break; case TagTypes.PlaceObject2: product = new TagHandler.PlaceObject2(sourceFile.Version); break; case TagTypes.PlaceObject3: product = new TagHandler.PlaceObject3(sourceFile.Version); break; // Shapes section // case TagTypes.DefineShape: product = new TagHandler.DefineShape(sourceFile.Version); break; case TagTypes.DefineShape2: product = new TagHandler.DefineShape(sourceFile.Version); break; case TagTypes.DefineShape3: product = new TagHandler.DefineShape(sourceFile.Version); break; case TagTypes.DefineShape4: product = new TagHandler.DefineShape4(sourceFile.Version); break; // Bitmap section // case TagTypes.DefineBits: product = new TagHandler.DefineBits(sourceFile.Version); break; case TagTypes.JPEGTables: product = new TagHandler.JPEGTables(sourceFile.Version); break; case TagTypes.DefineBitsJPEG2: product = new TagHandler.DefineBitsJPEG2(sourceFile.Version); break; case TagTypes.DefineBitsJPEG3: product = new TagHandler.DefineBitsJPEG3(sourceFile.Version); break; case TagTypes.DefineBitsLossless: product = new TagHandler.DefineBitsLossless(sourceFile.Version); break; case TagTypes.DefineBitsLossless2: product = new TagHandler.DefineBitsLossless2(sourceFile.Version); break; // Shape Morphing Section // case TagTypes.DefineMorphShape: product = new TagHandler.DefineMorphShape(sourceFile.Version); break; case TagTypes.DefineMorphShape2: product = new TagHandler.DefineMorphShape2(sourceFile.Version); break; // Fonts and Text section // case TagTypes.DefineFont: product = new TagHandler.DefineFont(sourceFile.Version); break; case TagTypes.DefineFont2: product = new TagHandler.DefineFont2(sourceFile.Version); break; case TagTypes.DefineFont3: product = new TagHandler.DefineFont3(sourceFile.Version); break; case TagTypes.DefineFont4: product = new TagHandler.DefineFont4(sourceFile.Version); break; case TagTypes.DefineFontInfo: product = new TagHandler.DefineFontInfo(sourceFile.Version); break; case TagTypes.DefineFontInfo2: product = new TagHandler.DefineFontInfo(sourceFile.Version); break; case TagTypes.DefineFontAlignZones: product = new TagHandler.DefineFontAlignZones(sourceFile.Version); break; case TagTypes.DefineFontName: product = new TagHandler.DefineFontName(sourceFile.Version); break; case TagTypes.DefineText: product = new TagHandler.DefineText(sourceFile.Version); break; case TagTypes.DefineText2: product = new TagHandler.DefineText(sourceFile.Version); break; case TagTypes.DefineEditText: product = new TagHandler.DefineEditText(sourceFile.Version); break; case TagTypes.CSMTextSettings: product = new TagHandler.CsmTextSettings(sourceFile.Version); break; // Sounds Section // case TagTypes.DefineSound: product = new TagHandler.DefineSound(sourceFile.Version); break; case TagTypes.StartSound: product = new TagHandler.StartSound(sourceFile.Version); break; case TagTypes.StartSound2: product = new TagHandler.StartSound2(sourceFile.Version); break; case TagTypes.SoundStreamHead: product = new TagHandler.SoundStreamHead(sourceFile.Version); break; case TagTypes.SoundStreamHead2: product = new TagHandler.SoundStreamHead2(sourceFile.Version); break; case TagTypes.SoundStreamBlock: product = new TagHandler.SoundStreamBlock(sourceFile.Version); break; // Control Section // case TagTypes.DefineSceneAndFrameLabelData: product = new TagHandler.DefineSceneAndFrameLabelData(sourceFile.Version); break; case TagTypes.DefineScalingGrid: product = new TagHandler.DefineScalingGrid(sourceFile.Version); break; case TagTypes.SetTabIndex: product = new TagHandler.SetTabIndex(sourceFile.Version); break; case TagTypes.SetBackgroundColor: product = new TagHandler.SetBackgroundColor(sourceFile.Version); break; case TagTypes.Protect: product = new TagHandler.Protect(sourceFile.Version); break; case TagTypes.Metadata: product = new TagHandler.Metadata(sourceFile.Version); break; case TagTypes.ImportAssets: product = new TagHandler.ImportAssets(sourceFile.Version); break; case TagTypes.ImportAssets2: product = new TagHandler.ImportAssets2(sourceFile.Version); break; case TagTypes.FrameLabel: product = new TagHandler.FrameLabel(sourceFile.Version); break; case TagTypes.ExportAssets: product = new TagHandler.ExportAssets(sourceFile.Version); break; case TagTypes.EnableDebugger: product = new TagHandler.EnableDebugger(sourceFile.Version); break; case TagTypes.EnableDebugger2: product = new TagHandler.EnableDebugger2(sourceFile.Version); break; // Buttons Section // case TagTypes.DefineButton: product = new TagHandler.DefineButton(sourceFile.Version); break; case TagTypes.DefineButton2: product = new TagHandler.DefineButton2(sourceFile.Version); break; // Sprites and Movie Clips section // case TagTypes.DefineSprite: product = new TagHandler.DefineSprite(sourceFile.Version); break; // Video section // // Binary Data section // // Blitzabeleiter internals case TagTypes.ProductID: product = new TagHandler.ProductID(sourceFile.Version); break; case TagTypes.DebugID: product = new TagHandler.DebugID(sourceFile.Version); break; case TagTypes.DefineBinaryData: product = new TagHandler.DefineBinaryData(sourceFile.Version); break; // ABC / AVM2 Code case TagTypes.DoABC: product = new TagHandler.DoABC(sourceFile.Version); break; //case TagTypes.ScriptLimits: // product = new TagHandler.ScriptLimits(sourceFile.Version); // break; default: product = new TagHandler.GenericTag(sourceFile.Version); break; } } // Exceptions during this operation propagate all // the way up to SwfFile product.Read(tag, sourceFile, inputStream); // Note: we don't have to check that the stream did only consume as much // data as the Tag declared, since the Tag.ReadContent() method reads only // the declared amount of data from the Tag and produces a MemoryStream with // that. Tag.ReadContent() is used by AbstractTagHandler.Read(). return product; }
/// <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; }