/// <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;
}