public void Long() { var real_bytes = BitConverter.GetBytes(long.MaxValue); Assert.AreEqual(long.MaxValue, PointerCastHelper.BytesToLong(real_bytes, 0), "No se convirtió el puntero correctamente"); Assert.AreEqual(BitConverter.ToInt64(PointerCastHelper.LongToBytes(long.MaxValue), 0), long.MaxValue, "No se reconvirtieron los bytes correctamente"); }
/// <summary> /// Devuelve el objeto serializado sin incluir la cabecera con el tamaño y el estado de borrado. /// </summary> /// <typeparam name="TModel"></typeparam> /// <param name="graph"></param> /// <returns></returns> public static byte[] Serialize <TModel>(TModel graph) { if (!typeof(TModel).IsInterface) { throw new InvalidOperationException("El modelo <TModel> debe ser una interfaz"); } MemoryStream result = new MemoryStream(); var props = GetPropertiesOrderForInterface(typeof(TModel)); //Obtenemos las propiedades en el orden de serialización y las serializamos en result foreach (var prop in props) { string method = PointerCastHelper.GetTypeToByteMethod(prop.PropertyType); byte[] value = (byte[])typeof(PointerCastHelper) .GetMethod(method, new Type[] { prop.PropertyType }) .Invoke(null, new object[] { prop.GetValue(graph) }); result.Write(value, 0, value.Length); } return(result.ToArray()); }
public void GetStringOffsetAtIndex() { //cargamos 3 strings en un array MemoryStream ms = new MemoryStream(); byte[] bytes = PointerCastHelper.StringToBytes("texto 1"); ms.Write(bytes, 0, bytes.Length); bytes = PointerCastHelper.StringToBytes("texto 2"); ms.Write(bytes, 0, bytes.Length); bytes = PointerCastHelper.StringToBytes("texto 3"); ms.Write(bytes, 0, bytes.Length); byte[] data = ms.ToArray(); long offset2 = PointerCastHelper.GetStringOffsetAtIndex(data, 0, 1); long offset3 = PointerCastHelper.GetStringOffsetAtIndex(data, 0, 2); Assert.AreEqual(15, offset2, "El offset del segundo string debería ser 16"); Assert.AreEqual("texto 1", PointerCastHelper.BytesToString(data, 0), "No coinciden los textos"); Assert.AreEqual("texto 2", PointerCastHelper.BytesToString(data, offset2), "No coinciden los textos"); Assert.AreEqual("texto 3", PointerCastHelper.BytesToString(data, offset3), "No coinciden los textos"); }
public void String() { string test = "String de prueba para el test"; string result = PointerCastHelper.BytesToString( PointerCastHelper.StringToBytes(test), 0); Assert.AreEqual(test, result, "Los textos no coinciden"); }
public static void DeSerializeHeader(byte[] data, long offset, out int length, out bool deleted) { /*Header: * byte[4] longitud <- delante para mantener el alineamiento de la memoria. * byte flags: * 0x01 = Borrado */ length = PointerCastHelper.BytesToInt(data, offset); deleted = (data[offset + 4] & 0x01) == 0x01; }
public void Short() { var real_bytes = BitConverter.GetBytes(short.MaxValue); Assert.AreEqual(short.MaxValue, PointerCastHelper.BytesToShort(real_bytes, 0), "No se convirtió el puntero correctamente"); for (int n = 0; n < 2; n++) { Assert.AreEqual(real_bytes[n], PointerCastHelper.ShortToBytes(short.MaxValue)[n], "No se hizo la conversión correctamente"); } }
public void Double() { var real_bytes = BitConverter.GetBytes(12345678.23); Assert.AreEqual(12345678.23, PointerCastHelper.BytesToDouble(real_bytes, 0), "No se convirtió el puntero correctamente"); for (int n = 0; n < 8; n++) { Assert.AreEqual(real_bytes[n], PointerCastHelper.DoubleToBytes(12345678.23)[n], "No se hizo la conversión correctamente"); } }
public void Int() { var real_bytes = BitConverter.GetBytes(12345678); Assert.AreEqual(12345678, PointerCastHelper.BytesToInt(real_bytes, 0), "No se convirtió el puntero correctamente"); Assert.AreEqual(real_bytes[0], PointerCastHelper.IntToBytes(12345678)[0], "No se convirtió a un array de bytes correctamente"); Assert.AreEqual(real_bytes[1], PointerCastHelper.IntToBytes(12345678)[1], "No se convirtió a un array de bytes correctamente"); Assert.AreEqual(real_bytes[2], PointerCastHelper.IntToBytes(12345678)[2], "No se convirtió a un array de bytes correctamente"); Assert.AreEqual(real_bytes[3], PointerCastHelper.IntToBytes(12345678)[3], "No se convirtió a un array de bytes correctamente"); }
public bool MoveNext() { if (data.Length == 0) { return(false); } if (current_offset == -1) { current_offset = 0; //todo: optimize! importante que esto sea óptimo dado que es el iterador principal //movemos el cursor hacia adelante el largo del registro. bool deleted; int length; SerializationHelper .DeSerializeHeader(data, current_offset, out length, out deleted); if (deleted) { return(MoveNext()); } if (data.Length > 0) { return(true); } } else { //todo: optimize! importante que esto sea óptimo dado que es el iterador principal int length = PointerCastHelper.BytesToInt(data, current_offset); //movemos el cursor hacia adelante el largo del registro. current_offset += length + Constants.RECORD_HEADER_SIZE; if (current_offset >= data.Length) { return(false); } bool deleted = (data[current_offset + 5] & 0x01) == 0x01; if (deleted) { return(MoveNext()); } if (data.Length > current_offset)//??? { return(true); } } return(false); }
public static byte[] SerializeHeader(int record_length, bool deleted = false) { byte[] header = new byte[5]; PointerCastHelper.IntToBytes(record_length).CopyTo(header, 0); if (deleted) { header[4] = 0x01; } return(header); }
public static IEnumerable <System.Reflection.PropertyInfo> GetPropertiesOrderForInterface(Type TModel) { if (!TModel.IsInterface) { throw new InvalidOperationException("El modelo <TModel> debe ser una interfaz"); } //obtenemos las propiedades del tipo de interfaz del modelo var properties = TModel .GetProperties() .OrderByDescending(x => PointerCastHelper.TypeSizeInMemory(x.PropertyType));//así quedan las de tamaño variable al final. return(properties); }
public void Serialize() { var model = new testmodel() { value = 1, value3 = 2D, text1 = "texto 1", text2 = "otro texto de prueba" }; byte[] serialization = SerializationHelper.Serialize <ITestModel>(model); //según la ordenación, lo primero debería ser el campo más grande, el double, después el entero y los strings. Assert.AreEqual(1, PointerCastHelper.BytesToInt(serialization, 8)); Assert.AreEqual(2D, PointerCastHelper.BytesToDouble(serialization, 0)); Assert.AreEqual("texto 1", PointerCastHelper.GetStringAtOffset(serialization, 12, 0)); Assert.AreEqual("otro texto de prueba", PointerCastHelper.GetStringAtOffset(serialization, 12, 1)); }
private static Type BuildWrapperType(Type interface_type) { //si anteriormente se había creado un tipo para esta interfaz lo devolvemos. if (generated_types_cache.ContainsKey(interface_type)) { return(generated_types_cache[interface_type]); } string type_name = interface_type.FullName.Replace('.', '_') + Constants.WRAPPER_TYPE_NAME_SUFIX; //definimos la nueva classe wrapper. TypeBuilder type_builder = module_builder.DefineType(type_name, TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.AutoClass | TypeAttributes.AnsiClass, null, Type.EmptyTypes); //Añadimos la implementación de la interfaz del modelo. type_builder.AddInterfaceImplementation(interface_type); //creamos una variable estática en cla clase que contendrá //un puntero al array de bytes del origen de datos. FieldBuilder data_field = type_builder .DefineField("data", typeof(Byte[]), FieldAttributes.Public | FieldAttributes.Static); //creamos otra variable para almacenar el offset del registro actual FieldBuilder offset_field = type_builder .DefineField("offset", typeof(long), FieldAttributes.Public); //obtenemos las propiedades del tipo de interfaz del modelo var properties = SerializationHelper.GetPropertiesOrderForInterface(interface_type); //offset de la propiedad dentro del conjunto de bytes del registro. int prop_offset = 0; int first_string_offset = -1; int string_index = 0; //implementamos las propiedades foreach (var prop in properties) { //método de transformación del array de bytes al tipo de la propiedad. string cast_method_name = PointerCastHelper.GetByteToTypeMethod(prop.PropertyType); PropertyBuilder prop_builder = type_builder .DefineProperty(prop.Name, PropertyAttributes.HasDefault, prop.PropertyType, Type.EmptyTypes); //definimos el método get MethodBuilder pGet = type_builder.DefineMethod("get_" + prop.Name, MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, prop.PropertyType, Type.EmptyTypes); var getIl = pGet.GetILGenerator(); //emitimos el código que convierte el array de bytes encontrado en el //offset de la variable del modelo a un puntero del tipo de retorno. if (prop.PropertyType == typeof(string)) { if (first_string_offset == -1) { first_string_offset = prop_offset; } //llamámos al método que nos dá el offset de este índice de string. GetStringOffsetAtIndex getIl.Emit(OpCodes.Ldsfld, data_field); getIl.Emit(OpCodes.Ldarg_0); //sumamos el offset del primer campo con el del registro getIl.Emit(OpCodes.Ldfld, offset_field); getIl.Emit(OpCodes.Ldc_I4, prop_offset); getIl.Emit(OpCodes.Conv_I8); getIl.Emit(OpCodes.Add); //añadimos el indice del string que estamos cargando. getIl.Emit(OpCodes.Ldc_I4, string_index++); //obtenemos el offset del string. getIl.Emit(OpCodes.Call, typeof(PointerCastHelper).GetMethod("GetStringAtOffset")); getIl.Emit(OpCodes.Ret); } else { getIl.Emit(OpCodes.Nop); getIl.Emit(OpCodes.Ldsfld, data_field); getIl.Emit(OpCodes.Ldarg_0); getIl.Emit(OpCodes.Ldfld, offset_field); getIl.Emit(OpCodes.Ldc_I4, prop_offset); getIl.Emit(OpCodes.Conv_I8); getIl.Emit(OpCodes.Add); getIl.Emit(OpCodes.Call, typeof(PointerCastHelper).GetMethod(PointerCastHelper.GetByteToTypeMethod(prop.PropertyType))); getIl.Emit(OpCodes.Ret); prop_offset += PointerCastHelper.TypeSizeInMemory(prop.PropertyType); } prop_builder.SetGetMethod(pGet); type_builder.DefineMethodOverride(pGet, interface_type.GetMethod("get_" + prop.Name)); } //Añadimos el nuevo tipo a la caché de creación. Type created = type_builder.CreateType(); generated_types_cache.Add(interface_type, created); return(created); }