Skip to content

Commit

Permalink
Add CheckIfXMFVersionMatches() for version check through XMF
Browse files Browse the repository at this point in the history
  • Loading branch information
neon-nyan committed Jan 18, 2023
1 parent 01916ba commit baeecdd
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 24 deletions.
63 changes: 45 additions & 18 deletions Hi3Helper.EncTool/XMFParser/Class/MetadataParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ private void TryCheckXMFPath()
}

// Try enumerate XMF file from the given path.
string assumedXMFPath = Directory.EnumerateFiles(_xmfPath, "Blocks*.xmf", SearchOption.TopDirectoryOnly).FirstOrDefault();
string assumedXMFPath = Directory.EnumerateFiles(_xmfPath, "Blocks.xmf", SearchOption.TopDirectoryOnly).FirstOrDefault();
if (assumedXMFPath != null)
{
_xmfPath = assumedXMFPath;
Expand All @@ -40,12 +40,12 @@ private void ParseMetadata()
using (Stream stream = new FileStream(_xmfPath, FileMode.Open, FileAccess.Read))
{
// Read XMF with Endianess-aware BinaryReader
using (_bigEndBinReader = new EndianBinaryReader(stream))
using (EndianBinaryReader reader = new EndianBinaryReader(stream))
{
// Start read the header of the XMF file.
ReadHeader();
ReadHeader(reader);
// Start read the metadata including block info and asset indexes.
ReadMetadata();
ReadMetadata(reader);
// Finalize by creating catalog for block lookup as hash name and index.
// This will make searching process for the block easier.
CreateBlockIndexCatalog(BlockCount);
Expand All @@ -63,44 +63,58 @@ private void CreateBlockIndexCatalog(uint count)
}
}

private void ReadHeader()
internal static byte[] ReadSignature(EndianBinaryReader reader)
{
// Switch to Little-endian to read header.
_bigEndBinReader.endian = UABT.EndianType.LittleEndian;
VersionSignature = _bigEndBinReader.ReadBytes(0x10);
reader.endian = UABT.EndianType.LittleEndian;
return reader.ReadBytes(_signatureLength);
}

internal static int[] ReadVersion(EndianBinaryReader reader)
{
// Read block version.
Version = new int[_versioningLength];
int[] ver = new int[_versioningLength];
for (int i = 0; i < _versioningLength; i++)
{
Version[i] = _bigEndBinReader.ReadInt32();
if (Version[i] < _allowedMinVersion || Version[i] > _allowedMaxVersion)
ver[i] = reader.ReadInt32();
if (ver[i] < _allowedMinVersion || ver[i] > _allowedMaxVersion)
{
throw new InvalidDataException($"Header version on array: {i} is invalid with value: {Version[i]}. The allowed range is: ({_allowedMinVersion} - {_allowedMaxVersion})");
throw new InvalidDataException($"Header version on array: {i} is invalid with value: {ver[i]}. The allowed range is: ({_allowedMinVersion} - {_allowedMaxVersion})");
}
}

return ver;
}

private void ReadHeader(EndianBinaryReader reader)
{
// Read signature (32 bytes).
VersionSignature = ReadSignature(reader);

// Read block version.
Version = ReadVersion(reader);

// Try read endian mode.
byte readMode = _bigEndBinReader.ReadByte();
byte readMode = reader.ReadByte();
if (readMode > 1)
{
throw new InvalidDataException("Read mode is invalid! The value should be 0 for Big-endian and 1 for Little-endian");
}

// If readMode == 0, then switch to Big-endian.
if (readMode == 0) _bigEndBinReader.endian = UABT.EndianType.BigEndian;
if (readMode == 0) reader.endian = UABT.EndianType.BigEndian;

// Allocate the size of Block array.
BlockEntry = new XMFBlock[_bigEndBinReader.ReadUInt32()];
BlockEntry = new XMFBlock[reader.ReadUInt32()];
}

private void ReadMetadata()
private void ReadMetadata(EndianBinaryReader reader)
{
// Initialize the XMFBlock instance to the BlockEntry array.
// At the same time, the XMFBlock will read the metadata section of the block.
for (int i = 0; i < BlockEntry.Length; i++)
{
BlockEntry[i] = new XMFBlock(_bigEndBinReader);
BlockEntry[i] = new XMFBlock(reader);
}
}

Expand All @@ -127,7 +141,7 @@ public XMFBlock GetBlockByHashString(string hash)
/// <summary>
/// Get the enumeration of the block hashes in a string form.
/// </summary>
/// <returns>Ennumeration of the block hashes.</returns>
/// <returns>Enumeration of the block hashes.</returns>
public IEnumerable<string> EnumerateBlockHashString()
{
uint count = BlockCount;
Expand All @@ -137,10 +151,23 @@ public IEnumerable<string> EnumerateBlockHashString()
}
}

