using MsgPack; using System.IO; using System; using System.Collections; using System.Collections.Generic; using CodeStage.AntiCheat.ObscuredTypes; namespace metagen { //NOTE: don't change existing values public enum MetaIoError { NONE = 0, NO_SPACE_LEFT_IN_ARRAY = 1, HAS_LEFT_SPACE = 2, ARRAY_STACK_IS_EMPTY = 3, FAIL_READ = 4, TYPE_DONT_MATCH = 5, DATA_MISSING = 7, GENERIC = 10, } public class MetaException : Exception { public MetaIoError err; public MetaException(MetaIoError err) { this.err = err; } } [System.Flags] public enum MetaSyncContextOpts { NONE = 0, USE_MASK = 1 } [System.Flags] public enum MetaSyncFieldOpts { NONE = 0, SKIP_NOT_IN_MASK = 1, SKIP_OPTIONAL = 2 } public struct MetaSyncContext { public bool is_read; public IDataReader reader; public IDataWriter writer; public Func factory; public MetaSyncContextOpts opts; public bool CanReadField(MetaSyncFieldOpts opts) { return is_read && (opts & MetaSyncFieldOpts.SKIP_NOT_IN_MASK) != MetaSyncFieldOpts.SKIP_NOT_IN_MASK; } public bool CanWriteField(MetaSyncFieldOpts opts) { return !is_read && (opts & MetaSyncFieldOpts.SKIP_NOT_IN_MASK) != MetaSyncFieldOpts.SKIP_NOT_IN_MASK; } public bool IsMaskUsed() { return (opts & MetaSyncContextOpts.USE_MASK) > 0; } public static MetaSyncContext NewForRead(Func factory, IDataReader reader, MetaSyncContextOpts opts = 0) { var ctx = new MetaSyncContext() { is_read = true, reader = reader, writer = null, factory = factory, opts = opts }; return ctx; } public static MetaSyncContext NewForWrite(IDataWriter writer, MetaSyncContextOpts opts = 0) { var ctx = new MetaSyncContext() { is_read = false, reader = null, writer = writer, opts = opts }; return ctx; } } public interface IMetaStruct { uint CLASS_ID(); int getFieldsCount(); int getWritableFieldsCount(); void syncFields(MetaSyncContext ctx); void reset(); } public interface IMetaCloneable { void copy(IMetaStruct source); IMetaStruct clone(); } public abstract class BaseMetaStruct : IMetaStruct { public virtual uint CLASS_ID() { return 0; } public virtual int getFieldsCount() { return 0; } public virtual int getWritableFieldsCount() { return 0; } public virtual void reset() {} public virtual void syncFields(MetaSyncContext ctx) {} } public interface IRpcError { bool isOk(); } public interface IRpc { int getCode(); IMetaStruct getRequest(); IMetaStruct getResponse(); IRpcError getError(); void setError(IRpcError err); } public interface IDataReader { MetaIoError ReadI8(ref sbyte v); MetaIoError ReadU8(ref byte v); MetaIoError ReadI16(ref short v); MetaIoError ReadU16(ref ushort v); MetaIoError ReadI32(ref int v); MetaIoError ReadU32(ref uint v); MetaIoError ReadU64(ref ulong v); MetaIoError ReadI64(ref long v); MetaIoError ReadFloat(ref float v); MetaIoError ReadBool(ref bool v); MetaIoError ReadDouble(ref double v); MetaIoError ReadString(ref string v); MetaIoError ReadRaw(ref byte[] v, ref int vlen); MetaIoError ReadNil(); MetaIoError BeginContainer(); MetaIoError GetContainerSize(ref int v); MetaIoError EndContainer(); } public interface IDataWriter { MetaIoError WriteI8(sbyte v); MetaIoError WriteU8(byte v); MetaIoError WriteI16(short v); MetaIoError WriteU16(ushort v); MetaIoError WriteI32(int v); MetaIoError WriteU32(uint v); MetaIoError WriteI64(long v); MetaIoError WriteU64(ulong v); MetaIoError WriteFloat(float v); MetaIoError WriteBool(bool v); MetaIoError WriteDouble(double v); MetaIoError WriteString(string v); MetaIoError WriteRaw(byte[] v); MetaIoError BeginContainer(int len); MetaIoError EndContainer(); MetaIoError End(); MetaIoError WriteNil(); } public static class Meta { public delegate void LogCb(string text); public static LogCb LogError = DefaultLog; public static LogCb LogWarn = DefaultLog; public static LogCb LogDebug = DefaultLog; public struct BitfieldsContext { long fields_mask; int curr_field_idx; MetaSyncContext ctx; readonly bool use_mask; public BitfieldsContext(MetaSyncContext ctx, long fields_mask) { this.ctx = ctx; this.use_mask = ctx.IsMaskUsed(); this.fields_mask = fields_mask; this.curr_field_idx = -1; } public void SyncMaskHeader() { if(!use_mask) return; if(ctx.is_read) { ensure(ctx.reader.ReadNil()); ensure(ctx.reader.ReadI64(ref fields_mask)); } else { ensure(ctx.writer.WriteNil()); ensure(ctx.writer.WriteI64(fields_mask)); } } public MetaSyncFieldOpts GetCurrentOpts() { if(!use_mask || curr_field_idx < 0 || curr_field_idx > 63) return 0; long curr_field_ptr = 1L << curr_field_idx; if((curr_field_ptr & fields_mask) == 0) return MetaSyncFieldOpts.SKIP_NOT_IN_MASK; return 0; } public MetaSyncFieldOpts GetNextOpts() { Advance(); return GetCurrentOpts(); } public void Advance() { curr_field_idx++; #if DEBUG if(curr_field_idx > 64) { LogError("overflow in @bitfields struct. Does it have > 64 fields?"); throw new MetaException(MetaIoError.GENERIC); } #endif } } public const int MASK_HEADER_FIELDS_COUNT = 2; public static List tmp_enums_list = new List(); static void DefaultLog(string s) {} public delegate string L_TCb(string text); public static L_TCb L_T; public delegate string L_FromListCb(IList list); public static L_FromListCb L_FromList; public delegate string L_PFromListCb(IList list, double force_n = double.NaN); public static L_PFromListCb L_Pluralize; public delegate bool L_PListCheckCb(IList list, string plural_mark); public static L_PListCheckCb L_IsPlural; public static void ensure(MetaIoError err) { if(err != 0) throw new MetaException(err); } static bool canSkipOptionalRead(MetaIoError err, MetaSyncFieldOpts opts) { return err != 0 && (opts & MetaSyncFieldOpts.SKIP_OPTIONAL) == MetaSyncFieldOpts.SKIP_OPTIONAL; } static MetaIoError checkRead(MetaIoError err, MetaSyncFieldOpts opts) { if(canSkipOptionalRead(err, opts)) { LogWarn("Skipping optional field"); return MetaIoError.NONE; } else return err; } public static void Sync(MetaSyncContext ctx, ref byte[] v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) { int len = 0; ensure(checkRead(ctx.reader.ReadRaw(ref v, ref len), opts)); } else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteRaw(v)); } public static void Sync(MetaSyncContext ctx, ref string v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) ensure(checkRead(ctx.reader.ReadString(ref v), opts)); else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteString(v)); } public static void Sync(MetaSyncContext ctx, ref ObscuredString v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) { string tmp = string.Empty; ensure(checkRead(ctx.reader.ReadString(ref tmp), opts)); v = tmp; } else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteString(v)); } public static void Sync(MetaSyncContext ctx, ref long v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) ensure(checkRead(ctx.reader.ReadI64(ref v), opts)); else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteI64(v)); } public static void Sync(MetaSyncContext ctx, ref ObscuredLong v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) { long tmp = 0; ensure(checkRead(ctx.reader.ReadI64(ref tmp), opts)); v = tmp; } else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteI64(v)); } public static void Sync(MetaSyncContext ctx, ref int v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) ensure(checkRead(ctx.reader.ReadI32(ref v), opts)); else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteI32(v)); } public static void Sync(MetaSyncContext ctx, ref ObscuredInt v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) { int tmp = 0; ensure(checkRead(ctx.reader.ReadI32(ref tmp), opts)); v = tmp; } else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteI32(v)); } public static void Sync(MetaSyncContext ctx, ref short v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) ensure(checkRead(ctx.reader.ReadI16(ref v), opts)); else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteI16(v)); } public static void Sync(MetaSyncContext ctx, ref ObscuredShort v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) { short tmp = 0; ensure(checkRead(ctx.reader.ReadI16(ref tmp), opts)); v = tmp; } else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteI16(v)); } public static void Sync(MetaSyncContext ctx, ref sbyte v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) ensure(checkRead(ctx.reader.ReadI8(ref v), opts)); else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteI8(v)); } public static void Sync(MetaSyncContext ctx, ref ObscuredSByte v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) { sbyte tmp = 0; ensure(checkRead(ctx.reader.ReadI8(ref tmp), opts)); v = tmp; } else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteI8(v)); } public static void Sync(MetaSyncContext ctx, ref ulong v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) ensure(checkRead(ctx.reader.ReadU64(ref v), opts)); else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteU64(v)); } public static void Sync(MetaSyncContext ctx, ref ObscuredULong v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) { ulong tmp = 0; ensure(checkRead(ctx.reader.ReadU64(ref tmp), opts)); v = tmp; } else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteU64(v)); } public static void Sync(MetaSyncContext ctx, ref ushort v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) ensure(checkRead(ctx.reader.ReadU16(ref v), opts)); else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteU16(v)); } public static void Sync(MetaSyncContext ctx, ref ObscuredUShort v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) { ushort tmp = 0; ensure(checkRead(ctx.reader.ReadU16(ref tmp), opts)); v = tmp; } else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteU16(v)); } public static void Sync(MetaSyncContext ctx, ref uint v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) ensure(checkRead(ctx.reader.ReadU32(ref v), opts)); else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteU32(v)); } public static void Sync(MetaSyncContext ctx, ref ObscuredUInt v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) { uint tmp = 0; ensure(checkRead(ctx.reader.ReadU32(ref tmp), opts)); v = tmp; } else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteU32(v)); } public static void Sync(MetaSyncContext ctx, ref byte v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) ensure(checkRead(ctx.reader.ReadU8(ref v), opts)); else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteU8(v)); } public static void Sync(MetaSyncContext ctx, ref ObscuredByte v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) { byte tmp = 0; ensure(checkRead(ctx.reader.ReadU8(ref tmp), opts)); v = tmp; } else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteU8(v)); } public static void Sync(MetaSyncContext ctx, ref bool v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) ensure(checkRead(ctx.reader.ReadBool(ref v), opts)); else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteBool(v)); } public static void Sync(MetaSyncContext ctx, ref ObscuredBool v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) { bool tmp = false; ensure(checkRead(ctx.reader.ReadBool(ref tmp), opts)); v = tmp; } else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteBool(v)); } public static void Sync(MetaSyncContext ctx, ref float v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) ensure(checkRead(ctx.reader.ReadFloat(ref v), opts)); else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteFloat(v)); } public static void Sync(MetaSyncContext ctx, ref ObscuredFloat v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) { float tmp = 0f; ensure(checkRead(ctx.reader.ReadFloat(ref tmp), opts)); v = tmp; } else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteFloat(v)); } public static void Sync(MetaSyncContext ctx, ref double v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) ensure(checkRead(ctx.reader.ReadDouble(ref v), opts)); else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteDouble(v)); } public static void Sync(MetaSyncContext ctx, ref ObscuredDouble v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) { double tmp = 0; ensure(checkRead(ctx.reader.ReadDouble(ref tmp), opts)); v = tmp; } else if(ctx.CanWriteField(opts)) ensure(ctx.writer.WriteDouble(v)); } static int SyncBeginListGetSize(MetaSyncContext ctx, IList v, MetaSyncFieldOpts opts) { if(ctx.CanReadField(opts)) { var err = ctx.reader.BeginContainer(); if(canSkipOptionalRead(err, opts)) { LogWarn("Skipping optional array field"); return -1; } ensure(err); int size = 0; ensure(ctx.reader.GetContainerSize(ref size)); return size; } else if(ctx.CanWriteField(opts)) { int size = v == null ? 0 : v.Count; ensure(ctx.writer.BeginContainer(size)); return size; } else return -1; } static int SyncBeginList(MetaSyncContext ctx, List v, ref MetaSyncFieldOpts opts) { int size = SyncBeginListGetSize(ctx, v, opts); if(size == -1) return size; if(ctx.is_read && v.Capacity < size) v.Capacity = size; //NOTE: unsetting opts for array items opts &= ~MetaSyncFieldOpts.SKIP_OPTIONAL; opts &= ~MetaSyncFieldOpts.SKIP_NOT_IN_MASK; return size; } static void SyncEndList(MetaSyncContext ctx, IList v) { if(ctx.is_read) ensure(ctx.reader.EndContainer()); else ensure(ctx.writer.EndContainer()); } public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) { int size = SyncBeginList(ctx, v, ref opts); if(size == -1) return; for(int i = 0; i < size; ++i) { var tmp = ctx.is_read ? "" : v[i]; Sync(ctx, ref tmp, opts); if(ctx.is_read) v.Add(tmp); } SyncEndList(ctx, v); } public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) { int size = SyncBeginList(ctx, v, ref opts); if(size == -1) return; for(int i = 0; i < size; ++i) { var tmp = ctx.is_read ? default(long) : v[i]; Sync(ctx, ref tmp, opts); if(ctx.is_read) v.Add(tmp); } SyncEndList(ctx, v); } public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) { int size = SyncBeginList(ctx, v, ref opts); if(size == -1) return; for(int i = 0; i < size; ++i) { var tmp = ctx.is_read ? default(int) : v[i]; Sync(ctx, ref tmp, opts); if(ctx.is_read) v.Add(tmp); } SyncEndList(ctx, v); } public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) { int size = SyncBeginList(ctx, v, ref opts); if(size == -1) return; for(int i = 0; i < size; ++i) { var tmp = ctx.is_read ? default(short) : v[i]; Sync(ctx, ref tmp, opts); if(ctx.is_read) v.Add(tmp); } SyncEndList(ctx, v); } public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) { int size = SyncBeginList(ctx, v, ref opts); if(size == -1) return; for(int i = 0; i < size; ++i) { var tmp = ctx.is_read ? default(sbyte) : v[i]; Sync(ctx, ref tmp, opts); if(ctx.is_read) v.Add(tmp); } SyncEndList(ctx, v); } public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) { int size = SyncBeginList(ctx, v, ref opts); if(size == -1) return; for(int i = 0; i < size; ++i) { var tmp = ctx.is_read ? default(ulong) : v[i]; Sync(ctx, ref tmp, opts); if(ctx.is_read) v.Add(tmp); } SyncEndList(ctx, v); } public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) { int size = SyncBeginList(ctx, v, ref opts); if(size == -1) return; for(int i = 0; i < size; ++i) { var tmp = ctx.is_read ? default(uint) : v[i]; Sync(ctx, ref tmp, opts); if(ctx.is_read) v.Add(tmp); } SyncEndList(ctx, v); } public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) { int size = SyncBeginList(ctx, v, ref opts); if(size == -1) return; for(int i = 0; i < size; ++i) { var tmp = ctx.is_read ? default(ushort) : v[i]; Sync(ctx, ref tmp, opts); if(ctx.is_read) v.Add(tmp); } SyncEndList(ctx, v); } public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) { int size = SyncBeginList(ctx, v, ref opts); if(size == -1) return; for(int i = 0; i < size; ++i) { var tmp = ctx.is_read ? default(byte) : v[i]; Sync(ctx, ref tmp, opts); if(ctx.is_read) v.Add(tmp); } SyncEndList(ctx, v); } public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) { int size = SyncBeginList(ctx, v, ref opts); if(size == -1) return; for(int i = 0; i < size; ++i) { var tmp = ctx.is_read ? default(bool) : v[i]; Sync(ctx, ref tmp, opts); if(ctx.is_read) v.Add(tmp); } SyncEndList(ctx, v); } public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) { int size = SyncBeginList(ctx, v, ref opts); if(size == -1) return; for(int i = 0; i < size; ++i) { var tmp = ctx.is_read ? default(float) : v[i]; Sync(ctx, ref tmp, opts); if(ctx.is_read) v.Add(tmp); } SyncEndList(ctx, v); } public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) { int size = SyncBeginList(ctx, v, ref opts); if(size == -1) return; for(int i = 0; i < size; ++i) { var tmp = ctx.is_read ? default(double) : v[i]; Sync(ctx, ref tmp, opts); if(ctx.is_read) v.Add(tmp); } SyncEndList(ctx, v); } public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) where T : IMetaStruct, new() { int size = SyncBeginList(ctx, v, ref opts); if(size == -1) return; if(ctx.is_read) v.Clear(); for(int i = 0; i < size; ++i) { var tmp = ctx.is_read ? new T() : v[i]; Sync(ctx, ref tmp, opts); if(ctx.is_read) v.Add(tmp); } SyncEndList(ctx, v); } public static IMetaStruct SyncGeneric(MetaSyncContext ctx, IMetaStruct v, MetaSyncFieldOpts opts = 0) { if(ctx.CanReadField(opts)) { ensure(ctx.reader.BeginContainer()); uint clid = 0; ensure(ctx.reader.ReadU32(ref clid)); //NOTE: when reading we ignore the passed argument v = ctx.factory(clid); if(v == null) { LogError("Could not create struct: " + clid); ensure(MetaIoError.TYPE_DONT_MATCH); } v.reset(); v.syncFields(ctx); ensure(ctx.reader.EndContainer()); } else if(ctx.CanWriteField(opts)) { ensure(ctx.writer.BeginContainer(v.getFieldsCount() + 1)); ensure(ctx.writer.WriteU32(v.CLASS_ID())); v.syncFields(ctx); ensure(ctx.writer.EndContainer()); } return v; } public static void SyncGeneric(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) where T : IMetaStruct, new() { int size = SyncBeginList(ctx, v, ref opts); if(size == -1) return; for(int i = 0; i < size; ++i) { var tmp = SyncGeneric(ctx, ctx.is_read ? default(T) : v[i]); if(ctx.is_read) v.Add((T)tmp); } SyncEndList(ctx, v); } public static void Sync(MetaSyncContext ctx, ref T v, MetaSyncFieldOpts opts = 0) where T : IMetaStruct { if(ctx.CanReadField(opts)) { var err = ctx.reader.BeginContainer(); if(canSkipOptionalRead(err, opts)) { LogWarn("Skipping optional struct field"); return; } ensure(err); v.reset(); v.syncFields(ctx); ensure(ctx.reader.EndContainer()); } else if(ctx.CanWriteField(opts)) { int array_size = getWriteFieldsCount(ctx, v); ensure(ctx.writer.BeginContainer(array_size)); v.syncFields(ctx); ensure(ctx.writer.EndContainer()); } } public static MetaIoError SyncSafe(MetaSyncContext ctx, ref T v, MetaSyncFieldOpts opts = 0) where T : IMetaStruct { try { Sync(ctx, ref v, opts); } catch(MetaException e) { LogError(e.Message + " " + e.StackTrace); return e.err; } catch(Exception e) { LogError(e.Message + " " + e.StackTrace); return MetaIoError.GENERIC; } return MetaIoError.NONE; } static int getWriteFieldsCount(MetaSyncContext ctx, IMetaStruct v) { if(ctx.IsMaskUsed()) return v.getWritableFieldsCount(); else return v.getFieldsCount(); } public static MetaSyncContext PrepareForClone(ref T src) where T : IMetaStruct { var stream = new MemoryStream(); var ctx = new MetaSyncContext() { is_read = false, reader = new MsgPackDataReader(stream), writer = new MsgPackDataWriter(stream), opts = 0 }; Sync(ctx, ref src); ctx.is_read = true; stream.Position = 0; return ctx; } //Shared mask utils below public static int GetDirtyFieldsCount(long fields_mask, int fields_count) { int changed_fields = 0; long ptr = 1L; for(int i=0; i(ref List v) { if(v == null) v = new List(); v.Clear(); } public static string I18NPick(string raw_val, List list_val, string plural_marker, double pluralize_for_n) { if(raw_val.Length != 0) return Meta.L_T(raw_val); if(Meta.L_IsPlural(list_val, plural_marker)) return Meta.L_Pluralize(list_val, pluralize_for_n); return Meta.L_FromList(list_val); } public static void Reset(ref T v) where T : IMetaStruct, new() { if(v == null) v = new T(); v.reset(); } } public class MsgPackDataWriter : IDataWriter { Stream stream; MsgPackWriter io; Stack space = new Stack(); public MsgPackDataWriter(Stream _stream) { reset(_stream); } public void reset(Stream _stream) { stream = _stream; io = new MsgPackWriter(stream); space.Clear(); space.Push(1); } MetaIoError decSpace() { if(space.Count == 0) return MetaIoError.NO_SPACE_LEFT_IN_ARRAY; int left = space.Pop(); left--; if(left < 0) return MetaIoError.NO_SPACE_LEFT_IN_ARRAY; space.Push(left); return 0; } public MetaIoError BeginContainer(int size) { MetaIoError err = decSpace(); if(err != 0) return err; space.Push(size); io.WriteArrayHeader(size); return 0; } public MetaIoError EndContainer() { if(space.Count <= 1) return MetaIoError.ARRAY_STACK_IS_EMPTY; int left = space.Pop(); if(left != 0) return MetaIoError.HAS_LEFT_SPACE; return 0; } public MetaIoError End() { if(space.Count != 1) return MetaIoError.ARRAY_STACK_IS_EMPTY; return 0; } public MetaIoError WriteI8(sbyte v) { io.Write(v); return decSpace(); } public MetaIoError WriteU8(byte v) { io.Write(v); return decSpace(); } public MetaIoError WriteI16(short v) { io.Write(v); return decSpace(); } public MetaIoError WriteU16(ushort v) { io.Write(v); return decSpace(); } public MetaIoError WriteI32(int v) { io.Write(v); return decSpace(); } public MetaIoError WriteU32(uint v) { io.Write(v); return decSpace(); } public MetaIoError WriteU64(ulong v) { io.Write(v); return decSpace(); } public MetaIoError WriteI64(long v) { io.Write(v); return decSpace(); } public MetaIoError WriteBool(bool v) { io.Write(v); return decSpace(); } public MetaIoError WriteFloat(float v) { io.Write(v); return decSpace(); } public MetaIoError WriteDouble(double v) { io.Write(v); return decSpace(); } public MetaIoError WriteString(string v) { if(v == null) io.Write(""); else io.Write(v); return decSpace(); } public MetaIoError WriteNil() { io.WriteNil(); return decSpace(); } public MetaIoError WriteRaw(byte[] v) { io.Write(v); return decSpace(); } } public class MsgPackDataReader : IDataReader { Stream stream; MsgPackReader io; public struct ContainerPosition { public int max; public int curr; public ContainerPosition(int length) { curr = 0; max = length - 1; } } Stack stack = new Stack(); public MsgPackDataReader(Stream _stream) { reset(_stream); } public void reset(Stream _stream) { stream = _stream; stack.Clear(); io = new MsgPackReader(stream); } public void setPos(long pos) { stream.Position = pos; stack.Clear(); } int nextInt(ref MetaIoError err) { if(!ContainerPositionValid()) { err = MetaIoError.DATA_MISSING; return 0; } if(!io.Read()) { err = MetaIoError.FAIL_READ; return 0; } ContainerPositionMoveNext(); if(io.IsSigned()) return io.ValueSigned; else if(io.IsUnsigned()) return (int)io.ValueUnsigned; else { Meta.LogWarn("Got type: " + io.Type); err = MetaIoError.TYPE_DONT_MATCH; return 0; } } uint nextUint(ref MetaIoError err) { if(!ContainerPositionValid()) { err = MetaIoError.DATA_MISSING; return 0; } if(!io.Read()) { err = MetaIoError.FAIL_READ; return 0; } ContainerPositionMoveNext(); if(io.IsUnsigned()) return io.ValueUnsigned; else if(io.IsSigned()) return (uint)io.ValueSigned; else { Meta.LogWarn("Got type: " + io.Type); err = MetaIoError.TYPE_DONT_MATCH; return 0; } } bool nextBool(ref MetaIoError err) { if(!ContainerPositionValid()) { err = MetaIoError.DATA_MISSING; return false; } if(!io.Read()) { err = MetaIoError.FAIL_READ; return false; } ContainerPositionMoveNext(); if(io.IsBoolean()) return (bool)io.ValueBoolean; else if(io.IsUnsigned()) return io.ValueUnsigned != 0; else if(io.IsSigned()) return (uint)io.ValueSigned != 0; else { Meta.LogWarn("Got type: " + io.Type); err = MetaIoError.TYPE_DONT_MATCH; return false; } } ulong nextUint64(ref MetaIoError err) { if(!ContainerPositionValid()) { err = MetaIoError.DATA_MISSING; return 0; } if(!io.Read()) { err = MetaIoError.FAIL_READ; return 0; } ContainerPositionMoveNext(); if(io.IsUnsigned()) return io.ValueUnsigned; else if(io.IsSigned()) return (ulong)io.ValueSigned; else if(io.IsUnsigned64()) return io.ValueUnsigned64; else if(io.IsSigned64()) return (ulong)io.ValueSigned64; else { Meta.LogWarn("Got type: " + io.Type); err = MetaIoError.TYPE_DONT_MATCH; return 0; } } long nextInt64(ref MetaIoError err) { if(!ContainerPositionValid()) { err = MetaIoError.DATA_MISSING; return 0; } if(!io.Read()) { err = MetaIoError.FAIL_READ; return 0; } ContainerPositionMoveNext(); if(io.IsUnsigned()) return (long)io.ValueUnsigned; else if(io.IsSigned()) return io.ValueSigned; else if(io.IsUnsigned64()) return (long)io.ValueUnsigned64; else if(io.IsSigned64()) return io.ValueSigned64; else { Meta.LogWarn("Got type: " + io.Type); err = MetaIoError.TYPE_DONT_MATCH; return 0; } } public MetaIoError ReadI8(ref sbyte v) { MetaIoError err = 0; v = (sbyte) nextInt(ref err); return err; } public MetaIoError ReadI16(ref short v) { MetaIoError err = 0; v = (short) nextInt(ref err); return err; } public MetaIoError ReadI32(ref int v) { MetaIoError err = 0; v = nextInt(ref err); return err; } public MetaIoError ReadU8(ref byte v) { MetaIoError err = 0; v = (byte) nextUint(ref err); return err; } public MetaIoError ReadU16(ref ushort v) { MetaIoError err = 0; v = (ushort) nextUint(ref err); return err; } public MetaIoError ReadU32(ref uint v) { MetaIoError err = 0; v = nextUint(ref err); return err; } public MetaIoError ReadU64(ref ulong v) { MetaIoError err = 0; v = nextUint64(ref err); return err; } public MetaIoError ReadI64(ref long v) { MetaIoError err = 0; v = nextInt64(ref err); return err; } public MetaIoError ReadBool(ref bool v) { MetaIoError err = 0; v = nextBool(ref err); return err; } public MetaIoError ReadFloat(ref float v) { if(!ContainerPositionValid()) return MetaIoError.DATA_MISSING; if(!io.Read()) { return MetaIoError.FAIL_READ; } if(io.IsUnsigned()) { v = io.ValueUnsigned; } else if(io.IsSigned()) { v = io.ValueSigned; } else { switch(io.Type) { case TypePrefixes.Float: v = io.ValueFloat; break; case TypePrefixes.Double: var tmp = io.ValueDouble; //TODO: //if(tmp > float.MaxValue || tmp < float.MinValue) //{ // Meta.LogWarn("Double -> Float bad conversion: " + tmp); // return MetaIoError.TYPE_DONT_MATCH; //} v = (float) tmp; break; default: Meta.LogWarn("Got type: " + io.Type); return MetaIoError.TYPE_DONT_MATCH; } } ContainerPositionMoveNext(); return 0; } public MetaIoError ReadDouble(ref double v) { if(!ContainerPositionValid()) return MetaIoError.DATA_MISSING; if(!io.Read()) { return MetaIoError.FAIL_READ; } if(io.IsUnsigned()) { v = io.ValueUnsigned; } else if(io.IsSigned()) { v = io.ValueSigned; } else { switch(io.Type) { case TypePrefixes.Float: v = (double) io.ValueFloat; break; case TypePrefixes.Double: v = io.ValueDouble; break; case TypePrefixes.UInt64: v = (double) io.ValueUnsigned64; break; case TypePrefixes.Int64: v = (double) io.ValueSigned64; break; default: Meta.LogWarn("Got type: " + io.Type); return MetaIoError.TYPE_DONT_MATCH; } } ContainerPositionMoveNext(); return 0; } public MetaIoError ReadRaw(ref byte[] v, ref int vlen) { if(!ContainerPositionValid()) return MetaIoError.DATA_MISSING; if(!io.Read()) return MetaIoError.FAIL_READ; if(!io.IsRaw()) { Meta.LogWarn("Got type: " + io.Type); return MetaIoError.TYPE_DONT_MATCH; } vlen = (int)io.Length; if(v == null) v = new byte[vlen]; else if(v.Length < vlen) Array.Resize(ref v, vlen); io.ReadValueRaw(v, 0, vlen); ContainerPositionMoveNext(); return 0; } public MetaIoError ReadNil() { if(!ContainerPositionValid()) return MetaIoError.DATA_MISSING; if(!io.Read()) return MetaIoError.FAIL_READ; if(io.Type != TypePrefixes.Nil) { Meta.LogWarn("Got type: " + io.Type); return MetaIoError.TYPE_DONT_MATCH; } ContainerPositionMoveNext(); return 0; } public MetaIoError ReadString(ref string v) { if(!ContainerPositionValid()) return MetaIoError.DATA_MISSING; if(!io.Read()) return MetaIoError.FAIL_READ; if(!io.IsRaw()) { Meta.LogWarn("Got type: " + io.Type); return MetaIoError.TYPE_DONT_MATCH; } //TODO: use shared buffer for strings loading byte[] strval = new byte[io.Length]; io.ReadValueRaw(strval, 0, strval.Length); v = System.Text.Encoding.UTF8.GetString(strval); ContainerPositionMoveNext(); return 0; } public MetaIoError BeginContainer() { if(!ContainerPositionValid()) return MetaIoError.DATA_MISSING; if(!io.Read()) return MetaIoError.FAIL_READ; if(!io.IsArray()) { Meta.LogWarn("Got type: " + io.Type); return MetaIoError.TYPE_DONT_MATCH; } ContainerPosition ap = new ContainerPosition((int)io.Length); stack.Push(ap); return 0; } public MetaIoError GetContainerSize(ref int v) { if(!io.IsArray()) { Meta.LogWarn("Got type: " + io.Type); return MetaIoError.TYPE_DONT_MATCH; } v = (int) io.Length; return 0; } void SkipField() { if(!io.Read()) return; if(!io.IsArray() && !io.IsMap()) { //NOTE: if value is a raw string we need to read all of its data if(io.IsRaw()) io.ReadRawString(); return; } uint array_len = io.Length; for(uint i=0; i -1) { SkipField(); ContainerPositionMoveNext(); } } public MetaIoError EndContainer() { SkipTrailingFields(); stack.Pop(); ContainerPositionMoveNext(); return 0; } int ContainerEntriesLeft() { if(stack.Count == 0) return 0; ContainerPosition ap = stack.Peek(); return ap.max - ap.curr; } bool ContainerPositionValid() { return ContainerEntriesLeft() >= 0; } void ContainerPositionMoveNext() { if(stack.Count > 0) { ContainerPosition ap = stack.Pop(); ap.curr++; stack.Push(ap); } } } } //namespace metagen