private void ReadAttachment(EbmlReader ebmlReader) { MatroskaConsts.MatroskaAttachment attachment = new MatroskaConsts.MatroskaAttachment(); ElementDescriptor desc; ebmlReader.EnterContainer(); while (ebmlReader.ReadNext()) { if (_descriptorsMap.TryGetValue(ebmlReader.ElementId.EncodedValue, out desc)) { if (desc.Name == "FileName") { attachment.FileName = ebmlReader.ReadUtf(); } else if (desc.Name == "FileMimeType") { attachment.MimeType = ebmlReader.ReadAscii(); } else if (desc.Name == "FileData") { byte[] data = new byte[ebmlReader.ElementSize]; ebmlReader.ReadBinary(data, 0, data.Length); _attachments.Add(attachment.FileName, data); attachment.FileSize = ebmlReader.ElementSize; } } } _attachmentList.Add(attachment); ebmlReader.LeaveContainer(); }
/// <summary> /// Reads the current position in the file as an unsigned integer converted from binary. /// </summary> /// <param name="reader">An instance of <see cref="EbmlReader"/>.</param> /// <returns>The unsigned integer.</returns> internal static uint ReadUIntFromBinary(this EbmlReader reader) { var buffer = new byte[4]; reader.ReadBinary(buffer, 0, 4); return(BinaryPrimitives.ReadUInt32BigEndian(buffer)); }
/// <summary> /// Enters the Tracks segment and reads all tracks to find the specified type. /// </summary> /// <param name="reader">Instance of <see cref="EbmlReader"/>.</param> /// <param name="tracksPosition">The relative position of the tracks segment.</param> /// <param name="type">The track type identifier.</param> /// <returns>The first track number with the specified type.</returns> /// <exception cref="InvalidOperationException">Stream type is not found.</exception> internal static ulong FindFirstTrackNumberByType(this EbmlReader reader, long tracksPosition, ulong type) { reader.ReadAt(tracksPosition); reader.EnterContainer(); while (reader.FindElement(MatroskaConstants.TrackEntry)) { reader.EnterContainer(); // Mandatory element reader.FindElement(MatroskaConstants.TrackNumber); var trackNumber = reader.ReadUInt(); // Mandatory element reader.FindElement(MatroskaConstants.TrackType); var trackType = reader.ReadUInt(); reader.LeaveContainer(); if (trackType == MatroskaConstants.TrackTypeVideo) { reader.LeaveContainer(); return(trackNumber); } } reader.LeaveContainer(); throw new InvalidOperationException($"No stream with type {type} found"); }
private int[] readEbmlLaceSizes(int index, short laceCount) { int[] laceSizes = new int[laceCount + 1]; laceSizes[laceCount] = (int)(data.Length - data.Position); int startIndex = index; laceSizes[0] = (int)EbmlReader.ReadEbmlCode(data); index += Utility.CodedSizeLength((ulong)laceSizes[0], 0); laceSizes[laceCount] -= laceSizes[0]; ulong firstEbmlSize = (ulong)laceSizes[0]; ulong lastEbmlSize = 0; for (int l = 0; l < laceCount - 1; l++) { lastEbmlSize = EbmlReader.ReadSignedEbmlCode(data); index += Utility.CodedSizeLength(lastEbmlSize, 0); firstEbmlSize += lastEbmlSize; laceSizes[l + 1] = (int)firstEbmlSize; laceSizes[laceCount] -= laceSizes[l + 1]; } headerSize += (index - startIndex); laceSizes[laceCount] -= headerSize; return(laceSizes); }
public void ReadWriteContainer() { var innerdata = new MemoryStream(); var container = new EbmlWriter(innerdata); container.WriteAscii(VInt.MakeId(1), "Hello"); container.Write(VInt.MakeId(2), 12345); container.Write(VInt.MakeId(3), 123.45); _writer.Write(VInt.MakeId(5), innerdata.ToArray()); _writer.WriteAscii(VInt.MakeId(6), "end"); _stream.Position = 0; var reader = new EbmlReader(_stream); Assert.IsTrue(reader.ReadNext()); Assert.AreEqual(VInt.MakeId(5), reader.ElementId); reader.EnterContainer(); // reading inner data AssertRead(reader, 1, "Hello", r => r.ReadAscii()); AssertRead(reader, 2, 12345, r => r.ReadInt()); AssertRead(reader, 3, 123.45, r => r.ReadFloat()); reader.LeaveContainer(); // back to main stream AssertRead(reader, 6, "end", r => r.ReadAscii()); }
public void GetInfoFromMkvFile() { var filePath = SampleFilePath; using (var dataStream = File.OpenRead(filePath)) { var reader = new EbmlReader(dataStream); //reader.EnterContainer(); var headDumper = MakeElementDumper( StandardDtd.EBMLDesc.EBMLVersion, StandardDtd.EBMLDesc.EBMLReadVersion, StandardDtd.EBMLDesc.DocTypeVersion, StandardDtd.EBMLDesc.DocType, StandardDtd.EBMLDesc.DocTypeReadVersion); var trackInfoDumper = MakeElementDumper( MatroskaDtd.Tracks.TrackEntry.TrackNumber, MatroskaDtd.Tracks.TrackEntry.Name, MatroskaDtd.Tracks.TrackEntry.Language, MatroskaDtd.Tracks.TrackEntry.TrackType, MatroskaDtd.Tracks.TrackEntry.CodecName ); reader.ReadNext(); Assert.Equal(StandardDtd.EBML.Identifier, reader.ElementId); headDumper(reader); if (reader.LocateElement(MatroskaDtd.Segment)) { reader.EnterContainer(); if (reader.LocateElement(MatroskaDtd.Tracks)) { Console.WriteLine("Tracks"); reader.EnterContainer(); while (reader.ReadNext()) { if (reader.ElementId == MatroskaDtd.Tracks.TrackEntry.Identifier) { trackInfoDumper(reader); } Console.WriteLine(); } reader.LeaveContainer(); Console.WriteLine("end of Tracks"); } if (reader.LocateElement(MatroskaDtd.Segment.Cluster)) { Console.WriteLine("Got first track"); // TODO have to deal with interlaced track data } // reader.LeaveContainer(); } } }
/// <summary> /// Extracts the keyframes in ticks (scaled using the container timestamp scale) from the matroska container. /// </summary> /// <param name="filePath">The file path.</param> /// <returns>An instance of <see cref="KeyframeData"/>.</returns> public static KeyframeData GetKeyframeData(string filePath) { using var stream = File.OpenRead(filePath); using var reader = new EbmlReader(stream); var seekHead = reader.ReadSeekHead(); // External lib does not support seeking backwards (yet) Info info; ulong videoTrackNumber; if (seekHead.InfoPosition < seekHead.TracksPosition) { info = reader.ReadInfo(seekHead.InfoPosition); videoTrackNumber = reader.FindFirstTrackNumberByType(seekHead.TracksPosition, MatroskaConstants.TrackTypeVideo); } else { videoTrackNumber = reader.FindFirstTrackNumberByType(seekHead.TracksPosition, MatroskaConstants.TrackTypeVideo); info = reader.ReadInfo(seekHead.InfoPosition); } var keyframes = new List <long>(); reader.ReadAt(seekHead.CuesPosition); reader.EnterContainer(); while (reader.FindElement(MatroskaConstants.CuePoint)) { reader.EnterContainer(); ulong?trackNumber = null; // Mandatory element reader.FindElement(MatroskaConstants.CueTime); var cueTime = reader.ReadUInt(); // Mandatory element reader.FindElement(MatroskaConstants.CueTrackPositions); reader.EnterContainer(); if (reader.FindElement(MatroskaConstants.CuePointTrackNumber)) { trackNumber = reader.ReadUInt(); } reader.LeaveContainer(); if (trackNumber == videoTrackNumber) { keyframes.Add(ScaleToTicks(cueTime, info.TimestampScale)); } reader.LeaveContainer(); } reader.LeaveContainer(); var result = new KeyframeData(ScaleToTicks(info.Duration ?? 0, info.TimestampScale), keyframes); return(result); }
private void ReadTag(EbmlReader ebmlReader) { ulong targetValue = 0; ElementDescriptor desc; ebmlReader.EnterContainer(); while (ebmlReader.ReadNext()) { if (_descriptorsMap.TryGetValue(ebmlReader.ElementId.EncodedValue, out desc)) { if (desc.Name == "Targets") { ebmlReader.EnterContainer(); while (ebmlReader.ReadNext()) { if (_descriptorsMap.TryGetValue(ebmlReader.ElementId.EncodedValue, out desc) && desc.Name == "TargetTypeValue") { targetValue = ebmlReader.ReadUInt(); } } ebmlReader.LeaveContainer(); } else if (desc.Name == "SimpleTag") { string tagName = null; ebmlReader.EnterContainer(); while (ebmlReader.ReadNext()) { if (_descriptorsMap.TryGetValue(ebmlReader.ElementId.EncodedValue, out desc)) { if (desc.Name == "TagName") { tagName = ebmlReader.ReadUtf(); } else if (desc.Name == "TagString") { string key = $"{targetValue}.{tagName}"; if (!_tags.ContainsKey(key)) { _tags.Add(key, new List <string> { ebmlReader.ReadUtf() }); } else { _tags[key].Add(ebmlReader.ReadUtf()); } } } } ebmlReader.LeaveContainer(); } } } ebmlReader.LeaveContainer(); }
private EbmlReader StartRead() { _stream.Position = 0; var reader = new EbmlReader(_stream); Assert.IsTrue(reader.ReadNext()); Assert.AreEqual(ElementId, reader.ElementId); return(reader); }
private List <(ElementDescriptor Element, ulong Position)> ReadSeekHeads(EbmlReader ebmlReader) { List <(ElementDescriptor, ulong)> availableElements = null; ElementDescriptor desc; ElementDescriptor availDesc = null; ulong pos = 0; ebmlReader.EnterContainer(); while (ebmlReader.ReadNext()) { if (_descriptorsMap.TryGetValue(ebmlReader.ElementId.EncodedValue, out desc)) { if (desc.Name == "Seek") { ebmlReader.EnterContainer(); try { while (ebmlReader.ReadNext()) { if (_descriptorsMap.TryGetValue(ebmlReader.ElementId.EncodedValue, out desc)) { if (desc.Name == "SeekID") { byte[] data = new byte[ebmlReader.ElementSize]; ebmlReader.ReadBinary(data, 0, data.Length); MemoryStream mem = new MemoryStream(data); byte[] temp = new byte[data.Length]; VInt id = VInt.Read(mem, data.Length, temp); _descriptorsMap.TryGetValue(id.EncodedValue, out availDesc); } else if (desc.Name == "SeekPosition") { pos = ebmlReader.ReadUInt(); } } } if (availableElements == null) { availableElements = new List <(ElementDescriptor, ulong)>(); } if (availDesc != null && pos > 0) { availableElements.Add((availDesc, pos)); } } catch { } } ebmlReader.LeaveContainer(); } } ebmlReader.LeaveContainer(); return(availableElements); }
public static string GetName(this EbmlReader r, bool dumpValue = false) { string name = "?"; string dump = "?"; if (MatroskaSpecification.ElementDescriptors.TryGetValue(r.ElementId, out var el)) { name = el.Name; if (dumpValue) { switch (el.Type) { case ElementType.AsciiString: dump = r.ReadAscii(); break; case ElementType.Binary: dump = "'Binary Data'"; break; case ElementType.Date: dump = r.ReadDate().ToString(); break; case ElementType.Float: dump = r.ReadFloat().ToString(); break; case ElementType.SignedInteger: dump = r.ReadInt().ToString(); break; case ElementType.UnsignedInteger: dump = r.ReadUInt().ToString(); break; case ElementType.Utf8String: dump = r.ReadUtf(); break; case ElementType.MasterElement: dump = "'MasterElement'"; break; default: dump = $"unknown (id:{r})"; break; } } } return($"0x{r.ElementId.Value:X8} {name} [{r.ElementSize} bytes]" + (dumpValue ? " Value: " + dump : "")); }
/// <summary> /// Traverses the current container to find the element with <paramref name="identifier"/> identifier. /// </summary> /// <param name="reader">An instance of <see cref="EbmlReader"/>.</param> /// <param name="identifier">The element identifier.</param> /// <returns>A value indicating whether the element was found.</returns> internal static bool FindElement(this EbmlReader reader, ulong identifier) { while (reader.ReadNext()) { if (reader.ElementId.EncodedValue == identifier) { return(true); } } return(false); }
public static bool LocateElement(this EbmlReader reader, ulong identifier) { while (reader.ReadNext()) { if (reader.ElementId == identifier) { return(true); } } return(false); }
public static bool LocateElement(this EbmlReader reader, ElementDescriptor descriptor) { while (reader.ReadNext()) { var identifier = reader.ElementId; if (identifier == descriptor.Identifier) { return(true); } } return(false); }
public void ReusesPriorFiller() { var stream = new MemoryStream(); var writer = new EbmlWriter(stream); writer.Write(VInt.MakeId(122), 321); using (var segment = writer.StartMasterElement(MatroskaDtd.Segment.Identifier)) { segment.Write(StandardDtd.Void.Identifier, new byte[1000]); using (var segmentInfo = segment.StartMasterElement(MatroskaDtd.Segment.Info.Identifier)) { segmentInfo.WriteUtf(MatroskaDtd.Segment.Info.Title.Identifier, "Test data"); } // write some dummy data segment.Write(VInt.MakeId(123), 123); // marker } stream.Position = 0; // act var infoReader = new SegmentInfoUpdater(); infoReader.Open(stream); infoReader.Title = new string('a', 500); infoReader.Write(); // verify the stream is correct stream.Position = 0; var reader = new EbmlReader(stream); reader.ReadNext(); Assert.AreEqual(122, reader.ElementId.Value, "start marker"); Assert.AreEqual(321, reader.ReadInt()); reader.ReadNext(); Assert.AreEqual(MatroskaDtd.Segment.Identifier, reader.ElementId); reader.EnterContainer(); reader.ReadNext(); Assert.AreEqual(MatroskaDtd.Segment.Info.Identifier, reader.ElementId); Assert.Greater(reader.ElementSize, 500); reader.ReadNext(); Assert.AreEqual(StandardDtd.Void.Identifier, reader.ElementId); reader.ReadNext(); Assert.AreEqual(123, reader.ElementId.Value, "end data marker"); Assert.AreEqual(123, reader.ReadInt()); }
public void ParseBlock() { int index = 0; TrackNumber = (int)EbmlReader.ReadEbmlCode(data); index = Utility.CodedSizeLength((ulong)TrackNumber, 0); headerSize += index; byte[] readBytes = new byte[2]; data.Read(readBytes, 0, 2); BlockTimecode = BitConverter.ToInt16(readBytes, 0); byte flagsByte = (byte)data.ReadByte(); int keyFlag = flagsByte & 0x80; IsKeyFrame = keyFlag > 0; int laceFlag = flagsByte & 0x06; index++; headerSize += 3; if (laceFlag != 0x00) { byte laceCount = (byte)data.ReadByte(); headerSize += 1; if (laceFlag == 0x02) { sizes = readXiphLaceSizes(index, laceCount); } else if (laceFlag == 0x06) { sizes = readEbmlLaceSizes(index, laceCount); } else if (laceFlag == 0x04) { sizes = new int[laceCount + 1]; sizes[0] = (int)((data.Length - data.Position) - headerSize) / (laceCount + 1); for (int s = 0; s < laceCount; s++) { sizes[s + 1] = sizes[0]; } } else { throw new Exception("Unsupported lacing type flag."); } } headerSize = (int)data.Position; }
public MatroskaFile(FileStream inputDataSource) { level0 = null; TimecodeScale = 1000000; stream = inputDataSource; reader = new EbmlReader(stream); trackList = new List <MatroskaFileTrack>(); tagList = new List <MatroskaFileTagEntry>(); frameQueue = new List <MatroskaFileFrame>(); ScanFirstCluster = true; logger = null; initDocTypes(); }
private void ReadTags(EbmlReader ebmlReader) { _tags = new Dictionary <string, IList <string> >(); ElementDescriptor desc; ebmlReader.EnterContainer(); while (ebmlReader.ReadNext()) { if (_descriptorsMap.TryGetValue(ebmlReader.ElementId.EncodedValue, out desc) && desc.Name == "Tag") { ReadTag(ebmlReader); } } ebmlReader.LeaveContainer(); }
public static MatroskaDocument Deserialize(Stream stream) { var reader = new EbmlReader(stream); reader.ReadNext(); var ebml = Deserialize <EBML>(reader); reader.ReadNext(); var segment = Deserialize <Segment>(reader); return(new MatroskaDocument { Ebml = ebml, Segment = segment }); }
private void ReadAttachments(EbmlReader ebmlReader) { _attachments = new Dictionary <string, byte[]>(); _attachmentList = new List <MatroskaConsts.MatroskaAttachment>(); ElementDescriptor desc; ebmlReader.EnterContainer(); while (ebmlReader.ReadNext()) { if (_descriptorsMap.TryGetValue(ebmlReader.ElementId.EncodedValue, out desc) && desc.Name == "AttachedFile") { ReadAttachment(ebmlReader); } } ebmlReader.LeaveContainer(); }
private static object GetValue(MatroskaElementInfo info, EbmlReader reader) { switch (info.ElementDescriptor.Type) { case ElementType.AsciiString: return(reader.ReadAscii()); case ElementType.Binary: int bufferLength = (int)reader.ElementSize; var buffer = new byte[bufferLength]; reader.ReadBinary(buffer, 0, bufferLength); // TODO : EbmlReader does not yet support reading a Span<byte> if (typeof(IParseRawBinary).IsAssignableFrom(info.ElementType)) { var parsedRawBinary = (IParseRawBinary)Activator.CreateInstance(info.ElementType); parsedRawBinary.Parse(buffer); return(parsedRawBinary); } return(buffer); case ElementType.Date: return(reader.ReadDate()); case ElementType.Float: return(reader.ReadFloat()); case ElementType.MasterElement: return(Deserialize(info.ElementType, reader)); case ElementType.SignedInteger: return(reader.ReadInt()); case ElementType.UnsignedInteger: return(reader.ReadUInt()); case ElementType.Utf8String: return(reader.ReadUtf()); } throw new NotSupportedException(); }
private void ReadInfo(EbmlReader ebmlReader) { _infoProps = new Dictionary <string, IList <string> >(); ElementDescriptor desc; ebmlReader.EnterContainer(); while (ebmlReader.ReadNext()) { if (_descriptorsMap.TryGetValue(ebmlReader.ElementId.EncodedValue, out desc)) { if (!_infoProps.ContainsKey(desc.Name)) { _infoProps.Add(desc.Name, new List <string>()); } if (desc.Type == ElementType.AsciiString) { _infoProps[desc.Name].Add(ebmlReader.ReadAscii()); } else if (desc.Type == ElementType.Date) { _infoProps[desc.Name].Add(ebmlReader.ReadDate().ToString(CultureInfo.InvariantCulture)); } else if (desc.Type == ElementType.Float) { _infoProps[desc.Name].Add(ebmlReader.ReadFloat().ToString(CultureInfo.InvariantCulture)); } else if (desc.Type == ElementType.SignedInteger) { _infoProps[desc.Name].Add(ebmlReader.ReadInt().ToString(CultureInfo.InvariantCulture)); } else if (desc.Type == ElementType.UnsignedInteger) { _infoProps[desc.Name].Add(ebmlReader.ReadUInt().ToString(CultureInfo.InvariantCulture)); } else if (desc.Type == ElementType.Utf8String) { _infoProps[desc.Name].Add(ebmlReader.ReadUtf()); } } } ebmlReader.LeaveContainer(); }
/// <summary> /// Reads from SegmentContainer to retrieve the Info segment. /// </summary> /// <param name="reader">An instance of <see cref="EbmlReader"/>.</param> /// <param name="position">The position of the info segment relative to the Segment container.</param> /// <returns>Instance of <see cref="Info"/>.</returns> internal static Info ReadInfo(this EbmlReader reader, long position) { reader.ReadAt(position); double?duration = null; reader.EnterContainer(); // Mandatory element reader.FindElement(MatroskaConstants.TimestampScale); var timestampScale = reader.ReadUInt(); if (reader.FindElement(MatroskaConstants.Duration)) { duration = reader.ReadFloat(); } reader.LeaveContainer(); return(new Info((long)timestampScale, duration)); }
public static void LoadSRS(SortedList <int, TrackData> tracks, ref FileData file, FileInfo inFile) { using (EbmlReader rdr = new EbmlReader(inFile.FullName, EbmlReadMode.SRS)) { bool done = false; while (!done && rdr.Read()) { switch (rdr.ElementType) { case EbmlElementType.Segment: case EbmlElementType.ReSample: rdr.MoveToChild(); break; case EbmlElementType.ReSampleFile: byte[] buff = rdr.ReadContents(); file = new FileData(buff); break; case EbmlElementType.ReSampleTrack: buff = rdr.ReadContents(); TrackData track = new TrackData(buff); tracks.Add(track.TrackNumber, track); break; case EbmlElementType.Cluster: case EbmlElementType.AttachmentList: // if we get to either of these elements, we've passed the interesting part of the file, so bail out rdr.SkipContents(); done = true; break; default: rdr.SkipContents(); break; } } } }
public Element ReadNextChild(EbmlReader reader) { if (usedSize >= Size) { Utility.LogTrace("Can't read any more children."); return(null); } Element element = reader.ReadNextElement(); if (element == null) { Utility.LogDebug("Reader returned null"); return(null); } element.Parent = this; usedSize += element.TotalSize; Utility.LogTrace($"Read element {element.TypeInfo.Name} of size {element.TotalSize}, {Size - usedSize} remaining."); return(element); }
public static object Deserialize(Type type, EbmlReader reader) { bool isMasterElement = reader.IsKnownMasterElement(); if (isMasterElement) { reader.EnterContainer(); } var instance = Activator.CreateInstance(type); try { while (reader.ReadNext()) { if (TryGetInfoByIdentifier(type, reader.ElementId.EncodedValue, out var info)) { SetPropertyValue(instance, info, reader); } else { Console.WriteLine($"WARNING: {instance.GetType().Name}: property {reader.GetName(true)} not mapped."); } } } catch (Exception ex) { Console.WriteLine($"ERROR: {instance.GetType().Name} at position {reader.ElementPosition} not mapped. Exception: {ex}"); } if (isMasterElement) { reader.LeaveContainer(); } return(instance); }
public static FileData RebuildSample(FileData file, SortedList <int, TrackData> tracks, Dictionary <string, AttachmentData> attachments, FileInfo srsFile, DirectoryInfo outDir) { uint crc = Crc32.StartValue; using (EbmlReader rdr = new EbmlReader(srsFile.FullName, EbmlReadMode.SRS)) using (FileStream fsOut = new FileStream(Path.Combine(outDir.FullName, file.Name), FileMode.Create)) { string currentAttachment = null; int clustercount = 0; while (rdr.Read()) { // the ReSample element is the only part of the SRS file we don't want copied into the new sample. if (rdr.ElementType == EbmlElementType.ReSample) { rdr.SkipContents(); continue; } fsOut.Write(rdr.Element.RawHeader, 0, rdr.Element.RawHeader.Length); crc = Crc32.GetCrc(crc, rdr.Element.RawHeader); switch (rdr.ElementType) { case EbmlElementType.Segment: case EbmlElementType.BlockGroup: case EbmlElementType.AttachmentList: case EbmlElementType.Attachment: // these elements have no useful info of their own, but we want to step into them to examine their children rdr.MoveToChild(); break; case EbmlElementType.Cluster: // simple progress indicator since this can take a while (cluster is good because they're about 1mb each) Console.Write("\b{0}", Program.spinners[clustercount++ % Program.spinners.Length]); rdr.MoveToChild(); break; case EbmlElementType.AttachedFileName: byte[] buff = rdr.ReadContents(); fsOut.Write(buff, 0, buff.Length); crc = Crc32.GetCrc(crc, buff); currentAttachment = Encoding.UTF8.GetString(buff); break; case EbmlElementType.AttachedFileData: AttachmentData attachment = attachments[currentAttachment]; // restore data from extracted attachments buff = new byte[rdr.Element.Length]; attachment.AttachmentFile.Read(buff, 0, buff.Length); fsOut.Write(buff, 0, buff.Length); crc = Crc32.GetCrc(crc, buff); if ((file.Flags & FileData.FileDataFlags.AttachmentsRemoved) != 0) { rdr.MoveToChild(); // really means do nothing in this case } else { rdr.SkipContents(); } break; case EbmlElementType.Block: TrackData track = tracks[rdr.Block.TrackNumber]; // restore data from extracted tracks buff = new byte[rdr.Block.Length]; track.TrackFile.Read(buff, 0, buff.Length); fsOut.Write(rdr.Block.RawBlockHeader, 0, rdr.Block.RawBlockHeader.Length); crc = Crc32.GetCrc(crc, rdr.Block.RawBlockHeader); fsOut.Write(buff, 0, buff.Length); crc = Crc32.GetCrc(crc, buff); rdr.MoveToChild(); // really means do nothing in this case break; default: // anything not caught above is considered metadata, so we copy it as is buff = rdr.ReadContents(); fsOut.Write(buff, 0, buff.Length); crc = Crc32.GetCrc(crc, buff); break; } } } Console.Write('\b'); FileData newFile = new FileData(Path.Combine(outDir.FullName, file.Name)); newFile.Crc32 = ~crc; return(newFile); }
private static void AssertRead <T>(EbmlReader reader, uint elementId, T value, Func <EbmlReader, T> read) { Assert.IsTrue(reader.ReadNext()); Assert.AreEqual(VInt.MakeId(elementId), reader.ElementId); Assert.AreEqual(value, read(reader)); }
private void WriteData() { var reader = new EbmlReader(new MemoryStream(_oldSegmentInfoData), _oldSegmentInfoData.Length); // prepare writing part var infoStream = new MemoryStream(); var infoWriter = new EbmlWriter(infoStream); var writeMap = new[] { new { Id = MatroskaDtd.Segment.Info.Title.Identifier, Value = _title }, new { Id = MatroskaDtd.Segment.Info.WritingApp.Identifier, Value = _writingApp }, }; // enter the Segment block reader.ReadNext(); reader.EnterContainer(); while (reader.ReadNext()) { if (!writeMap.Any(arg => arg.Id == reader.ElementId)) { // copying data as is var buffer = new byte[reader.ElementSize]; reader.ReadBinary(buffer, 0, (int)reader.ElementSize); infoWriter.Write(reader.ElementId, buffer); } } // write title/app in case it was not present! foreach (var e in writeMap.Where(arg => !string.IsNullOrEmpty(arg.Value))) { infoWriter.WriteUtf(e.Id, e.Value); } var outStream = new MemoryStream(_dataLength); var writer = new EbmlWriter(outStream); writer.Write(MatroskaDtd.Segment.Info.Identifier, infoStream.ToArray()); var extraByteCount = _dataLength - outStream.Position; if (extraByteCount != 0) { var extraHLen = StandardDtd.Void.Identifier.Length + 2; var blankDataLen = (int)(extraByteCount - extraHLen); if (blankDataLen < 0) { throw new InvalidOperationException(string.Format("Not enough space to put the new data, {0} bytes to feet", -blankDataLen)); } writer.WriteElementHeader(StandardDtd.Void.Identifier, VInt.EncodeSize((ulong)blankDataLen, 2)); writer.Write(new byte[blankDataLen], 0, blankDataLen); } if (outStream.Length != _dataLength) { throw new InvalidOperationException("Failed to prepare modified data - block length mismatch"); } _stream.Position = _dataStart; _stream.Write(outStream.ToArray(), 0, _dataLength); }
private void ReadData(Stream src) { var reader = new EbmlReader(src); var readMap = new[] { new { Element = MatroskaDtd.Segment.Info.Title, Code = new Action(() => _title = reader.ReadUtf()) }, new { Element = MatroskaDtd.Segment.Info.WritingApp, Code = new Action(() => _writingApp = reader.ReadUtf()) }, new { Element = MatroskaDtd.Segment.Info.MuxingApp, Code = new Action(() => MuxingApp = reader.ReadUtf()) }, new { Element = MatroskaDtd.Segment.Info.Duration, Code = new Action(() => Duration = TimeSpan.FromMilliseconds(reader.ReadFloat())) }, }; if (!reader.LocateElement(MatroskaDtd.Segment)) { throw new InvalidDataException("Failed to locate Segment"); } reader.EnterContainer(); var segmentInfoIdentifier = MatroskaDtd.Segment.Info.Identifier; // support for Void block right before SegmentInfo var priorElementId = VInt.MakeId(0); var priorElementStart = -1l; // locate SegmentInfo and track its predesessor while (reader.ReadNext()) { if (reader.ElementId == segmentInfoIdentifier) { break; } priorElementId = reader.ElementId; priorElementStart = reader.ElementPosition; } if (reader.ElementId != segmentInfoIdentifier) { throw new InvalidDataException("Failed to locate Segment"); } _dataStart = priorElementId == StandardDtd.Void.Identifier ? priorElementStart : reader.ElementPosition; var oldDataStart = reader.ElementPosition; reader.EnterContainer(); while (reader.ReadNext()) { var entry = readMap.FirstOrDefault(arg => arg.Element.Identifier == reader.ElementId); if (entry != null) { entry.Code(); } } reader.LeaveContainer(); // getting start of the next element reader.ReadNext(); if (reader.ElementId == StandardDtd.Void.Identifier) { reader.ReadNext(); } _dataLength = (int)(reader.ElementPosition - _dataStart); var oldDataLen = (int)(reader.ElementPosition - oldDataStart); _oldSegmentInfoData = new byte[oldDataLen]; _stream.Seek(oldDataStart, SeekOrigin.Begin); _stream.Read(_oldSegmentInfoData, 0, oldDataLen); }