2014-07-22 03:26:28 +08:00
|
|
|
//! \file Utility.cs
|
|
|
|
//! \date Sat Jul 05 02:47:33 2014
|
2014-07-28 04:50:18 +08:00
|
|
|
//! \brief utility classes for GameRes assembly.
|
|
|
|
//
|
|
|
|
// Copyright (C) 2014 by morkt
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
// of this software and associated documentation files (the "Software"), to
|
|
|
|
// deal in the Software without restriction, including without limitation the
|
|
|
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
|
|
// sell copies of the Software, and to permit persons to whom the Software is
|
|
|
|
// furnished to do so, subject to the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
|
// IN THE SOFTWARE.
|
2014-07-22 03:26:28 +08:00
|
|
|
//
|
|
|
|
|
2016-10-16 13:22:53 +08:00
|
|
|
using System.Collections.Generic;
|
2015-04-17 02:39:57 +08:00
|
|
|
using System.Text;
|
2014-08-16 08:23:12 +08:00
|
|
|
|
2014-07-22 03:26:28 +08:00
|
|
|
namespace GameRes.Utility
|
|
|
|
{
|
|
|
|
public static class Binary
|
|
|
|
{
|
|
|
|
public static uint BigEndian (uint u)
|
|
|
|
{
|
2016-10-04 03:23:43 +08:00
|
|
|
return u << 24 | (u & 0xff00) << 8 | (u & 0xff0000) >> 8 | u >> 24;
|
2014-07-22 03:26:28 +08:00
|
|
|
}
|
|
|
|
public static int BigEndian (int i)
|
|
|
|
{
|
|
|
|
return (int)BigEndian ((uint)i);
|
|
|
|
}
|
|
|
|
public static ushort BigEndian (ushort u)
|
|
|
|
{
|
2016-10-04 03:23:43 +08:00
|
|
|
return (ushort)(u << 8 | u >> 8);
|
2014-07-22 03:26:28 +08:00
|
|
|
}
|
|
|
|
public static short BigEndian (short i)
|
|
|
|
{
|
|
|
|
return (short)BigEndian ((ushort)i);
|
|
|
|
}
|
|
|
|
public static ulong BigEndian (ulong u)
|
|
|
|
{
|
|
|
|
return (ulong)BigEndian((uint)(u & 0xffffffff)) << 32
|
|
|
|
| (ulong)BigEndian((uint)(u >> 32));
|
|
|
|
}
|
|
|
|
public static long BigEndian (long i)
|
|
|
|
{
|
|
|
|
return (long)BigEndian ((ulong)i);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static bool AsciiEqual (byte[] name1, string name2)
|
|
|
|
{
|
|
|
|
return AsciiEqual (name1, 0, name2);
|
|
|
|
}
|
|
|
|
|
2017-01-17 22:18:11 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Check if sequence of ASCII characters in array <paramref name="name1"/> is equal to string <paramref name="name2"/>.
|
|
|
|
/// This methods avoids costly construction of the string object from byte array for a mere purpose of
|
|
|
|
/// comparison.
|
|
|
|
/// </summary>
|
2014-07-22 03:26:28 +08:00
|
|
|
public static bool AsciiEqual (byte[] name1, int offset, string name2)
|
|
|
|
{
|
2016-10-16 20:13:57 +08:00
|
|
|
return name1.AsciiEqual (offset, name2);
|
2014-07-22 03:26:28 +08:00
|
|
|
}
|
2014-08-25 19:04:26 +08:00
|
|
|
|
2017-01-17 22:18:11 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Copy potentially overlapping sequence of <paramref name="count"/> bytes in array
|
|
|
|
/// <paramref name="data"/> from <paramref name="src"/> to <paramref name="dst"/>.
|
|
|
|
/// If destination offset resides within source region then sequence will repeat itself. Widely used
|
|
|
|
/// in various compression techniques.
|
|
|
|
/// </summary>
|
2014-08-25 19:04:26 +08:00
|
|
|
public static void CopyOverlapped (byte[] data, int src, int dst, int count)
|
|
|
|
{
|
2015-12-06 00:26:36 +08:00
|
|
|
if (dst > src)
|
2014-08-25 19:04:26 +08:00
|
|
|
{
|
2015-07-19 19:29:00 +08:00
|
|
|
while (count > 0)
|
|
|
|
{
|
2015-12-06 00:26:36 +08:00
|
|
|
int preceding = System.Math.Min (dst - src, count);
|
2015-07-19 19:29:00 +08:00
|
|
|
System.Buffer.BlockCopy (data, src, data, dst, preceding);
|
|
|
|
dst += preceding;
|
|
|
|
count -= preceding;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
System.Buffer.BlockCopy (data, src, data, dst, count);
|
2014-08-25 19:04:26 +08:00
|
|
|
}
|
|
|
|
}
|
2015-04-17 02:39:57 +08:00
|
|
|
|
2017-01-17 22:18:11 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Extract null-terminated string (a "C string") from array <paramref name="data"/> starting
|
|
|
|
/// at offset <paramref name="index"/> up to <paramref name="length_limit"/> bytes long, stored in
|
|
|
|
/// encoding <paramref name="enc"/>.
|
|
|
|
/// </summary>
|
2015-04-17 02:39:57 +08:00
|
|
|
public static string GetCString (byte[] data, int index, int length_limit, Encoding enc)
|
|
|
|
{
|
|
|
|
int name_length = 0;
|
|
|
|
while (name_length < length_limit && 0 != data[index+name_length])
|
|
|
|
name_length++;
|
|
|
|
return enc.GetString (data, index, name_length);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static string GetCString (byte[] data, int index, int length_limit)
|
|
|
|
{
|
|
|
|
return GetCString (data, index, length_limit, Encodings.cp932);
|
|
|
|
}
|
2015-12-01 15:24:48 +08:00
|
|
|
|
2016-09-13 07:04:37 +08:00
|
|
|
public static string GetCString (byte[] data, int index)
|
|
|
|
{
|
|
|
|
return GetCString (data, index, data.Length - index, Encodings.cp932);
|
|
|
|
}
|
|
|
|
|
2015-12-01 15:24:48 +08:00
|
|
|
public static uint RotR (uint v, int count)
|
|
|
|
{
|
|
|
|
count &= 0x1F;
|
|
|
|
return v >> count | v << (32-count);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static uint RotL (uint v, int count)
|
|
|
|
{
|
|
|
|
count &= 0x1F;
|
|
|
|
return v << count | v >> (32-count);
|
|
|
|
}
|
2015-12-03 19:51:06 +08:00
|
|
|
|
2016-01-15 15:50:13 +08:00
|
|
|
public static ulong RotR (ulong v, int count)
|
|
|
|
{
|
|
|
|
count &= 0x3F;
|
|
|
|
return v >> count | v << (64-count);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static ulong RotL (ulong v, int count)
|
|
|
|
{
|
|
|
|
count &= 0x3F;
|
|
|
|
return v << count | v >> (64-count);
|
|
|
|
}
|
|
|
|
|
2015-12-03 19:51:06 +08:00
|
|
|
public static byte RotByteR (byte v, int count)
|
|
|
|
{
|
|
|
|
count &= 7;
|
|
|
|
return (byte)(v >> count | v << (8-count));
|
|
|
|
}
|
|
|
|
|
|
|
|
public static byte RotByteL (byte v, int count)
|
|
|
|
{
|
|
|
|
count &= 7;
|
|
|
|
return (byte)(v << count | v >> (8-count));
|
|
|
|
}
|
2014-07-22 03:26:28 +08:00
|
|
|
}
|
|
|
|
|
2015-04-14 14:30:23 +08:00
|
|
|
public static class BigEndian
|
|
|
|
{
|
2016-10-16 13:22:53 +08:00
|
|
|
public static ushort ToUInt16<TArray> (TArray value, int index) where TArray : IList<byte>
|
2015-11-18 01:30:46 +08:00
|
|
|
{
|
|
|
|
return (ushort)(value[index] << 8 | value[index+1]);
|
|
|
|
}
|
|
|
|
|
2016-10-16 13:22:53 +08:00
|
|
|
public static short ToInt16<TArray> (TArray value, int index) where TArray : IList<byte>
|
2015-11-18 01:30:46 +08:00
|
|
|
{
|
|
|
|
return (short)(value[index] << 8 | value[index+1]);
|
|
|
|
}
|
|
|
|
|
2016-10-16 13:22:53 +08:00
|
|
|
public static uint ToUInt32<TArray> (TArray value, int index) where TArray : IList<byte>
|
2015-04-14 14:30:23 +08:00
|
|
|
{
|
|
|
|
return (uint)(value[index] << 24 | value[index+1] << 16 | value[index+2] << 8 | value[index+3]);
|
|
|
|
}
|
|
|
|
|
2016-10-16 13:22:53 +08:00
|
|
|
public static int ToInt32<TArray> (TArray value, int index) where TArray : IList<byte>
|
2015-04-14 14:30:23 +08:00
|
|
|
{
|
|
|
|
return (int)ToUInt32 (value, index);
|
|
|
|
}
|
2018-10-19 03:00:21 +08:00
|
|
|
|
|
|
|
public static void Pack (ushort value, byte[] buf, int index)
|
|
|
|
{
|
|
|
|
buf[index] = (byte)(value >> 8);
|
|
|
|
buf[index+1] = (byte)(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void Pack (uint value, byte[] buf, int index)
|
|
|
|
{
|
|
|
|
buf[index] = (byte)(value >> 24);
|
|
|
|
buf[index+1] = (byte)(value >> 16);
|
|
|
|
buf[index+2] = (byte)(value >> 8);
|
|
|
|
buf[index+3] = (byte)(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void Pack (ulong value, byte[] buf, int index)
|
|
|
|
{
|
|
|
|
Pack ((uint)(value >> 32), buf, index);
|
|
|
|
Pack ((uint)value, buf, index+4);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void Pack (short value, byte[] buf, int index)
|
|
|
|
{
|
|
|
|
Pack ((ushort)value, buf, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void Pack (int value, byte[] buf, int index)
|
|
|
|
{
|
|
|
|
Pack ((uint)value, buf, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void Pack (long value, byte[] buf, int index)
|
|
|
|
{
|
|
|
|
Pack ((ulong)value, buf, index);
|
|
|
|
}
|
2015-04-14 14:30:23 +08:00
|
|
|
}
|
|
|
|
|
2014-07-22 03:26:28 +08:00
|
|
|
public static class LittleEndian
|
|
|
|
{
|
2016-10-16 20:13:57 +08:00
|
|
|
public static ushort ToUInt16<TArray> (TArray value, int index) where TArray : IList<byte>
|
2014-07-22 03:26:28 +08:00
|
|
|
{
|
|
|
|
return (ushort)(value[index] | value[index+1] << 8);
|
|
|
|
}
|
|
|
|
|
2016-10-16 20:13:57 +08:00
|
|
|
public static short ToInt16<TArray> (TArray value, int index) where TArray : IList<byte>
|
2014-07-22 03:26:28 +08:00
|
|
|
{
|
|
|
|
return (short)(value[index] | value[index+1] << 8);
|
|
|
|
}
|
|
|
|
|
2016-10-16 13:22:53 +08:00
|
|
|
public static uint ToUInt32<TArray> (TArray value, int index) where TArray : IList<byte>
|
2014-07-22 03:26:28 +08:00
|
|
|
{
|
|
|
|
return (uint)(value[index] | value[index+1] << 8 | value[index+2] << 16 | value[index+3] << 24);
|
|
|
|
}
|
|
|
|
|
2016-10-16 20:13:57 +08:00
|
|
|
public static int ToInt32<TArray> (TArray value, int index) where TArray : IList<byte>
|
2014-07-22 03:26:28 +08:00
|
|
|
{
|
|
|
|
return (int)ToUInt32 (value, index);
|
|
|
|
}
|
2014-07-25 04:52:24 +08:00
|
|
|
|
2016-10-16 20:13:57 +08:00
|
|
|
public static ulong ToUInt64<TArray> (TArray value, int index) where TArray : IList<byte>
|
2014-07-25 04:52:24 +08:00
|
|
|
{
|
|
|
|
return (ulong)ToUInt32 (value, index) | ((ulong)ToUInt32 (value, index+4) << 32);
|
|
|
|
}
|
|
|
|
|
2016-10-16 20:13:57 +08:00
|
|
|
public static long ToInt64<TArray> (TArray value, int index) where TArray : IList<byte>
|
2014-07-25 04:52:24 +08:00
|
|
|
{
|
|
|
|
return (long)ToUInt64 (value, index);
|
|
|
|
}
|
2015-04-14 14:30:23 +08:00
|
|
|
|
|
|
|
public static void Pack (ushort value, byte[] buf, int index)
|
|
|
|
{
|
|
|
|
buf[index] = (byte)(value);
|
|
|
|
buf[index+1] = (byte)(value >> 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void Pack (uint value, byte[] buf, int index)
|
|
|
|
{
|
|
|
|
buf[index] = (byte)(value);
|
|
|
|
buf[index+1] = (byte)(value >> 8);
|
|
|
|
buf[index+2] = (byte)(value >> 16);
|
|
|
|
buf[index+3] = (byte)(value >> 24);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void Pack (ulong value, byte[] buf, int index)
|
|
|
|
{
|
|
|
|
Pack ((uint)value, buf, index);
|
|
|
|
Pack ((uint)(value >> 32), buf, index+4);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void Pack (short value, byte[] buf, int index)
|
|
|
|
{
|
|
|
|
Pack ((ushort)value, buf, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void Pack (int value, byte[] buf, int index)
|
|
|
|
{
|
|
|
|
Pack ((uint)value, buf, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void Pack (long value, byte[] buf, int index)
|
|
|
|
{
|
|
|
|
Pack ((ulong)value, buf, index);
|
|
|
|
}
|
2014-07-22 03:26:28 +08:00
|
|
|
}
|
|
|
|
|
2015-05-29 18:51:28 +08:00
|
|
|
public class AsciiString
|
|
|
|
{
|
|
|
|
public byte[] Value { get; set; }
|
|
|
|
public int Length { get { return Value.Length; } }
|
|
|
|
|
|
|
|
public AsciiString (int size)
|
|
|
|
{
|
|
|
|
Value = new byte[size];
|
|
|
|
}
|
|
|
|
|
|
|
|
public AsciiString (byte[] str)
|
|
|
|
{
|
|
|
|
Value = str;
|
|
|
|
}
|
|
|
|
|
|
|
|
public AsciiString (string str)
|
|
|
|
{
|
|
|
|
Value = Encoding.ASCII.GetBytes (str);
|
|
|
|
}
|
|
|
|
|
|
|
|
public override string ToString ()
|
|
|
|
{
|
|
|
|
return Encoding.ASCII.GetString (Value);
|
|
|
|
}
|
|
|
|
|
|
|
|
public override bool Equals (object o)
|
|
|
|
{
|
|
|
|
if (null == o)
|
|
|
|
return false;
|
|
|
|
var a = o as AsciiString;
|
|
|
|
if (null == (object)a)
|
|
|
|
return false;
|
|
|
|
return this == a;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override int GetHashCode ()
|
|
|
|
{
|
|
|
|
int hash = 5381;
|
|
|
|
for (int i = 0; i < Value.Length; ++i)
|
|
|
|
{
|
|
|
|
hash = ((hash << 5) + hash) ^ Value[i];
|
|
|
|
}
|
|
|
|
return hash ^ (hash * 1566083941);;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static bool operator== (AsciiString a, AsciiString b)
|
|
|
|
{
|
|
|
|
if (ReferenceEquals (a, b))
|
|
|
|
return true;
|
|
|
|
if (null == (object)a || null == (object)b)
|
|
|
|
return false;
|
|
|
|
if (a.Length != b.Length)
|
|
|
|
return false;
|
|
|
|
for (int i = 0; i < a.Length; ++i)
|
|
|
|
if (a.Value[i] != b.Value[i])
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static bool operator!= (AsciiString a, AsciiString b)
|
|
|
|
{
|
|
|
|
return !(a == b);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static bool operator== (AsciiString a, string b)
|
|
|
|
{
|
|
|
|
return Binary.AsciiEqual (a.Value, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static bool operator!= (AsciiString a, string b)
|
|
|
|
{
|
|
|
|
return !(a == b);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static bool operator== (string a, AsciiString b)
|
|
|
|
{
|
|
|
|
return b == a;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static bool operator!= (string a, AsciiString b)
|
|
|
|
{
|
|
|
|
return !(b == a);
|
|
|
|
}
|
|
|
|
}
|
2015-06-01 04:51:02 +08:00
|
|
|
|
|
|
|
public interface IDataUnpacker
|
|
|
|
{
|
|
|
|
byte[] Data { get; }
|
|
|
|
void Unpack ();
|
|
|
|
}
|
2014-07-22 03:26:28 +08:00
|
|
|
}
|