Update MkvInfoReader, Add MkvNode extensions
This commit is contained in:
121
MkvToolnixWrapper/MkvInfo/Reader/MkvInfoReader.cs
Normal file
121
MkvToolnixWrapper/MkvInfo/Reader/MkvInfoReader.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace MkvPropEditWrapper.MkvInfo.Reader;
|
||||
|
||||
public class MkvInfoReader
|
||||
{
|
||||
public const char LineDelimiter = '\n';
|
||||
|
||||
private readonly ReadOnlyMemory<char> _memory;
|
||||
private ReadOnlyMemory<char> _remainingMemory;
|
||||
|
||||
private readonly MkvNodeRoot _root;
|
||||
private MkvNode _currentNode;
|
||||
|
||||
private int _currentPosition;
|
||||
|
||||
public MkvInfoReader(string mkvInfoOutput)
|
||||
{
|
||||
_memory = mkvInfoOutput.AsMemory();
|
||||
_remainingMemory = _memory;
|
||||
|
||||
_root = new MkvNodeRoot();
|
||||
_currentNode = _root;
|
||||
|
||||
_currentPosition = 0;
|
||||
}
|
||||
|
||||
public MkvNodeRoot Read()
|
||||
{
|
||||
if (_root.Children.Count > 0)
|
||||
{
|
||||
return _root;
|
||||
}
|
||||
|
||||
while (_currentPosition < _memory.Length)
|
||||
{
|
||||
var line = ReadLine();
|
||||
|
||||
// Skip empty lines
|
||||
if (line.Length < 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ProcessLine(line);
|
||||
}
|
||||
|
||||
return _root;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void ProcessLine(ReadOnlyMemory<char> line)
|
||||
{
|
||||
var lineSpan = line.Span;
|
||||
|
||||
// Find depth
|
||||
int depth = lineSpan.IndexOf('+');
|
||||
|
||||
// Climb up the node tree
|
||||
while (depth <= _currentNode.Depth)
|
||||
{
|
||||
_currentNode = _currentNode.Parent!;
|
||||
}
|
||||
|
||||
// Node content
|
||||
var content = line[(depth + 2)..];
|
||||
var contentSpan = content.Span;
|
||||
|
||||
// Check for property
|
||||
int propertyIndex = contentSpan.IndexOf(':');
|
||||
|
||||
MkvNode node;
|
||||
// Property node
|
||||
if (propertyIndex != -1)
|
||||
{
|
||||
var name = content[..propertyIndex];
|
||||
var value = content[(propertyIndex + 2)..];
|
||||
|
||||
node = new MkvProperty(_currentNode, name, value);
|
||||
}
|
||||
// Generic node
|
||||
else
|
||||
{
|
||||
node = new MkvNode(_currentNode, content);
|
||||
}
|
||||
|
||||
_currentNode.Children.Add(node);
|
||||
|
||||
_currentNode = node;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read in the span till next \n or EOF while incrementing _currentPosition
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private ReadOnlyMemory<char> ReadLine()
|
||||
{
|
||||
var remainingSpan = _remainingMemory.Span;
|
||||
ReadOnlyMemory<char> line;
|
||||
|
||||
int index = remainingSpan.IndexOf(LineDelimiter);
|
||||
|
||||
// Reach the end
|
||||
if (index == -1)
|
||||
{
|
||||
line = _remainingMemory;
|
||||
_currentPosition = _memory.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
line = _remainingMemory[..(index - 1)]; // -1 to skip \r
|
||||
_currentPosition += index + 1; // Skip \n
|
||||
}
|
||||
|
||||
// Move forward in the span
|
||||
_remainingMemory = _memory[_currentPosition..];
|
||||
|
||||
return line;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user