using System; using System.Collections.Generic; using System.Linq; using System.Text; using UniversalEditor.IO; namespace UniversalEditor.Plugins.UnrealEngine { public static class ExtensionMethods { /// /// The Name type is a simple string type. The format does, although, differ between the /// package versions. /// /// /// 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 if (packageVersion >= 512) { bw.WriteUInt32((uint)value.Length); 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.WriteByte((byte)0); } } /// /// 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.) /// /// An "uncompacted" signed integer. /// There may be better ways to implement this, but this is fast, and it works. 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(); } } }