EbmlNodeMaster ParseTree(EbmlSig element) { string err = null; var contentLenBuf = ReadMTF(Data.fbs, out long contentLen); if (contentLen < 0) { return(null); } Data.ValidSize += contentLenBuf.Length; var newMaster = new EbmlNodeMaster(element, contentLenBuf.Length + contentLen); var buf = new byte[3]; long stop = Data.ValidSize + contentLen; while (Data.ValidSize < stop) { Data.fbs.Position = Data.ValidSize; var got = Data.fbs.Read(buf, 0, 3); if (got < 3) { err = "File corrupt or truncated"; goto FATAL; } EbmlNode newNode; foreach (var item in masterSigs) { if (item.SigIsStartOf(buf)) { Data.fbs.Position = Data.ValidSize = Data.ValidSize + item.Signature.Count; newNode = ParseTree(item); if (IssueModel.Data.HasFatal) { if (newNode != null) { newMaster.AddNode(newNode); } return(newMaster); } goto NEXT; } } foreach (var item in leafSigs) { if (item.SigIsStartOf(buf)) { Data.fbs.Position = Data.ValidSize = Data.ValidSize + item.Signature.Count; byte[] payload = null; byte[] payloadHdr = ReadMTF(Data.fbs, out long payloadLen); if (payloadHdr == null) { err = "File truncated or corrupt"; goto FATAL; } if ((item.Flag & ParseFlag.Persist) != 0) { payload = new byte[payloadLen]; got = Data.fbs.Read(payload, 0, (int)payloadLen); } if (buf[0] != CrcSig.Sig32) { newNode = new EbmlNodeLeaf(item, payload); } else { ++Data.CrcCount; long hashStart = Data.ValidSize + payloadHdr.Length + payloadLen; long hashCount; if (newMaster.Nodes.Count == 0) { hashCount = contentLen - 5 - payloadHdr.Length; } else { IssueModel.Add("Misplaced CRC"); hashCount = 0; } newNode = new EbmlNodeCRC(item, payload, hashStart, hashCount); } Data.ValidSize += payloadHdr.Length + payloadLen; goto NEXT; } } err = $"Unknown element [{buf[0]:X2}][{buf[1]:X2}][{buf[2]:X2}]"; goto FATAL; NEXT: newMaster.AddNode(newNode); } if (Data.ValidSize == stop) { return(newMaster); } err = "Positional error"; FATAL: err += String.Format(" at {0:X}.", Data.ValidSize); IssueModel.Add(err, Severity.Fatal); return(newMaster); }
public Model(Stream stream, string path) { base._data = Data = new MkvFormat(this, stream, path); var bb = new byte[5]; Data.fbs.Position = Data.ValidSize = 4; Data.root = ParseTree(rootSig); Data.layout.Add(Data.root); if (Data.Issues.HasError) { return; } System.Diagnostics.Debug.Assert(Data.ValidSize == Data.fbs.Position); Data.fbs.Position = Data.ValidSize; long SegmentLength = ReadMTF(0x18, 0x53, 0x80, 0x67); if (SegmentLength < 0) { IssueModel.Add("Missing root element.", Severity.Fatal); return; } System.Diagnostics.Debug.Assert(Data.ValidSize == Data.fbs.Position); long segmentStart = Data.ValidSize; var diff = Data.ValidSize + SegmentLength - Data.FileSize; if (diff > 0) { IssueModel.Add($"File appears truncated by {diff} bytes.", Severity.Error); } Data.segment = new EbmlNodeMaster(segmentSig, SegmentLength); Data.layout.Add(Data.segment); Data.fbs.Position = Data.ValidSize; while (Data.ValidSize < segmentStart + SegmentLength) { Data.fbs.Position = Data.ValidSize; int got = Data.fbs.Read(bb, 0, 4); if (got < 3) { break; } if (bb[0] == voidSig.Sig32) { Data.fbs.Position = Data.ValidSize + 1; var voidLenBuf = ReadMTF(Data.fbs, out long voidLen); if (voidLen < 0) { IssueModel.Add("File truncated near void.", Severity.Fatal); return; } Data.ValidSize += 1 + voidLenBuf.Length + voidLen; var voidNode = new EbmlNodeLeaf(voidSig, voidLen); Data.segment.AddNode(voidNode); continue; } if (got < 4) { break; } foreach (var mstr in topSigs) { if (mstr.SigIsStartOf(bb)) { Data.fbs.Position = Data.ValidSize = Data.ValidSize + 4; if ((mstr.Flag & ParseFlag.PrunePayload) != 0) { var payloadLenBuf = ReadMTF(Data.fbs, out long payloadLen); if (payloadLen < 0) { IssueModel.Add("File corrupt or truncated.", Severity.Fatal); return; } Data.ValidSize += payloadLenBuf.Length + payloadLen; Data.segment.AddMaster(mstr, payloadLenBuf.Length + payloadLen); } else { var newNode = ParseTree(mstr); if (IssueModel.Data.HasFatal) { if (newNode != null) { Data.segment.AddNode(newNode); } return; } Data.segment.AddNode(newNode); } goto NEXT_SEG; } } string msg = $"Parse fail at 0x{Data.ValidSize:X} on [{bb[0]:X2}][{bb[1]:X2}][{bb[2]:X2}][{bb[3]:X2}]."; IssueModel.Add(msg, Severity.Fatal); return; NEXT_SEG :; } Data.fbs.Position = Data.ValidSize; var got2 = Data.fbs.Read(bb, 0, 4); if (got2 == 4 && attachSig.SigIsStartOf(bb)) { // By spec, everything should be within a single Segment. Data.HasMisplacedAttachment = true; IssueModel.Add($"Misplaced attachment at {Data.ValidSize:X}", Severity.Warning); } Data.fbs.Position = Data.ValidSize; CalcMark(true); return; }