/// <summary>
/// Get the enumeration of the block file path.
/// </summary>
/// <returns>Enumeration of the block hashes.</returns>
public IEnumerable<string> EnumerateBlockPath()
{
uint count = BlockCount;
for (uint i = 0; i < count; i++)
{
yield return Path.Combine(_folderPath, BlockEntry[i].HashString + ".wmv");
}
}

/// <summary>
/// Get the enumeration of the block hashes in a byte array.
/// </summary>
/// <returns>Ennumeration of the block hashes in byte array form.</returns>
/// <returns>Enumeration of the block hashes in byte array form.</returns>
public IEnumerable<byte[]> EnumerateBlockHash()
{
uint count = BlockCount;
Expand Down
2 changes: 1 addition & 1 deletion Hi3Helper.EncTool/XMFParser/Class/XMFBlock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public XMFAsset GetAssetByName(string name)
/// <summary>
/// Get the enumeration of the asset file name in a string form.
/// </summary>
/// <returns>Ennumeration of the asset file names.</returns>
/// <returns>Enumeration of the asset file names.</returns>
public IEnumerable<string> EnumerateAssetNames()
{
uint count = AssetCount;
Expand Down
36 changes: 36 additions & 0 deletions Hi3Helper.EncTool/XMFParser/Class/XMFUtility.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Hi3Helper.UABT;
using Hi3Helper.UABT.Binary;
using System;
using System.IO;

namespace Hi3Helper.EncTool
{
public static class XMFUtility
{
/// <summary>
/// Compares the version given from <c>versionBytes</c> with the one from xmfPath.
/// </summary>
/// <param name="xmfPath">The path of the XMF file to compare.</param>
/// <param name="versionBytes">The <c>int</c> array of version to compare. The array length must be 4.</param>
/// <returns>
/// If the version contained in the XMF file matches the one from <c>versionBytes</c> or there's any fault, then return <c>false</c>.<br/>
/// If it matches, then return <c>true</c>.
/// </returns>
public static bool CheckIfXMFVersionMatches(string xmfPath, ReadOnlySpan<int> versionBytes)
{
FileInfo xmf = new FileInfo(xmfPath);

if (!xmf.Exists) return false;
if (versionBytes.Length != XMFParser._versioningLength) return false;

using (EndianBinaryReader reader = new EndianBinaryReader(xmf.OpenRead(), EndianType.LittleEndian))
{
reader.Position = XMFParser._signatureLength;
ReadOnlySpan<int> versionXMF = XMFParser.ReadVersion(reader);

return versionXMF[0] == versionBytes[0] && versionXMF[1] == versionBytes[1]
&& versionXMF[2] == versionBytes[2] && versionXMF[3] == versionBytes[3];
}
}
}
}
15 changes: 10 additions & 5 deletions Hi3Helper.EncTool/XMFParser/XMFParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ namespace Hi3Helper.EncTool
{
public sealed partial class XMFParser
{
private const byte _versioningLength = 4;
private const byte _allowedMinVersion = 0;
private const byte _allowedMaxVersion = 64;
private string _xmfPath { get; set; }
internal const byte _signatureLength = 0x10; // 16
internal const byte _versioningLength = 0x04; // 4
internal const byte _allowedMinVersion = 0x00; // 0
internal const byte _allowedMaxVersion = 0x40; // 64
internal string _xmfPath;
internal static string _folderPath;
private EndianBinaryReader _bigEndBinReader { get; set; }

/// <summary>
/// Represent the class of the XMFParser.<br/>
Expand Down Expand Up @@ -53,6 +53,11 @@ public XMFParser(string path)
/// </summary>
public int[] Version { get; private set; }

/// <summary>
/// The directory location of the block files.
/// </summary>
public string BlockDirectory { get => _folderPath; }

/// <summary>
/// Entries of the Block file defined as an array of <c>XMFBlock</c> class.
/// </summary>
Expand Down

0 comments on commit baeecdd

Please sign in to comment.