context: /*
  	BlamLib: .NET SDK for the Blam Engine
  
  	See license\BlamLib\BlamLib for specific license information
  */
  using System;
  using System.Linq;
  using System.Linq.Expressions;
  using System.Threading;
  
  namespace BlamLib
  {
  	/// <summary>
  	/// Standard global utility classes and functions
  	/// </summary>
  	public static partial class Util
  	{
  		#region Flags
  		/// <summary>
  		/// 
  		/// </summary>
  		/// <remarks>
  		/// This is a class so we can effectively use it as a property. 
  		/// If it was treated as a struct doing <code>[obj].Flags.Add(1);</code>
  		/// wouldn't affect [obj]'s Flags property
  		/// </remarks>
  		public sealed class Flags : IO.IStreamable
  		{
  			uint Value;
  			/// <summary>
  			/// Reset the internal value with another
  			/// </summary>
  			/// <param name="value"></param>
  			public void Reset(uint value) { Value = value; }
  			public void Reset(params uint[] values) { foreach (uint f in values) Add(f); }
  
  			public static implicit operator uint(Flags value) { return value.Value; }
  
  			public Flags(uint value) { Reset(value); }
  
  			public Flags(params uint[] values) { Reset(values); }
  
  			/// <summary>
  			/// Tests if this.Value has <paramref name="flag"/>
  			/// </summary>
  			/// <param name="flag">flag to test</param>
  			/// <returns>True if <paramref name="flag"/> is set</returns>
  			public bool Test(uint flag) { return (Value & flag) != 0; }
  
  			/// <summary>
  			/// Adds <paramref name="flags"/> from this.Value
  			/// </summary>
  			/// <param name="flags">flags to add</param>
  			public void Add(uint flags) { Value |= flags; }
  
  			/// <summary>
  			/// Adds <paramref name="flags"/> when <paramref name="cond"/> is true
  			/// </summary>
  			/// <param name="cond">condition to use to determine when to set flags</param>
  			/// <param name="flags">flags to add</param>
  			/// <returns><paramref name="cond"/>'s value</returns>
  			public bool Add(bool cond, uint flags) { if (cond) Add(flags); return cond; }
  
  			/// <summary>
  			/// Removes <paramref name="flags"/> from this.Value
  			/// </summary>
  			/// <param name="flags">flags to remove</param>
  			public void Remove(uint flags) { Value &= ~flags; }
  
  			/// <summary>
  			/// Removes <paramref name="flags"/> when <paramref name="cond"/> is true
  			/// </summary>
  			/// <param name="cond">condition to use to determine when to remove flags</param>
  			/// <param name="flags">flags to remove</param>
  			/// <returns><paramref name="cond"/>'s value</returns>
  			public bool Remove(bool cond, uint flags) { if (cond) Remove(flags); return cond; }
  
  			public override bool Equals(object obj) { return obj is Flags && (obj as Flags).Value == Value; }
  			public override int GetHashCode() { return Value.GetHashCode(); }
  			public override string ToString() { return Value.ToString(); }
  
  			#region IStreamable Members
  			public void Read(BlamLib.IO.EndianReader s)		{ Value = s.ReadUInt32(); }
  			public void Write(BlamLib.IO.EndianWriter s)	{ s.Write(Value); }
  			#endregion
  
  			#region Util
  			/// <summary>
  			/// Adds <paramref name="flags"/> from <paramref name="value"/>
  			/// </summary>
  			/// <param name="value"></param>
  			/// <param name="flags"></param>
  			/// <returns></returns>
  			public static uint Add(uint value, uint flags) { return value |= flags; }
  			/// <summary>
  			/// Adds <paramref name="flags"/> from <paramref name="value"/>
  			/// </summary>
  			/// <param name="value"></param>
  			/// <param name="flags"></param>
  			public static void Add(ref uint value, uint flags) { value |= flags; }
  
  			/// <summary>Adds <paramref name="rhs"/> to <paramref name="lhs"/></summary>
  			/// <param name="lhs">Existing bit-vector</param>
  			/// <param name="rhs">Other bit-vector whose bits we wish to add to <paramref name="lhs"/></param>
  			/// <returns><paramref name="lhs"/> != <paramref name="rhs"/></returns>
  			public static ulong Add(ulong lhs, ulong rhs)		{ return lhs |= rhs; }
  			/// <summary>Adds <paramref name="rhs"/> to <paramref name="lhs"/></summary>
  			/// <param name="lhs">Existing bit-vector reference</param>
  			/// <param name="rhs">Other bit-vector whose bits we wish to add to <paramref name="lhs"/></param>
  			public static void Add(ref ulong lhs, ulong rhs)	{ lhs |= rhs; }
  
  
  			/// <summary>
  			/// Removes <paramref name="flags"/> from <paramref name="value"/>
  			/// </summary>
  			/// <param name="value"></param>
  			/// <param name="flags"></param>
  			/// <returns></returns>
  			public static uint Remove(uint value, uint flags) { return value &= ~flags; }
  			/// <summary>
  			/// Removes <paramref name="flags"/> from <paramref name="value"/>
  			/// </summary>
  			/// <param name="value"></param>
  			/// <param name="flags"></param>
  			public static void Remove(ref uint value, uint flags) { value &= ~flags; }
  
  			/// <summary>Removes <paramref name="rhs"/> from <paramref name="lhs"/></summary>
  			/// <param name="lhs">Existing bit-vector</param>
  			/// <param name="rhs">Other bit-vector whose bits we wish to remove from <paramref name="lhs"/></param>
  			/// <returns><paramref name="lhs"/> &= <paramref name="rhs"/></returns>
  			public static ulong Remove(ulong lhs, ulong rhs)	{ return lhs &= ~rhs; }
  			/// <summary>Removes <paramref name="rhs"/> from <paramref name="lhs"/></summary>
  			/// <param name="lhs">Existing bit-vector</param>
  			/// <param name="rhs">Other bit-vector whose bits we wish to remove from <paramref name="lhs"/></param>
  			public static void Remove(ref ulong lhs, ulong rhs)	{ lhs &= ~rhs; }
  
  
  			/// <summary>
  			/// Modify <paramref name="value"/> with <paramref name="flags"/>
  			/// </summary>
  			/// <param name="add_or_remove">True to add <paramref name="flags"/>, false to remove</param>
  			/// <param name="value"></param>
  			/// <param name="flags"></param>
  			/// <returns></returns>
  			public static ushort Modify(bool add_or_remove, ushort value, ushort flags)
  			{
  				return (add_or_remove == true ?
  					value |= flags :
  					value &= (ushort)~flags);
  			}
  			/// <summary>
  			/// Modify <paramref name="value"/> with <paramref name="flags"/>
  			/// </summary>
  			/// <param name="add_or_remove">True to add <paramref name="flags"/>, false to remove</param>
  			/// <param name="value"></param>
  			/// <param name="flags"></param>
  			public static void Modify(bool add_or_remove, ref ushort value, ushort flags)
  			{
  				if (add_or_remove)
  					value |= flags;
  				else
  					value &= (ushort)~flags;
  			}
  			/// <summary>
  			/// Modify <paramref name="value"/> with <paramref name="flags"/>
  			/// </summary>
  			/// <param name="add_or_remove">True to add <paramref name="flags"/>, false to remove</param>
  			/// <param name="value"></param>
  			/// <param name="flags"></param>
  			/// <returns></returns>
  			public static uint Modify(bool add_or_remove, uint value, uint flags)
  			{
  				return (add_or_remove == true ?
  					value |= flags : 
  					value &= ~flags);
  			}
  			/// <summary>
  			/// Modify <paramref name="value"/> with <paramref name="flags"/>
  			/// </summary>
  			/// <param name="add_or_remove">True to add <paramref name="flags"/>, false to remove</param>
  			/// <param name="value"></param>
  			/// <param name="flags"></param>
  			public static void Modify(bool add_or_remove, ref uint value, uint flags)
  			{
  				if (add_or_remove == true)
  					value |= flags;
  				else
  					value &= ~flags;
  			}
  
  			/// <summary>
  			/// Returns true if <paramref name="flag"/> is active in <paramref name="value"/>
  			/// </summary>
  			/// <param name="value">Value to test in</param>
  			/// <param name="flag">Value to test for</param>
  			/// <returns></returns>
  			public static bool Test(short value, short flag) { return (value & flag) != 0; }
  
  			/// <summary>
  			/// Returns true if <paramref name="flag"/> is active in <paramref name="value"/>
  			/// </summary>
  			/// <param name="value">Value to test in</param>
  			/// <param name="flag">Value to test for</param>
  			/// <returns></returns>
  			public static bool Test(ushort value, ushort flag) { return (value & flag) != 0; }
  
  			/// <summary>
  			/// Returns true if <paramref name="flag"/> is active in <paramref name="value"/>
  			/// </summary>
  			/// <param name="value">Value to test in</param>
  			/// <param name="flag">Value to test for</param>
  			/// <returns></returns>
  			public static bool Test(int value, int flag) { return (value & flag) != 0; }
  
  			/// <summary>
  			/// Returns true if <paramref name="flag"/> is active in <paramref name="value"/>
  			/// </summary>
  			/// <param name="value">Value to test in</param>
  			/// <param name="flag">Value to test for</param>
  			/// <returns></returns>
  			public static bool Test(uint value, uint flag) { return (value & flag) != 0; }
  
  			/// <summary>
  			/// Returns true if all the flags in <paramref name="flags"/> are active in <paramref name="value"/>
  			/// </summary>
  			/// <param name="value">Value to test in</param>
  			/// <param name="flags">Values to test for</param>
  			/// <returns></returns>
  			public static bool Test(uint value, params uint[] flags)
  			{
  				bool ret = false;
  				foreach (uint i in flags)
  					ret = ret & Test(value, i);
  				return ret;
  			}
  
  			/// <summary>
  			/// Returns true if any one of the flags in <paramref name="flags"/> are active in <paramref name="value"/>
  			/// </summary>
  			/// <param name="value"></param>
  			/// <param name="flags"></param>
  			/// <returns></returns>
  			public static bool TestAny(uint value, params uint[] flags)
  			{
  				foreach (uint i in flags)
  					if (Test(value, i)) return true;
  
  				return false;
  			}
  			#endregion
  		};
  		#endregion
  
  		#region optional_value
  		public struct OptionalValue
  		{
  			private readonly int
  				k_count,
  				k_shift;
  			public readonly uint k_mask;
  
  			public OptionalValue(byte option_count)
  			{
  				option_count &= 0xDF; // make sure optional count is 32 or less
  				k_count = option_count - 1;
  				k_shift = 32 - k_count;
  				k_mask = (uint)~(k_count << k_shift);
  			}
  
  			public uint GenerateData(byte option, uint value)	{ return (uint)( (value & k_mask) | (uint)((option << k_shift)) ); }
  			public byte GetOption(uint data)					{ return (byte)((data >> k_shift) & 0xFF); }
  			public uint GetValue(uint data)						{ return data & k_mask; }
  		};
  		#endregion
  
  		#region Zlib util
  		static byte[] ZLibBufferFromStream(System.IO.Compression.DeflateStream dec, int offset, int size)
  		{
  			byte[] result;
  
  			// adjust for zlib header
  			dec.BaseStream.Seek(offset + sizeof(ushort), System.IO.SeekOrigin.Begin);
  
  			// decompress the data and fill in the result array
  			result = new byte[size];
  			dec.Read(result, 0, result.Length);
  
  			return result;
  		}
  		public static byte[] ZLibBufferFromStream(System.IO.MemoryStream ms, int offset, int size)
  		{
  			using (var dec = new System.IO.Compression.DeflateStream(ms, System.IO.Compression.CompressionMode.Decompress, true))
  			{
  				return ZLibBufferFromStream(dec, offset, size);
  			}
  		}
  		public static byte[] ZLibBufferFromBytes(byte[] bytes, int offset, int size)
  		{
  
gt: 			using(var ms = new System.IO.MemoryStream(bytes))