/// <summary> /// Deserializes a string into a boolean. /// </summary> /// <param name="str">The string to deserialize.</param> /// <param name="settings">The settings for how to handle certain parts.</param> /// <param name="location">OPTIONAL: Used to put a location on errors.</param> /// <returns>The deserialized boolean.</returns> public static bool DeserializeBool(string str, ABSaveSettings settings, int location = 0) { // Get a lower case version of the string for easier comparison. var lower = str.ToLower(); // If it's "F", return false. if (lower == "f") { return(false); } // If it's "T", return true. else if (lower == "t") { return(true); } // Otherwise, there's a problem. else { settings.ErrorHandler.InvalidValueInABSaveWhenParsing(location, "The boolean given: " + str + " is not valid."); } // If we got here, it failed and so the value doesn't matter. return(false); }
static bool AttemptToCreateIdentifiedType(Type typ, ABSaveSettings settings, bool useSB, StringBuilder sb, ref string identifiedType) { // Create the new string. var str = SerializeType(typ, useSB, sb); // If the number "settings.HighestIdentifiedType" is too high, we can't do it anymore in the future. if (settings.HighestIdentifiedType + 1 == short.MaxValue) { return(settings.CurrentlyCanIdentifyTypes = false); } // Now, add it as an item, so that this type can be identified easier in the future. settings.RememberedTypes.Add(new Helpers.ABSaveIdentifiedType(settings.HighestIdentifiedType++, str, typ)); // We'll now write out the key for this type, as well as the actual type. if (useSB) { sb.Append(settings.RememberedTypes[settings.HighestIdentifiedType - 1].WrittenKey); } else { identifiedType = str + new string(settings.RememberedTypes[settings.HighestIdentifiedType - 1].WrittenKey); } return(true); }
static bool AttemptToUseRememberedType(Type typ, ABSaveSettings settings, bool useSB, StringBuilder sb, out string identifiedType) { identifiedType = ""; // If we can't remember types, then this won't work. if (!settings.RememberTypes) { return(false); } // Check for an already identifed type. var key = settings.SearchForIdentifiedType(typ); // If we can't find one, we'll attempt to create one, and if we can't even create one, then just write it. if (key == null && settings.CurrentlyCanIdentifyTypes) { return(AttemptToCreateIdentifiedType(typ, settings, useSB, sb, ref identifiedType)); } else if (useSB) { sb.Append(key); } else { identifiedType = new string(key); } // Since we've got here without stopped, we were successful. return(true); }
public void Setup() { Settings = ABSaveSettings.ForSize; CurrentMap = new ABSaveMap(Settings); CurrentGenerator = new MapGenerator(); CurrentGenerator.Initialize(CurrentMap); }
public static void WriteHeader(ABSaveType type, StringBuilder sb, ABSaveSettings settings, bool writeHeader) { // If we shouldn't write the header, then don't do it. if (!writeHeader) { return; } // Insert the type ("U" for unnamed and "N" for named and types, "V" for unnamed without types, "M" for named without types) if (settings.WithTypes) { sb.Append(type == ABSaveType.NoNames ? 'U' : 'N'); } else { sb.Append(type == ABSaveType.NoNames ? 'V' : 'M'); } // Insert version number - if needed. if (settings.HasVersion) { sb.Append(settings.Version); } // End the header off. sb.Append('\u0001'); }
public static ABSaveMap GetNonGeneric(Type type, ABSaveSettings settings) { var map = new ABSaveMap(settings); MapGenerator?generator = map.GetGenerator(); map._rootItem = generator.GetMap(type); ReleaseGenerator(generator); return(map); }
internal static void SerializeArrayItem(ABSaveType type, ABSaveSettings settings, bool useSB, StringBuilder sb, bool dnWriteEndLevel, ref string ret, ref bool notFirst, ref ABSavePrimitiveType lastType, dynamic item) { // Serialize the item and write to either the StringBuilder or the "ret"... ret += Serialize(item, type, settings, out lastType, useSB, sb, RequiresLowerInnerLevelSymbol(lastType) ? false : notFirst, dnWriteEndLevel); // Update the "notFirst" variable. if (!notFirst) { notFirst = true; } }
/// <summary> /// Deserializes a string into a number (int, long, double etc.) /// </summary> /// <param name="str">The string to deserialize.</param> /// <param name="settings">The settings for how to handle certain parts.</param> /// <param name="location">OPTIONAL: Used to put a location on errors.</param> /// <param name="targetType">Used to specify what target number type you want (int, long, double etc.)</param> /// <returns>The deserialized value.</returns> public static object DeserializeNumber(string str, Type targetType, ABSaveSettings settings, int location = 0) { // Attempt to parse it. var passed = decimal.TryParse(str, out decimal result); // If it fails to parse, the value isn't valid, so that will throw an error. if (!passed) { settings.ErrorHandler.InvalidValueInABSaveWhenParsing(location, "The number given: " + str + " is not valid for the type: " + targetType.Name); return(null); } // Otherwise, go ahead and return it! return(Convert.ChangeType(result, targetType)); }
public void Initialize(ABSaveSettings template, Dictionary <Type, uint> targetVersions = null, bool lazyWriteCompressed = false) { var settings = template.Customize(b => b .SetLazyWriteCompressed(lazyWriteCompressed) .AddConverter <BaseTypeConverter>() .AddConverter <SubTypeConverter>() .AddConverter <OtherTypeConverter>() ); CurrentMap = ABSaveMap.Get <EmptyClass>(settings); Stream = new MemoryStream(); Serializer = CurrentMap.GetSerializer(Stream, targetVersions); Deserializer = CurrentMap.GetDeserializer(Stream); }
/// <summary> /// Serializes a dictionary. /// </summary> /// <param name="obj">The dictionary to serialize.</param> /// <param name="useSB">Whether this will write to a string builder (if true), or return a string (if false).</param> /// <param name="sb">The StringBuilder to write to - if <paramref name="useSB"/> is true.</param> /// <param name="dnWriteEndLevel">"Do Not Write End Level Symbol" - Marks whether to NOT write \u0005 (if true), commonly used for the last object of all.</param> /// <returns>If <paramref name="useSB"/> is false, this method will return the result as a string.</returns> public static string SerializeDictionary(dynamic obj, ABSaveType type, ABSaveSettings settings, bool useSB = false, StringBuilder sb = null, bool dnWriteEndLevel = false) { // Create a variable to store what we'll return. var ret = ""; // Keep track of whether we're on the first item or not. var notFirst = false; // Write the opening for the array. ret += ABSaveWriter.WriteDictionaryOpening(useSB, sb); // Now, go through each item in the dictionary. foreach (var element in obj) { // If this isn't the first item, write the "next item" character. if (notFirst) { ret += ABSaveWriter.WriteNextItem(true, useSB, sb); } // Add the key to it. if (useSB) { sb.Append(element.Key); } else { ret += element.Key; } // Serialize the item and write to either the StringBuilder or the "ret" ret += Serialize(element.Value, type, settings, useSB, sb, true, dnWriteEndLevel); // Update the "notFirst" variable if needed. if (!notFirst) { notFirst = true; } } // Write the closing for the dictionary. ret += ABSaveWriter.WriteObjectClose(dnWriteEndLevel, useSB, sb); // Now, "ret" would be empty if we were using a StringBuilder, however, if we weren't... It will have the correct string in it so return it. return(ret); }
/// <summary> /// Writes the type data that goes before an object or array. /// Which usually includes a key. /// </summary> /// <param name="typ">The type to write as a string.</param> /// <param name="useSB">Whether we are writing to a StringBuilder or not.</param> /// <param name="sb">The StringBuilder to write to - if we're writing to one at all.</param> /// <param name="settings">The settings for how to handle certain parts.</param> /// <returns>Returns the type as a string.</returns> public static string SerializeTypeBeforeObject(Type typ, ABSaveSettings settings, bool useSB = false, StringBuilder sb = null) { // Don't do anything if we're not meant to. if (!settings.WithTypes) { return(""); } // Attempt use a remembered type (or create one) - and return with that. var attempt = AttemptToUseRememberedType(typ, settings, useSB, sb, out string res); // If that attempt was successful, then we'll use that. if (attempt) { return(res); } // If we weren't able to use an identified type, then we'll just have to write the type, not bothering with any of the identified type.. return(SerializeType(typ, useSB, sb)); }
/// <summary> /// Creates a new ABSaveParser with all the correct configuration. /// </summary> /// <param name="objType">The type of the object to parse.</param> /// <param name="type">The way to handle the ABSave string.</param> /// <param name="settings">The settings for it.</param> public ABSaveParser(ABSaveType type, ABSaveSettings settings) { // Set all the tokens for the ABSave. Tokens = new System.Collections.ObjectModel.ObservableCollection <ABParserToken>() { new ABParserToken(nameof(ABSaveTokens.NextItem), '\u0001'), new ABParserToken(nameof(ABSaveTokens.Null), '\u0002'), new ABParserToken(nameof(ABSaveTokens.StartObject), '\u0003'), new ABParserToken(nameof(ABSaveTokens.StartArray), '\u0004'), new ABParserToken(nameof(ABSaveTokens.ExitObject), '\u0005'), new ABParserToken(nameof(ABSaveTokens.StartDictionary), '\u0006'), }; // Set the correct settings. Settings = settings; Settings.ErrorHandler.ErrorEncountered += (e) => IsProcessing = false; // Set the type for now. ABSaveType = type; }
/// <summary> /// Figures out what a string is and how to deserialize it. This does not deserialize objects, arrays or dictionaries, however. /// </summary> /// <param name="str">The string to deserialize.</param> /// <param name="objType">The type of the object to deserialize to.</param> /// <param name="settings">The settings for how to handle certain parts.</param> /// <param name="location">OPTIONAL: This is used to add a location to the error from the <paramref name="settings"/></param> /// <returns>The deserialized object - can be null if it needs to be manually parsed.</returns> public static object Deserialize(string str, Type objType, ABSaveSettings settings, int location = 0) { return(Deserialize(str, objType, settings, out ABSavePrimitiveType none, out bool none2, location)); }
public static ABSaveMap Get <T>(ABSaveSettings settings) => GetNonGeneric(typeof(T), settings);
// Internal for use with unit tests. internal ABSaveMap(ABSaveSettings settings) { Settings = settings; _allTypes = new Dictionary <Type, Converter?>(); }
/// <summary> /// Deserializes a string into a number (int, long, double etc.) /// </summary> /// <param name="str">The string to deserialize.</param> /// <param name="settings">The settings for how to handle certain parts.</param> /// <param name="location">OPTIONAL: Used to put a location on errors.</param> /// <typeparam name="T">Used to specify what target number type you want (int, long, double etc.)</param> /// <returns>The deserialized value.</returns> public static T DeserializeNumber <T>(string str, ABSaveSettings settings, int location = 0) { return((T)DeserializeNumber(str, typeof(T), settings, location)); }
public void SetupSettings() { Settings = ABSaveSettings.ForSpeed; }
internal CheckTypeInfo(Type type, ABSaveSettings settings) { Type = type; Settings = settings; }
/// <summary> /// Deserializes a string into a DateTime - the string must be in ticks. /// </summary> /// <param name="str">The string to deserialize.</param> /// <param name="settings">The settings for how to handle certain parts.</param> /// <param name="location">OPTIONAL: Used to put a location on errors.</param> /// <returns>The deserialized DateTime.</returns> public static DateTime DeserializeDateTime(string str, ABSaveSettings settings, int location = 0) { // Just return a new DateTime, but with the number deserialized. return(new DateTime(DeserializeNumber <long>(str, settings, location))); }
/// <summary> /// Serializes an object. The object could be anything. /// </summary> /// <param name="obj">The object to serialize</param> /// <param name="useSB">Whether this will write to a string builder (if true), or return a string (if false).</param> /// <param name="sb">The StringBuilder to write to - if <paramref name="useSB"/> is true.</param> /// <param name="writeNextInstructionSymbol">Whether it will write \u0001 on the start - usually false if it is serializing the first object in a class.</param> /// <param name="dnWriteEndLevel">"Do Not Write End Level Symbol" - Marks whether to NOT write \u0005 (if true), commonly used for the last object of all.</param> /// <param name="settings">The settings for how to handle certain parts.</param> /// <returns>If <paramref name="useSB"/> is false, this method will return the result as a string.</returns> public static string Serialize(dynamic obj, ABSaveType type, ABSaveSettings settings, bool useSB = false, StringBuilder sb = null, bool writeNextInstructionSymbol = true, bool dnWriteEndLevel = false) { return(Serialize(obj, type, settings, out ABSavePrimitiveType _, useSB, sb, writeNextInstructionSymbol, dnWriteEndLevel)); }
/// <summary> /// Figures out what a string is and how to deserialize it. This does not deserialize objects, arrays or dictionaries, however. /// </summary> /// <param name="str">The string to deserialize.</param> /// <param name="objType">The type of the object to deserialize to.</param> /// <param name="determinedType">The primitive that the object has been determined as.</param> /// <param name="manuallyParse">Whether a parser using this should manually parse the object or not.</param> /// <param name="settings">The settings for how to handle certain parts.</param> /// <param name="location">OPTIONAL: This is used to add a location to the error from the <paramref name="settings"/></param> /// <returns>The deserialized object - can be null if it needs to be manually parsed.</returns> public static object Deserialize(string str, Type objType, ABSaveSettings settings, out ABSavePrimitiveType determinedType, out bool manuallyParse, int location = 0) { // Set the "determinedType" to Unknown for now, and, manuallyParse to false. determinedType = ABSavePrimitiveType.Unknown; manuallyParse = false; // Get a type code. var tCode = Type.GetTypeCode(objType); // Now, go through what it could be and convert it. if (objType == typeof(string)) { determinedType = ABSavePrimitiveType.String; return(str); } // Check if it's a number. else if (ABSaveUtils.IsNumericType(tCode)) { determinedType = ABSavePrimitiveType.Number; return(DeserializeNumber(str, objType, settings, location)); } // Check if it's an array - if so, all we can do is set the "determinedType" to "array" since this method doesn't deal with that. else if (ABSaveUtils.IsArray(objType)) { manuallyParse = true; determinedType = ABSavePrimitiveType.Array; } // Check if it's a dictionary - if so, all we can do is set the "determinedType" to "dictionary" since this method doesn't deal with that. else if (ABSaveUtils.IsDictionary(objType)) { manuallyParse = true; determinedType = ABSavePrimitiveType.Dictionary; } // Check if it's a boolean - if so, we can get the result out of that using "DeserializeBool" else if (objType == typeof(bool)) { determinedType = ABSavePrimitiveType.Boolean; return(DeserializeBool(str, settings, location)); } // Check if it's a DateTime - if so, we can get the result out of that using "DeserializeDateTime" else if (objType == typeof(DateTime)) { determinedType = ABSavePrimitiveType.DateTime; return(DeserializeDateTime(str, settings, location)); } // Check if it's a Type - if so, we can get the result using "Type.GetType()" else if (objType == typeof(Type)) { determinedType = ABSavePrimitiveType.Type; return(Type.GetType(str)); } // If it wasn't any of the above - it's probably an object, now, we've been given a string which is actually the type name of it (unless the ABSave is incorrect). else { // Mark it as an object. determinedType = ABSavePrimitiveType.Object; // We're going to try and find a TypeConverter. But if we can't find one - we'll just return the correct type based on the TypeName we were given. TypeConverter typeConv = TypeDescriptor.GetConverter(objType); // Check if the type converter can actually convert it FROM a string, if it can, use it. if (typeConv.CanConvertFrom(typeof(string))) { return(typeConv.ConvertFrom(str)); } // However, otherwise, since we know what the type is - we'll return that, and let the parser manually parse it. else { manuallyParse = true; return(Type.GetType(str)); } } // If we got here it was probably manually making the parser do the rest to return null. return(null); }
/// <summary> /// Serializes an object. The object could be anything. /// </summary> /// <param name="obj">The object to serialize</param> /// <param name="useSB">Whether this will write to a string builder (if true), or return a string (if false).</param> /// <param name="sb">The StringBuilder to write to - if <paramref name="useSB"/> is true.</param> /// <param name="determinedType">The primitive type which has been decided for it.</param> /// <param name="writeNextInstructionSymbol">Whether it will write \u0001 on the start - usually false if it is serializing the first object in a class.</param> /// <param name="dnWriteEndLevel">"Do Not Write End Level Symbol" - Marks whether to NOT write \u0005 (if true), commonly used for the last object of all.</param> /// <returns>If <paramref name="useSB"/> is false, this method will return the result as a string.</returns> public static string Serialize(dynamic obj, ABSaveType type, ABSaveSettings settings, out ABSavePrimitiveType determinedType, bool useSB = false, StringBuilder sb = null, bool writeNextInstructionSymbol = true, bool dnWriteEndLevel = false) { // This will be what to return if useSB is false. string ret; // For now, make it so we output "unknown". determinedType = ABSavePrimitiveType.Unknown; // Check if the object is null... or an IntPtr, write the null symbol - otherwise, we could get a StackOverflowException. if (obj == null || obj is IntPtr || obj is UIntPtr) { return(ABSaveWriter.WriteNullItem(useSB, sb)); } // Remember what type the object is - as well as the TypeCode. Type objType = obj.GetType(); var tCode = Type.GetTypeCode(obj.GetType()); // If the object is a string - write it as a string. if (tCode == TypeCode.String) { ret = ABSaveWriter.WriteString(obj, writeNextInstructionSymbol, useSB, sb); determinedType = ABSavePrimitiveType.String; } // If the object is a number - write it as a number. else if (IsNumericType(tCode)) { ret = ABSaveWriter.WriteNumerical(obj, tCode, true, useSB, sb); determinedType = ABSavePrimitiveType.Number; } // If the object is an array - serialize it as an array. else if (IsArray(objType)) { ret = SerializeArray(obj, objType, type, settings, useSB, sb, dnWriteEndLevel); determinedType = ABSavePrimitiveType.Array; } // If the object is a dictionary - serialize it as a dictionary. else if (IsDictionary(objType)) { ret = SerializeDictionary(obj, type, settings, useSB, sb, dnWriteEndLevel); determinedType = ABSavePrimitiveType.Dictionary; } // If the object is a boolean - serialize it as a boolean. else if (tCode == TypeCode.Boolean) { ret = SerializeBool(obj, writeNextInstructionSymbol, useSB, sb); determinedType = ABSavePrimitiveType.Boolean; } // If the object is a DateTime - serialize it as a DateTime. else if (tCode == TypeCode.DateTime) { ret = SerializeDateTime(obj, useSB, sb); determinedType = ABSavePrimitiveType.DateTime; } // If it's a type, just write it out using the ABSaveWriter (for some reason there is no TypeConverter built-in for a type!) else if (obj is Type) { ret = SerializeType(obj, useSB, sb); determinedType = ABSavePrimitiveType.Type; } // Otherwise, we'll attempt to find a built-in type converter (to a string) else { // Mark it as an object. determinedType = ABSavePrimitiveType.Object; // Attempt to get a converter for it. var canBeTypeConverted = false; var typeConv = TypeDescriptor.GetConverter(objType); // Check if the type converter can actually convert it to a string. if (typeConv.IsValid(obj)) { if (typeConv.CanConvertTo(typeof(string))) { canBeTypeConverted = true; } } // If it can be type converted, convert it using that, and then write it as a string. if (canBeTypeConverted) { ret = ABSaveWriter.WriteString(typeConv.ConvertToString(obj), writeNextInstructionSymbol, useSB, sb); } // Otherwise, if it can't be type converted... Manually convert it. else { ret = SerializeObject(obj, type, objType, settings, writeNextInstructionSymbol, useSB, sb, dnWriteEndLevel); } } // Return the result from this. return(ret); }
/// <summary> /// Serializes an object, by using <see cref="ABSaveConvert"/>, but some extras. /// </summary> /// <param name="obj">The object to serialize manually.</param> /// <param name="objType">The type of the object to serialize manually.</param> /// <param name="useSB">Whether this will write to a string builder (if true), or return a string (if false).</param> /// <param name="sb">The StringBuilder to write to - if <paramref name="useSB"/> is true.</param> /// <param name="dnWriteEndLevel">"Do Not Write End Level Symbol" - Marks whether to NOT write \u0005 (if true), commonly used for the last object of all.</param> /// <param name="settings">The settings for how to handle certain parts.</param> /// <returns>If <paramref name="useSB"/> is false, this method will return the result as a string.</returns> public static string SerializeObject(object obj, ABSaveType type, Type objType, ABSaveSettings settings, bool writeNextInstructionSymbol = true, bool useSB = false, StringBuilder sb = null, bool dnWriteEndLevel = false) { // Create a variable to store what we'll return - if we aren't using a StringBuilder. var ret = ""; // First, write a "next step" symbol. ret += ABSaveWriter.WriteNextItem(writeNextInstructionSymbol, useSB, sb); // Next, serialize the type that goes before it. ret += SerializeTypeBeforeObject(objType, settings, useSB, sb); // Then, write the opening (\u0003) for the object. ret += ABSaveWriter.WriteObjectOpen(useSB, sb); // And, write the actual object, use the correct method for either string or for a StringBuilder. ret += ABSaveConvert.ObjectToABSave(obj, type, settings, useSB, sb); // Finally, write the ending for the object. ret += ABSaveWriter.WriteObjectClose(dnWriteEndLevel, useSB, sb); // Now, "ret" would be empty if we were using a StringBuilder, however, if we weren't... It will have the correct string in it so return it. return(ret); }
public void Setup <T>(ABSaveSettings settings, Dictionary <Type, uint> targetVersions = null) { Initialize(settings, targetVersions); ResetStateWithMapFor <T>(); }
/// <summary> /// An object (with multiple properties) to serialize manually - one that doesn't have a TypeConverter. /// </summary> /// <param name="obj">The object to serialize manually</param> /// <param name="objType">The type of the object.</param> /// <param name="useSB">Whether this will write to a string builder (if true), or return a string (if false).</param> /// <param name="sb">The StringBuilder to write to - if <paramref name="useSB"/> is true.</param> /// <param name="dnWriteEndLevel">"Do Not Write End Level Symbol" - Marks whether to NOT write \u0005 (if true), commonly used for the last object of all.</param> /// <returns>If <paramref name="useSB"/> is false, this method will return the result as a string.</returns> public static string SerializeArray(dynamic obj, Type objType, ABSaveType type, ABSaveSettings settings, bool useSB = false, StringBuilder sb = null, bool dnWriteEndLevel = false) { obj = obj as IEnumerable; // Create a variable to store what we'll return. var ret = ""; // Keep track of whether we're on the first item or not. var notFirst = false; // Write the opening for the array. ret += ABSaveWriter.WriteArrayOpening(useSB, sb); // Keep track of what type the last property was - this allows us to decide whether to add the Next Item character to the next item. var lastType = ABSavePrimitiveType.Unknown; // If it's an array, just use a "for" loop. if (objType.IsArray) { for (var i = 0; i < obj.Length; i++) { SerializeArrayItem(type, settings, useSB, sb, dnWriteEndLevel, ref ret, ref notFirst, ref lastType, obj[i]); } } // For anything else, foreach will work fine. else { foreach (var item in obj) { SerializeArrayItem(type, settings, useSB, sb, dnWriteEndLevel, ref ret, ref notFirst, ref lastType, item); } } // Write the closing for the array. ret += ABSaveWriter.WriteObjectClose(dnWriteEndLevel, useSB, sb); // Now, "ret" would be empty if we were using a StringBuilder, however, if we weren't... It will have the correct string in it so return it. return(ret); }