diff --git a/Src/Core/EbmlReader.cs b/Src/Core/EbmlReader.cs index 6256f99..54ac354 100644 --- a/Src/Core/EbmlReader.cs +++ b/Src/Core/EbmlReader.cs @@ -84,21 +84,39 @@ public bool ReadNext() _element = Element.Empty; return false; } + + ReadElement(); + return true; + } - ElementPosition = _source.Position; - var identifier = ReadVarInt(4); + /// + /// Reads the next child element of the current container at the specified position and positions the stream at the beginning of the element data. + /// + /// The exact position in the current container to read the next element from. + /// true if the child element is available; false otherwise + /// if the value of the element identifier or element data size read from the stream is reserved + public bool ReadAt(long position) + { + _container.Remaining -= _element.Size; + _element = _container; - if (identifier.IsReserved) + if (_element.Remaining < 1) { - throw new EbmlDataFormatException("invalid element identifier value"); + _element = Element.Empty; + return false; } - var size = ReadVarInt(8).Value; - if (size > (ulong)_container.Remaining) + // compute the desired position relative to the current position in the container + var relativePosition = position - (_container.Size - _container.Remaining); + + if (relativePosition < 0) { - throw new EbmlDataFormatException("invalid element size value"); + throw new EbmlDataFormatException("invalid position, seeking backwards is not supported"); } - _element = new Element(identifier, (long) size, ElementType.None); + + Skip(relativePosition); + + ReadElement(); return true; } @@ -167,10 +185,8 @@ public void LeaveContainer() throw new InvalidOperationException(); } _container.Remaining -= _element.Size; - Skip(_container.Remaining); - _container.Remaining = 0; _element = _container; - + Skip(_element.Remaining); _container = _containers.Pop(); } @@ -406,6 +422,26 @@ private void Skip(long length) } } + private void ReadElement() + { + ElementPosition = _source.Position; + + var identifier = ReadVarInt(4); + + if (identifier.IsReserved) + { + throw new EbmlDataFormatException("invalid element identifier value"); + } + + var size = ReadVarInt(8).Value; + if (size > (ulong)_container.Remaining) + { + throw new EbmlDataFormatException("invalid element size value"); + } + + _element = new Element(identifier, (long) size, ElementType.None); + } + /// /// Reads the element data as a variable size integer. ///