130 lines
4.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UniversalEditor.IO;
namespace UniversalEditor.Plugins.UnrealEngine
{
public static class ExtensionMethods
{
/// <summary>
/// The Name type is a simple string type. The format does, although, differ between the
/// package versions.
/// </summary>
/// <param name="br"></param>
/// <returns></returns>
public static string ReadNAME(this Reader br, int packageVersion)
{
string value = String.Empty;
// Older package versions (<64, original Unreal engine) store the Name type as a
// zero-terminated ASCII string; "UT2k3", for example would be stored as:
// "U" "T" "2" "k" "3" 0x00
if (packageVersion < 64)
{
value = br.ReadNullTerminatedString();
}
else if (packageVersion >= 512)
{
uint length = br.ReadUInt32();
value = br.ReadNullTerminatedString();
}
else
{
// Newer packages (>=64, UT engine) prepend the length of the string plus the trailing
// zero. Again, "UT2k3" would be now stored as: 0x06 "U" "T" "2" "k" "3" 0x00
value = br.ReadLengthPrefixedString();
if (value.EndsWith("\0"))
{
value = value.TrimNull();
}
else
{
// do we need this sanity check?
throw new InvalidOperationException();
}
}
return value;
}
public static void WriteNAME(this Writer bw, string value, int packageVersion)
{
// Older package versions (<64, original Unreal engine) store the Name type as a
// zero-terminated ASCII string; "UT2k3", for example would be stored as:
// "U" "T" "2" "k" "3" 0x00
if (packageVersion < 64)
{
bw.WriteNullTerminatedString(value);
}
else
{
// Newer packages (>=64, UT engine) prepend the length of the string plus the trailing
// zero. Again, "UT2k3" would be now stored as: 0x06 "U" "T" "2" "k" "3" 0x00
bw.WriteLengthPrefixedString(value);
bw.WriteInt32((byte)0);
}
}
/// <summary>
/// Reads a compact integer from the FileReader. Bytes read differs, so do not make
/// assumptions about physical data being read from the stream. (If you have to, get the
/// difference of FileReader.BaseStream.Position before and after this is executed.)
/// </summary>
/// <returns>An "uncompacted" signed integer.</returns>
/// <remarks>There may be better ways to implement this, but this is fast, and it works.</remarks>
public static int ReadINDEX(this Reader br)
{
int output = 0;
bool signed = false;
for (int i = 0; i < 5; i++)
{
byte x = br.ReadByte();
// First byte
if (i == 0)
{
// Bit: X0000000
if ((x & 0x80) > 0)
{
signed = true;
}
// Bits: 00XXXXXX
output |= (x & 0x3F);
// Bit: 0X000000
if ((x & 0x40) == 0)
{
break;
}
}
// Last byte
else if (i == 4)
{
// Bits: 000XXXXX -- the 0 bits are ignored
// (hits the 32 bit boundary)
output |= (x & 0x1F) << (6 + (3 * 7));
}
// Middle bytes
else
{
// Bits: 0XXXXXXX
output |= (x & 0x7F) << (6 + ((i - 1) * 7));
// Bit: X0000000
if ((x & 0x80) == 0)
{
break;
}
}
}
// multiply by negative one here, since the first 6+ bits could be 0
if (signed)
{
output *= -1;
}
return (output);
}
public static void WriteINDEX(this Writer bw, int value)
{
throw new NotImplementedException();
}
}
}