diff --git a/ChoiSerializer/ChoiSerializer.sln b/ChoiSerializer/ChoiSerializer.sln
new file mode 100644
index 0000000..38861c5
--- /dev/null
+++ b/ChoiSerializer/ChoiSerializer.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.28307.852
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChoiSerializer", "ChoiSerializer\ChoiSerializer.csproj", "{5090CEE5-6850-4D61-8F6B-5875302F97E1}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example", "Example\Example.csproj", "{E4D665E2-DEC0-46A4-B8D4-70E907A1E358}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {5090CEE5-6850-4D61-8F6B-5875302F97E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5090CEE5-6850-4D61-8F6B-5875302F97E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5090CEE5-6850-4D61-8F6B-5875302F97E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5090CEE5-6850-4D61-8F6B-5875302F97E1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E4D665E2-DEC0-46A4-B8D4-70E907A1E358}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E4D665E2-DEC0-46A4-B8D4-70E907A1E358}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E4D665E2-DEC0-46A4-B8D4-70E907A1E358}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E4D665E2-DEC0-46A4-B8D4-70E907A1E358}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {DFCFE196-88F3-4F95-AA16-BE8CA71D1F6A}
+ EndGlobalSection
+EndGlobal
diff --git a/ChoiSerializer/ChoiSerializer/Annotation/MappedForLength.cs b/ChoiSerializer/ChoiSerializer/Annotation/MappedForLength.cs
new file mode 100644
index 0000000..2af6f4d
--- /dev/null
+++ b/ChoiSerializer/ChoiSerializer/Annotation/MappedForLength.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Reflection;
+
+namespace ChoiSerializer.Annotation
+{
+ public delegate int ValueToLengthConvertDelegate(object value);
+
+ public class MappedForLength : SerializerBaseAttribute
+ {
+ public string Target { get; set; }
+
+ public ValueToLengthConvertDelegate ValueConverterDelegate { get; set; }
+
+ private string valueConverter = "";
+
+ public string ValueConverter
+ {
+ set
+ {
+ valueConverter = value;
+ var arguments = value.Split('.');
+ var assembly = Assembly.GetEntryAssembly();
+ Type callerType = null;
+ foreach (var type in assembly.ExportedTypes)
+ {
+ if (type.Name.Equals(arguments[0]))
+ callerType = type;
+ }
+ ValueConverterDelegate = (ValueToLengthConvertDelegate)Delegate.CreateDelegate(typeof(ValueToLengthConvertDelegate), callerType, arguments[1]);
+ }
+ get { return valueConverter; }
+ }
+ }
+}
diff --git a/ChoiSerializer/ChoiSerializer/Annotation/MappedForSize.cs b/ChoiSerializer/ChoiSerializer/Annotation/MappedForSize.cs
new file mode 100644
index 0000000..b33d57c
--- /dev/null
+++ b/ChoiSerializer/ChoiSerializer/Annotation/MappedForSize.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Reflection;
+
+namespace ChoiSerializer.Annotation
+{
+ public delegate int ValueToSizeConvertDelegate(object value);
+
+ public class MappedForSize : SerializerBaseAttribute
+ {
+ public string Target { get; set; }
+
+ public ValueToSizeConvertDelegate ValueConverterDelegate { get; set; }
+
+ private string valueConverter = "";
+
+ public string ValueConverter
+ {
+ set
+ {
+ valueConverter = value;
+ var arguments = value.Split('.');
+ var assembly = Assembly.GetExecutingAssembly();
+ Type callerType = null;
+ foreach (var type in assembly.ExportedTypes)
+ {
+ if (type.Name.Equals(arguments[0]))
+ callerType = type;
+ }
+ ValueConverterDelegate = (ValueToSizeConvertDelegate)Delegate.CreateDelegate(typeof(ValueToSizeConvertDelegate), callerType, arguments[1]);
+ }
+ get { return valueConverter; }
+ }
+ }
+}
diff --git a/ChoiSerializer/ChoiSerializer/Annotation/MappedForType.cs b/ChoiSerializer/ChoiSerializer/Annotation/MappedForType.cs
new file mode 100644
index 0000000..c82f67f
--- /dev/null
+++ b/ChoiSerializer/ChoiSerializer/Annotation/MappedForType.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Reflection;
+
+namespace ChoiSerializer.Annotation
+{
+ public delegate Type ValueToTypeConvertDelegate(object value);
+
+ public class MappedForType : SerializerBaseAttribute
+ {
+ public string Target { get; set; }
+
+ public ValueToTypeConvertDelegate ValueConverterDelegate { get; set; }
+
+ private string valueConverter = "";
+
+ public string ValueConverter
+ {
+ set
+ {
+ valueConverter = value;
+ var arguments = value.Split('.');
+ var assembly = Assembly.GetEntryAssembly();
+ Type callerType = null;
+ foreach (var type in assembly.ExportedTypes)
+ {
+ if (type.Name.Equals(arguments[0]))
+ callerType = type;
+ }
+ ValueConverterDelegate = (ValueToTypeConvertDelegate)Delegate.CreateDelegate(typeof(ValueToTypeConvertDelegate), callerType, arguments[1]);
+ }
+ get { return valueConverter; }
+ }
+
+ //private int GetLengthOfTarget(string valueConverter, object fieldValue)
+ //{
+ // var arguments = valueConverter.Split('.');
+ // var assembly = Assembly.GetCallingAssembly();
+ // Type callerType = null;
+ // foreach (var type in assembly.ExportedTypes)
+ // {
+ // if (type.Name.Equals(arguments[0]))
+ // callerType = type;
+ // }
+ // ValueToLengthConvertDelegate valueConverterDelegate = (ValueToLengthConvertDelegate)Delegate.CreateDelegate(typeof(ValueToLengthConvertDelegate), callerType, arguments[1]);
+ // return valueConverterDelegate(fieldValue);
+ //}
+
+ //private Type GetTypeOfTarget(string valueConverter, object fieldValue)
+ //{
+ // var arguments = valueConverter.Split('.');
+ // var assembly = Assembly.GetEntryAssembly();
+ // Type callerType = null;
+ // foreach (var type in assembly.ExportedTypes)
+ // {
+ // if (type.Name.Equals(arguments[0]))
+ // callerType = type;
+ // }
+ // ValueToTypeConvertDelegate valueConverterDelegate = (ValueToTypeConvertDelegate)Delegate.CreateDelegate(typeof(ValueToTypeConvertDelegate), callerType, arguments[1]);
+ // return valueConverterDelegate(fieldValue);
+ //}
+ }
+}
diff --git a/ChoiSerializer/ChoiSerializer/Annotation/SerializableCulumn.cs b/ChoiSerializer/ChoiSerializer/Annotation/SerializableCulumn.cs
new file mode 100644
index 0000000..6feeedf
--- /dev/null
+++ b/ChoiSerializer/ChoiSerializer/Annotation/SerializableCulumn.cs
@@ -0,0 +1,9 @@
+namespace ChoiSerializer.Annotation
+{
+ public class SerializableCulumn : SerializerBaseAttribute
+ {
+ public int Index { get; set; }
+
+ public int Length { get; set; } = 0;
+ }
+}
diff --git a/ChoiSerializer/ChoiSerializer/Annotation/SerializerBaseAttribute.cs b/ChoiSerializer/ChoiSerializer/Annotation/SerializerBaseAttribute.cs
new file mode 100644
index 0000000..5615f4d
--- /dev/null
+++ b/ChoiSerializer/ChoiSerializer/Annotation/SerializerBaseAttribute.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace ChoiSerializer.Annotation
+{
+ [AttributeUsage(AttributeTargets.Property)]
+ public class SerializerBaseAttribute : Attribute
+ {
+ }
+}
diff --git a/ChoiSerializer/ChoiSerializer/ChoiFormatter.cs b/ChoiSerializer/ChoiSerializer/ChoiFormatter.cs
new file mode 100644
index 0000000..53c7f50
--- /dev/null
+++ b/ChoiSerializer/ChoiSerializer/ChoiFormatter.cs
@@ -0,0 +1,24 @@
+using System.IO;
+using System.Runtime.Serialization;
+
+namespace ChoiSerializer
+{
+ public class ChoiFormatter : IFormatter
+ {
+ public SerializationBinder Binder { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); }
+
+ public StreamingContext Context { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); }
+
+ public ISurrogateSelector SurrogateSelector { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); }
+
+ public object Deserialize(Stream serializationStream)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public void Serialize(Stream serializationStream, object graph)
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+}
diff --git a/ChoiSerializer/ChoiSerializer/ChoiSerializer.csproj b/ChoiSerializer/ChoiSerializer/ChoiSerializer.csproj
new file mode 100644
index 0000000..9f0ce15
--- /dev/null
+++ b/ChoiSerializer/ChoiSerializer/ChoiSerializer.csproj
@@ -0,0 +1,9 @@
+
+
+
+ netstandard2.0
+
+
+
+
+
diff --git a/ChoiSerializer/ChoiSerializer/Serializable.cs b/ChoiSerializer/ChoiSerializer/Serializable.cs
new file mode 100644
index 0000000..6c2d85c
--- /dev/null
+++ b/ChoiSerializer/ChoiSerializer/Serializable.cs
@@ -0,0 +1,349 @@
+using ChoiSerializer.Annotation;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+
+namespace ChoiSerializer
+{
+ public class Serializable
+ {
+ public SerializationContext Context { get; set; }
+
+ public Serializable(SerializationContext context)
+ {
+ Context = context;
+ }
+
+ public byte[] Serialize()
+ {
+ Type myType = GetType();
+
+ var prs = myType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).Where(p => p.CustomAttributes.Where(att => att.AttributeType == typeof(SerializableCulumn)).Count() > 0).ToList();
+ prs.OrderBy(p => (int)p.CustomAttributes.Where(att => att.AttributeType == typeof(SerializableCulumn)).FirstOrDefault().NamedArguments.Where(a => a.MemberName.Equals("Index")).FirstOrDefault().TypedValue.Value).ToList();
+
+ foreach (var item in prs)
+ {
+ foreach (CustomAttributeData att in item.CustomAttributes)
+ {
+ if (att.AttributeType == typeof(SerializableCulumn))
+ {
+ var culumnDefi = (SerializableCulumn)Attribute.GetCustomAttributes(item).ToList().Where(attr => attr is SerializableCulumn).FirstOrDefault();
+
+ int length = culumnDefi.Length;
+
+ switch (Type.GetTypeCode(item.PropertyType))
+ {
+ case TypeCode.Single:
+ Context.DataSource.PutSingle(((float)item.GetValue(this)));
+ break;
+
+ case TypeCode.UInt16:
+ Context.DataSource.PutUShort((ushort)item.GetValue(this));
+ break;
+
+ case TypeCode.UInt32:
+ Context.DataSource.PutUInt((uint)item.GetValue(this));
+ break;
+
+ case TypeCode.UInt64:
+ Context.DataSource.PutULong((ulong)item.GetValue(this));
+ break;
+
+ case TypeCode.Int16:
+ Context.DataSource.PutShort((short)item.GetValue(this));
+ break;
+
+ case TypeCode.Int32:
+ Context.DataSource.PutInt((int)item.GetValue(this));
+ break;
+
+ case TypeCode.Int64:
+ Context.DataSource.PutLong((long)item.GetValue(this));
+ break;
+
+ case TypeCode.Byte:
+ Context.DataSource.Put((byte)item.GetValue(this));
+ break;
+
+ case TypeCode.Char:
+ Context.DataSource.Put((byte)(char)item.GetValue(this));
+ break;
+
+ case TypeCode.String:
+ Context.DataSource.Put(Encoding.UTF8.GetBytes((string)item.GetValue(this)), length);
+ break;
+
+ case TypeCode.Object:
+ if (item.PropertyType.IsGenericType && item.PropertyType.Name.StartsWith("List"))
+ {
+ var objects = (IList)item.GetValue(this);
+ if (objects != null)
+ {
+ foreach (Serializable obj in objects)
+ {
+ obj.Context = this.Context;
+ obj.Serialize();
+ }
+ }
+ }
+ else if (item.PropertyType == typeof(byte[]))
+ {
+ Context.DataSource.Put((byte[])item.GetValue(this));
+ }
+ else
+ {
+ var obj = item.GetValue(this);
+ if (obj is Serializable)
+ {
+ ((Serializable)obj).Context = this.Context;
+ ((Serializable)obj).Serialize();
+ }
+ else if (obj is byte[] && obj != null)
+ {
+ Context.DataSource.Put((byte[])item.GetValue(this));
+ }
+ else if (obj.GetType().Name.StartsWith("List"))
+ {
+ var objects = (IList)obj;
+ if (objects != null)
+ {
+ foreach (Serializable sobj in objects)
+ {
+ sobj.Context = this.Context;
+ sobj.Serialize();
+ }
+ }
+ }
+ }
+ break;
+ }
+ Debug.WriteLine(item.DeclaringType.Name + "." + item.Name);
+ }
+ }
+ }
+
+ return Context.DataSource.ToArray();
+ }
+
+ public void Deserialize()
+ {
+ Type myType = GetType();
+
+ var prs = myType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).Where(p => p.CustomAttributes.Where(att => att.AttributeType == typeof(SerializableCulumn)).Count() > 0).ToList();
+ prs.OrderBy(p => (int)p.CustomAttributes.Where(att => att.AttributeType == typeof(SerializableCulumn)).FirstOrDefault().NamedArguments.Where(a => a.MemberName.Equals("Index")).FirstOrDefault().TypedValue.Value).ToList();
+
+ foreach (var item in prs)
+ {
+ foreach (CustomAttributeData att in item.CustomAttributes)
+ {
+ if (att.AttributeType == typeof(SerializableCulumn))
+ {
+ var culumnDefi = (SerializableCulumn)Attribute.GetCustomAttributes(item).ToList().Where(attr => attr is SerializableCulumn).FirstOrDefault();
+ //var mappedForSizeDefinition = (MappedForSize)Attribute.GetCustomAttributes(item).ToList().Where(attr => attr is MappedForSize).FirstOrDefault();
+ var mappedForLengthDefinition = (MappedForLength)Attribute.GetCustomAttributes(item).ToList().Where(attr => attr is MappedForLength).FirstOrDefault();
+ var mappedForTypeDefinition = (MappedForType)Attribute.GetCustomAttributes(item).ToList().Where(attr => attr is MappedForType).FirstOrDefault();
+
+ int length = culumnDefi.Length;
+
+ object fieldValue = null;
+ switch (Type.GetTypeCode(item.PropertyType))
+ {
+ case TypeCode.Single:
+ fieldValue = BitConverter.ToSingle(Context.DataSource.GetBytes(Math.Max(4, length)), 0);
+ break;
+
+ case TypeCode.UInt16:
+ fieldValue = BitConverter.ToUInt16(Context.DataSource.GetBytes(Math.Max(2, length)), 0);
+ break;
+
+ case TypeCode.UInt32:
+ fieldValue = BitConverter.ToUInt32(Context.DataSource.GetBytes(Math.Max(4, length)), 0);
+ break;
+
+ case TypeCode.UInt64:
+ fieldValue = BitConverter.ToUInt64(Context.DataSource.GetBytes(Math.Max(8, length)), 0);
+ break;
+
+ case TypeCode.Int16:
+ fieldValue = BitConverter.ToInt16(Context.DataSource.GetBytes(Math.Max(2, length)), 0);
+ break;
+
+ case TypeCode.Int32:
+ fieldValue = BitConverter.ToInt32(Context.DataSource.GetBytes(Math.Max(4, length)), 0);
+ break;
+
+ case TypeCode.Int64:
+ fieldValue = BitConverter.ToInt64(Context.DataSource.GetBytes(Math.Max(8, length)), 0);
+ break;
+
+ case TypeCode.Byte:
+ fieldValue = Context.DataSource.GetByte();
+ break;
+
+ case TypeCode.Char:
+ fieldValue = (char)Context.DataSource.GetByte();
+ break;
+
+ case TypeCode.String:
+ fieldValue = Context.DataSource.GetString(length);
+ break;
+
+ case TypeCode.Object:
+ if (item.PropertyType.IsGenericType && item.PropertyType.Name.StartsWith("List"))
+ {
+ var types = item.PropertyType.GetGenericArguments()[0];
+
+ if (length <= 0)
+ {
+ length = FindLength(item.DeclaringType.Name, item.Name);
+ }
+
+ if (IsSerializableClass(types))
+ {
+ Type d1 = typeof(List<>);
+ Type constructed = d1.MakeGenericType(types);
+ IList o = Activator.CreateInstance(constructed) as IList;
+
+ for (int i = 0; i < length; i++)
+ {
+ var obj = Activator.CreateInstance(types, Context);
+ ((Serializable)obj).Deserialize();
+ o.Add(obj);
+ }
+
+ fieldValue = o;
+ item.SetValue(this, o);
+ }
+ }
+ else if (item.PropertyType == typeof(byte[]))
+ {
+ if (length <= 0)
+ {
+ length = FindLength(item.DeclaringType.Name, item.Name);
+ }
+
+ fieldValue = length <= 0 ? null : Context.DataSource.GetBytes(length);
+ }
+ else if (item.PropertyType == typeof(object))
+ {
+ Type type = (Type)Context.Get(item.DeclaringType.Name + "." + item.Name);
+
+ if (type != null && type.Name.StartsWith("List"))
+ {
+ var types = type.GetGenericArguments()[0];
+
+ if (length <= 0)
+ {
+ length = FindLength(item.DeclaringType.Name, item.Name);
+ }
+
+ if (IsSerializableClass(types))
+ {
+ Type d1 = typeof(List<>);
+ Type constructed = d1.MakeGenericType(types);
+ IList o = Activator.CreateInstance(constructed) as IList;
+
+ for (int i = 0; i < length; i++)
+ {
+ var obj = Activator.CreateInstance(types, Context);
+ ((Serializable)obj).Deserialize();
+ o.Add(obj);
+ }
+
+ fieldValue = o;
+ item.SetValue(this, o);
+ }
+ }
+ else if (type != null && IsSerializableClass(type))
+ {
+ var obj = Activator.CreateInstance(type, Context);
+ ((Serializable)obj).Deserialize();
+ fieldValue = obj;
+ }
+ else if (type == typeof(byte[]))
+ {
+ if (length <= 0)
+ {
+ length = FindLength(item.DeclaringType.Name, item.Name);
+ }
+
+ try
+ {
+ fieldValue = Context.DataSource.GetBytes(length);
+ }
+ catch
+ {
+ Debug.WriteLine(Context.DataSource.Size - Context.DataSource.PositionToRead);
+ }
+ }
+ }
+ else
+ {
+ if (IsSerializableClass(item.PropertyType))
+ {
+ var obj = Activator.CreateInstance(item.PropertyType, Context);
+ ((Serializable)obj).Deserialize();
+ fieldValue = obj;
+ }
+ }
+ break;
+ }
+
+ if (fieldValue != null)
+ {
+ item.SetValue(this, fieldValue);
+ }
+
+ if (!string.IsNullOrEmpty(mappedForLengthDefinition?.Target))
+ {
+ Context.SetDecimal(mappedForLengthDefinition.Target, mappedForLengthDefinition.ValueConverterDelegate != null ? mappedForLengthDefinition.ValueConverterDelegate(fieldValue) : fieldValue, "length");
+ }
+
+ if (!string.IsNullOrEmpty(mappedForTypeDefinition?.Target))
+ {
+ Context.Set(mappedForTypeDefinition.Target, mappedForTypeDefinition.ValueConverterDelegate != null ? mappedForTypeDefinition.ValueConverterDelegate(fieldValue) : fieldValue);
+ }
+
+ Debug.WriteLine(item.DeclaringType.Name + "." + item.Name + " => " + fieldValue);
+ }
+ }
+ }
+ }
+
+ public int FindLength(string type, string property)
+ {
+ return (int)Context.GetToDecimal(type + "." + property, "length");
+ }
+
+ public int FindSize(string type, string property)
+ {
+ return (int)Context.GetToDecimal(type + "." + property, "size");
+ }
+
+ public object GetAnnotationValue(PropertyInfo field, Type type, string property)
+ {
+ return field.CustomAttributes.Where(att => att.AttributeType == type).FirstOrDefault().NamedArguments.Where(a => a.MemberName.Equals(property)).FirstOrDefault().TypedValue.Value;
+ }
+
+ public bool IsSerializableClass(Type type)
+ {
+ return Attribute.GetCustomAttributes(type).ToList().Where(attr => attr is SerializableAttribute).Count() > 0;
+ }
+
+ public PropertyInfo GetFieldUsingProperty(Type type, string propertyName, string propertyValue)
+ {
+ Type myType = GetType();
+ return myType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).Where(p => (string)GetAnnotationValue(p, type, propertyName) == propertyValue).FirstOrDefault();
+ }
+
+ public PropertyInfo GetPropertyInfo(string propertyName)
+ {
+ Type myType = GetType();
+ return myType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).Where(p => p.Name.Equals(propertyName)).FirstOrDefault();
+ }
+ }
+}
diff --git a/ChoiSerializer/ChoiSerializer/SerializationContext.cs b/ChoiSerializer/ChoiSerializer/SerializationContext.cs
new file mode 100644
index 0000000..c83134c
--- /dev/null
+++ b/ChoiSerializer/ChoiSerializer/SerializationContext.cs
@@ -0,0 +1,69 @@
+using ChoiSerializer.Support;
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace ChoiSerializer
+{
+ public class SerializationContext : Dictionary, IDisposable
+ {
+ public ByteBuffer DataSource { get; set; }
+
+ public SerializationContext()
+ {
+ DataSource = new ByteBuffer();
+ }
+
+ public SerializationContext(ByteBuffer dataSource)
+ {
+ DataSource = dataSource;
+ }
+
+ public SerializationContext(string filepath)
+ {
+ DataSource = new ByteBuffer(File.ReadAllBytes(filepath));
+ }
+
+ public SerializationContext(byte[] file)
+ {
+ DataSource = new ByteBuffer(file);
+ }
+
+ public decimal GetToDecimal(string key, string suffix = "")
+ {
+ suffix = !string.IsNullOrEmpty(suffix) ? "_" + suffix : suffix;
+ object value = 0;
+ TryGetValue(key + suffix + "_decimal", out value);
+ return value != null ? (decimal)value : decimal.Zero;
+ }
+
+ public void SetDecimal(string key, object value, string suffix = "")
+ {
+ suffix = !string.IsNullOrEmpty(suffix) ? "_" + suffix : suffix;
+ Remove(key + suffix + "_decimal");
+ Add(key + suffix + "_decimal", Convert.ToDecimal(value));
+ }
+
+ public object Get(string key, string suffix = "")
+ {
+ suffix = !string.IsNullOrEmpty(suffix) ? "_" + suffix : suffix;
+ object value;
+ TryGetValue(key + suffix + "_object", out value);
+ return value;
+ }
+
+ public void Set(string key, object value, string suffix = "")
+ {
+ suffix = !string.IsNullOrEmpty(suffix) ? "_" + suffix : suffix;
+ Remove(key + suffix + "_object");
+ Add(key + suffix + "_object", value);
+ }
+
+ public void Dispose()
+ {
+ DataSource?.Dispose();
+ DataSource = null;
+ GC.SuppressFinalize(this);
+ }
+ }
+}
diff --git a/ChoiSerializer/ChoiSerializer/Support/ByteBuffer.cs b/ChoiSerializer/ChoiSerializer/Support/ByteBuffer.cs
new file mode 100644
index 0000000..d467a1d
--- /dev/null
+++ b/ChoiSerializer/ChoiSerializer/Support/ByteBuffer.cs
@@ -0,0 +1,196 @@
+using System;
+using System.Linq;
+using System.Collections.Generic;
+
+namespace ChoiSerializer.Support
+{
+ public delegate byte[] EscapeDelegate(byte input);
+
+ public class ByteBuffer : List, IDisposable
+ {
+ public void Dispose()
+ {
+ Clear();
+ GC.SuppressFinalize(this);
+ }
+
+ public int PositionToWrite { get; private set; } = 0;
+
+ public int PositionToRead { get; private set; } = 0;
+
+ private EscapeDelegate EscapeDelegate { get; set; }
+
+ public void Rewind()
+ {
+ PositionToWrite = 0;
+ PositionToRead = 0;
+ }
+
+ public int Size
+ {
+ get { return this.Count; }
+ }
+
+ public ByteBuffer(byte[] data = null, EscapeDelegate escape = null )
+ {
+ EscapeDelegate = escape;
+ if (data != null)
+ AddRange(data.ToList());
+ }
+
+ public new void Clear()
+ {
+ PositionToWrite = 0;
+ PositionToRead = 0;
+ base.Clear();
+ }
+
+ public ByteBuffer Put( byte[] inputs )
+ {
+ foreach ( byte b in inputs )
+ {
+ Put( b );
+ }
+
+ return this;
+ }
+
+ public ByteBuffer Put( byte[] inputs, int length )
+ {
+ int alength = inputs.Length < length ? inputs.Length : length;
+
+ byte[] result = new byte[length];
+
+ Array.Clear( result, 0, length );
+ Array.Copy( inputs, 0, result, 0, alength );
+
+ return Put( result );
+ }
+
+ public ByteBuffer Put( byte input, bool escapeIfExist = true )
+ {
+ if (EscapeDelegate != null && escapeIfExist )
+ {
+ byte[] escDatas = EscapeDelegate(input);
+
+ foreach ( byte item in escDatas )
+ {
+ PutByte( item );
+ }
+ }
+ else
+ {
+ PutByte( input );
+ }
+
+ return this;
+ }
+
+ private ByteBuffer PutByte( byte input )
+ {
+ Add(input);
+ PositionToWrite++;
+ return this;
+ }
+
+ public ByteBuffer PutNull( int length )
+ {
+ for ( int i=0;i < length; i++ )
+ {
+ Put( 0x00 );
+ }
+
+ return this;
+ }
+
+ public ByteBuffer PutInt(int input)
+ {
+ return Put( ByteConverter.IntToByte( input ) );
+ }
+
+ public ByteBuffer PutLong( long input )
+ {
+ return Put( ByteConverter.LongToByte( input ) );
+ }
+
+ public ByteBuffer PutShort( short input )
+ {
+ return Put( ByteConverter.ShortToByte( input ) );
+ }
+
+ public ByteBuffer PutUShort(ushort input)
+ {
+ return Put(BitConverter.GetBytes(input));
+ }
+
+ public ByteBuffer PutUInt(uint input)
+ {
+ return Put(BitConverter.GetBytes(input));
+ }
+
+ public ByteBuffer PutULong(ulong input)
+ {
+ return Put(BitConverter.GetBytes(input));
+ }
+
+ public ByteBuffer PutSingle(Single input)
+ {
+ return Put(BitConverter.GetBytes(input));
+ }
+
+ #region get
+
+ public int GetInt()
+ {
+ return BitConverter.ToInt32( GetBytes( 4 ), 0 );
+ }
+
+ public short GetShort()
+ {
+ return BitConverter.ToInt16( GetBytes( 2 ), 0 );
+ }
+
+ public ushort GetUShort()
+ {
+ return BitConverter.ToUInt16(GetBytes(2), 0);
+ }
+
+ public long GetLong()
+ {
+ return BitConverter.ToInt64( GetBytes( 8 ), 0 );
+ }
+
+ public byte[] GetBytes()
+ {
+ return GetBytes( PositionToWrite - PositionToRead );
+ }
+
+ public byte[] GetBytes(int size)
+ {
+ PositionToRead += size;
+ return this.Skip(PositionToRead - size).Take(size).ToArray();
+ }
+
+ public byte GetByte()
+ {
+ return GetBytes(1)[0];
+ }
+
+ public int GetByteToInt()
+ {
+ return (int)( GetByte() & 0xFF );
+ }
+
+ public string GetString( int length )
+ {
+ return System.Text.Encoding.UTF8.GetString( GetBytes( length ) ).Trim('\0');
+ }
+
+ public byte GetChecksum(int length)
+ {
+ return (byte)this.Skip(PositionToRead).Take(length).Aggregate(0, (checkSum, item) => { checkSum += (int)(item & 0xFF); return checkSum; });
+ }
+
+ #endregion
+ }
+}
diff --git a/ChoiSerializer/ChoiSerializer/Support/ByteConverter.cs b/ChoiSerializer/ChoiSerializer/Support/ByteConverter.cs
new file mode 100644
index 0000000..30a5ca6
--- /dev/null
+++ b/ChoiSerializer/ChoiSerializer/Support/ByteConverter.cs
@@ -0,0 +1,54 @@
+using System;
+
+namespace ChoiSerializer.Support
+{
+ ///
+ /// 바이트와 short, int, long 간 변환
+ ///
+ public class ByteConverter
+ {
+ public static long ByteToLong(byte[] data)
+ {
+ //long result = data[0] + ( data[1] << 8 ) + ( data[2] << 16 ) + ( data[3] << 24 )
+ //+ ( data[4] << 32 ) + ( data[5] << 40 ) + ( data[6] << 48 ) + ( data[7] << 56 );
+ //return result;
+
+ return BitConverter.ToInt64( data, 0 );
+ }
+
+ public static int ByteToInt(byte[] data)
+ {
+ int result = data[0] + ( data[1] << 8 ) + ( data[2] << 16 ) + ( data[3] << 24 );
+ return result;
+ }
+
+ public static int SingleByteToInt(byte data)
+ {
+ return (int)( data & 0xFF );
+ }
+
+ public static short ByteToShort(byte[] data)
+ {
+ int result = data[0] + ( data[1] << 8 );
+ return (short)result;
+ }
+
+ public static byte[] ShortToByte(short value)
+ {
+ byte[] b = BitConverter.GetBytes( value );
+ return b;
+ }
+
+ public static byte[] LongToByte( long value )
+ {
+ byte[] b = BitConverter.GetBytes( value );
+ return b;
+ }
+
+ public static byte[] IntToByte( int value )
+ {
+ byte[] b = BitConverter.GetBytes( value );
+ return b;
+ }
+ }
+}
diff --git a/ChoiSerializer/Example/ContentContainer.cs b/ChoiSerializer/Example/ContentContainer.cs
new file mode 100644
index 0000000..1b5c8f2
--- /dev/null
+++ b/ChoiSerializer/Example/ContentContainer.cs
@@ -0,0 +1,56 @@
+using ChoiSerializer;
+using ChoiSerializer.Annotation;
+using System;
+using System.Collections.Generic;
+
+namespace Example
+{
+ [Serializable]
+ public class ContentContainer : Serializable
+ {
+ public ContentContainer(SerializationContext context) : base(context)
+ {
+ }
+
+ [SerializableCulumn(Index = 0, Length = 2)]
+ public string ParcelStart { get; set; } = "PS";
+
+ [MappedForLength(Target = "ContentContainer.Attribute")]
+ [SerializableCulumn(Index = 1)]
+ public int AttributeSize { get; set; } = 16;
+
+ [SerializableCulumn(Index = 2)]
+ public byte[] Attribute { get; set; }
+
+ [SerializableCulumn(Index = 3)]
+ public short SerialNumber { get; set; } = 0;
+
+ [MappedForType(Target = "ContentContainer.Data", ValueConverter = "ContentContainer.GetDataTypeFromChunkName")]
+ [SerializableCulumn(Index = 4, Length = 10)]
+ public string ChunkName { get; set; }
+
+ public static Type GetDataTypeFromChunkName(object name)
+ {
+ switch ((string)name)
+ {
+ case "IMAGE":
+ return typeof(List);
+ case "SOUND":
+ return typeof(List);
+ case "DATA":
+ return typeof(byte[]);
+ }
+ return null;
+ }
+
+ [MappedForLength(Target = "ContentContainer.Data")]
+ [SerializableCulumn(Index = 5)]
+ public int DataCount { get; set; }
+
+ [SerializableCulumn(Index = 6)]
+ public object Data { get; set; }
+
+ [SerializableCulumn(Index = 7, Length = 2)]
+ public string ParcelTail { get; set; } = "PE";
+ }
+}
diff --git a/ChoiSerializer/Example/Example.csproj b/ChoiSerializer/Example/Example.csproj
new file mode 100644
index 0000000..7bb8d5c
--- /dev/null
+++ b/ChoiSerializer/Example/Example.csproj
@@ -0,0 +1,12 @@
+
+
+
+ Exe
+ netcoreapp2.1
+
+
+
+
+
+
+
diff --git a/ChoiSerializer/Example/ImageContent.cs b/ChoiSerializer/Example/ImageContent.cs
new file mode 100644
index 0000000..81c7fec
--- /dev/null
+++ b/ChoiSerializer/Example/ImageContent.cs
@@ -0,0 +1,33 @@
+using ChoiSerializer;
+using ChoiSerializer.Annotation;
+using System;
+
+namespace Example
+{
+ [Serializable]
+ public class ImageContent : Serializable
+ {
+ public ImageContent(SerializationContext context) : base(context)
+ {
+ }
+
+ [SerializableCulumn(Index = 0, Length = 2)]
+ public string ContentStart { get; set; } = "CS";
+
+ [SerializableCulumn(Index = 1, Length = 100)]
+ public string Name { get; set; }
+
+ [MappedForLength(Target = "ImageContent.Data")]
+ [SerializableCulumn(Index = 2)]
+ public int DataSize { get; set; }
+
+ [SerializableCulumn(Index = 3)]
+ public byte[] Data { get; set; }
+
+ [SerializableCulumn(Index = 4)]
+ public short Checksum { get; set; } = 0;
+
+ [SerializableCulumn(Index = 5, Length = 2)]
+ public string ContentTail { get; set; } = "CE";
+ }
+}
diff --git a/ChoiSerializer/Example/Program.cs b/ChoiSerializer/Example/Program.cs
new file mode 100644
index 0000000..e726471
--- /dev/null
+++ b/ChoiSerializer/Example/Program.cs
@@ -0,0 +1,50 @@
+using ChoiSerializer;
+using System;
+using System.Linq;
+using System.IO;
+using System.Collections.Generic;
+
+namespace Example
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ string workingDir = Directory.GetCurrentDirectory() + @"\..\..\..";
+ string imageContentFile = workingDir + @"\image_content.data";
+
+ Console.WriteLine("Hello World! Working with Choi's Serializer");
+
+ // Example of reading an image file and serializing it into a single binary file
+ var images = Directory.EnumerateFiles(workingDir + @"\images");
+ using (var context = new SerializationContext())
+ {
+ var container = new ContentContainer(context);
+ container.ChunkName = "IMAGE";
+ container.DataCount = images.Count();
+ var imageContents = new List();
+ foreach (var image in images)
+ {
+ var imageBytes = File.ReadAllBytes(image);
+ var imageContent = new ImageContent(context);
+ imageContent.Name = Path.GetFileName(image);
+ imageContent.DataSize = imageBytes.Length;
+ imageContent.Data = imageBytes;
+ imageContents.Add(imageContent);
+ }
+ container.Data = imageContents;
+ container.AttributeSize = 16;
+ container.Attribute = new byte[16];
+ container.SerialNumber = 123;
+ File.WriteAllBytes(imageContentFile, container.Serialize());
+ }
+
+ // Example of deserializing an binary file
+ using (var context = new SerializationContext(imageContentFile))
+ {
+ var container = new ContentContainer(context);
+ container.Deserialize();
+ }
+ }
+ }
+}
diff --git a/ChoiSerializer/Example/SoundContent.cs b/ChoiSerializer/Example/SoundContent.cs
new file mode 100644
index 0000000..7ed316b
--- /dev/null
+++ b/ChoiSerializer/Example/SoundContent.cs
@@ -0,0 +1,36 @@
+using ChoiSerializer;
+using ChoiSerializer.Annotation;
+using System;
+
+namespace Example
+{
+ [Serializable]
+ public class SoundContent : Serializable
+ {
+ public SoundContent(SerializationContext context) : base(context)
+ {
+ }
+
+ [SerializableCulumn(Index = 0, Length = 2)]
+ public string ContentStart { get; set; } = "SS";
+
+ [SerializableCulumn(Index = 1, Length = 20)]
+ public string Name { get; set; }
+
+ [SerializableCulumn(Index = 2)]
+ public long PlayingTime { get; set; } = 0;
+
+ [MappedForLength(Target = "SoundContent.Data")]
+ [SerializableCulumn(Index = 3)]
+ public int DataSize { get; set; }
+
+ [SerializableCulumn(Index = 4)]
+ public byte[] Data { get; set; }
+
+ [SerializableCulumn(Index = 5)]
+ public short Checksum { get; set; } = 0;
+
+ [SerializableCulumn(Index = 6, Length = 2)]
+ public string ContentTail { get; set; } = "SE";
+ }
+}
diff --git a/ChoiSerializer/Example/images/16ca1bb440db4f209016c36e0ac6c08b_20191203122431.jpg b/ChoiSerializer/Example/images/16ca1bb440db4f209016c36e0ac6c08b_20191203122431.jpg
new file mode 100644
index 0000000..46278d4
Binary files /dev/null and b/ChoiSerializer/Example/images/16ca1bb440db4f209016c36e0ac6c08b_20191203122431.jpg differ
diff --git a/ChoiSerializer/Example/images/202048_43227_IRtAeJBGi.jpeg b/ChoiSerializer/Example/images/202048_43227_IRtAeJBGi.jpeg
new file mode 100644
index 0000000..6151622
Binary files /dev/null and b/ChoiSerializer/Example/images/202048_43227_IRtAeJBGi.jpeg differ
diff --git a/ChoiSerializer/Example/images/202048_43227_YKjUZBQtt.jpeg b/ChoiSerializer/Example/images/202048_43227_YKjUZBQtt.jpeg
new file mode 100644
index 0000000..3a9d996
Binary files /dev/null and b/ChoiSerializer/Example/images/202048_43227_YKjUZBQtt.jpeg differ
diff --git a/ChoiSerializer/Example/images/202048_6236_iJtRGzbyw.jpeg b/ChoiSerializer/Example/images/202048_6236_iJtRGzbyw.jpeg
new file mode 100644
index 0000000..1d8472a
Binary files /dev/null and b/ChoiSerializer/Example/images/202048_6236_iJtRGzbyw.jpeg differ