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