BS 0.0.1 EasySave初步
This commit is contained in:
454
Convention/Runtime/EasySave/Readers/EasySaveReader.cs
Normal file
454
Convention/Runtime/EasySave/Readers/EasySaveReader.cs
Normal file
@@ -0,0 +1,454 @@
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Convention.EasySave.Types;
|
||||
using Convention.EasySave.Internal;
|
||||
|
||||
public abstract class EasySaveReader : System.IDisposable
|
||||
{
|
||||
/// <summary>The settings used to create this reader.</summary>
|
||||
public EasySaveSettings settings;
|
||||
|
||||
protected int serializationDepth = 0;
|
||||
|
||||
#region EasySaveReader Abstract Methods
|
||||
|
||||
internal abstract int Read_int();
|
||||
internal abstract float Read_float();
|
||||
internal abstract bool Read_bool();
|
||||
internal abstract char Read_char();
|
||||
internal abstract decimal Read_decimal();
|
||||
internal abstract double Read_double();
|
||||
internal abstract long Read_long();
|
||||
internal abstract ulong Read_ulong();
|
||||
internal abstract byte Read_byte();
|
||||
internal abstract sbyte Read_sbyte();
|
||||
internal abstract short Read_short();
|
||||
internal abstract ushort Read_ushort();
|
||||
internal abstract uint Read_uint();
|
||||
internal abstract string Read_string();
|
||||
internal abstract byte[] Read_byteArray();
|
||||
internal abstract long Read_ref();
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public abstract string ReadPropertyName();
|
||||
|
||||
protected abstract Type ReadKeyPrefix(bool ignore = false);
|
||||
protected abstract void ReadKeySuffix();
|
||||
internal abstract byte[] ReadElement(bool skip=false);
|
||||
|
||||
/// <summary>Disposes of the reader and it's underlying stream.</summary>
|
||||
public abstract void Dispose();
|
||||
|
||||
// Seeks to the given key. Note that the stream position will not be reset.
|
||||
internal virtual bool Goto(string key)
|
||||
{
|
||||
if (key == null)
|
||||
throw new ArgumentNullException("Key cannot be NULL when loading data.");
|
||||
|
||||
string currentKey;
|
||||
while ((currentKey = ReadPropertyName()) != key)
|
||||
{
|
||||
if (currentKey == null)
|
||||
return false;
|
||||
Skip();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
internal virtual bool StartReadObject()
|
||||
{
|
||||
serializationDepth++;
|
||||
return false;
|
||||
}
|
||||
|
||||
internal virtual void EndReadObject()
|
||||
{
|
||||
serializationDepth--;
|
||||
}
|
||||
|
||||
internal abstract bool StartReadDictionary();
|
||||
internal abstract void EndReadDictionary();
|
||||
internal abstract bool StartReadDictionaryKey();
|
||||
internal abstract void EndReadDictionaryKey();
|
||||
internal abstract void StartReadDictionaryValue();
|
||||
internal abstract bool EndReadDictionaryValue();
|
||||
|
||||
internal abstract bool StartReadCollection();
|
||||
internal abstract void EndReadCollection();
|
||||
internal abstract bool StartReadCollectionItem();
|
||||
internal abstract bool EndReadCollectionItem();
|
||||
|
||||
#endregion
|
||||
|
||||
internal EasySaveReader(EasySaveSettings settings, bool readHeaderAndFooter = true)
|
||||
{
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
// If this is not null, the next call to the Properties will return this name.
|
||||
internal string overridePropertiesName = null;
|
||||
/// <summary>Allows you to enumerate over each field name. This should only be used within an EasySaveType file.</summary>
|
||||
public virtual EasySaveReaderPropertyEnumerator Properties
|
||||
{
|
||||
get
|
||||
{
|
||||
return new EasySaveReaderPropertyEnumerator (this);
|
||||
}
|
||||
}
|
||||
|
||||
internal virtual EasySaveReaderRawEnumerator RawEnumerator
|
||||
{
|
||||
get
|
||||
{
|
||||
return new EasySaveReaderRawEnumerator (this);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Skips the current object in the stream.
|
||||
* Stream position should be somewhere before the opening brace for the object.
|
||||
* When this method successfully exits, it will be on the closing brace for the object.
|
||||
*/
|
||||
/// <summary>Skips the current object in the stream.</summary>
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public virtual void Skip()
|
||||
{
|
||||
ReadElement(true);
|
||||
}
|
||||
|
||||
/// <summary>Reads a value of type T from the reader.</summary>
|
||||
public virtual T Read<T>()
|
||||
{
|
||||
return Read<T>(EasySaveTypeMgr.GetOrCreateEasySaveType(typeof(T)));
|
||||
}
|
||||
|
||||
/// <summary>Reads a value of type T from the reader into an existing object.</summary>
|
||||
/// <param name="obj">The object we want to read our value into.</param>
|
||||
public virtual void ReadInto<T>(object obj)
|
||||
{
|
||||
ReadInto<T>(obj, EasySaveTypeMgr.GetOrCreateEasySaveType(typeof(T)));
|
||||
}
|
||||
|
||||
/// <summary>Reads a property (i.e. a property name and value) from the reader, ignoring the property name and only returning the value.</summary>
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public T ReadProperty<T>()
|
||||
{
|
||||
return ReadProperty<T>(EasySaveTypeMgr.GetOrCreateEasySaveType(typeof(T)));
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public T ReadProperty<T>(EasySaveType type)
|
||||
{
|
||||
ReadPropertyName();
|
||||
return Read<T>(type);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public long ReadRefProperty()
|
||||
{
|
||||
ReadPropertyName();
|
||||
return Read_ref();
|
||||
}
|
||||
|
||||
internal Type ReadType()
|
||||
{
|
||||
return EasySaveReflection.GetType(Read<string>(EasySaveType_string.Instance));
|
||||
}
|
||||
|
||||
/// <summary>Sets the value of a private property on an object.</summary>
|
||||
/// <param name="name">The name of the property we want to set.</param>
|
||||
/// <param name="value">The value we want to set the property to.</param>
|
||||
/// <param name="objectContainingProperty">The object containing the property we want to set.</param>
|
||||
/// <returns>The objectContainingProperty object. This is helpful if you're setting a private property on a struct or other immutable type and need to return the boxed value.</returns>
|
||||
public object SetPrivateProperty(string name, object value, object objectContainingProperty)
|
||||
{
|
||||
var property = EasySaveReflection.GetEasySaveReflectedProperty(objectContainingProperty.GetType(), name);
|
||||
if (property.IsNull)
|
||||
throw new MissingMemberException("A private property named " + name + " does not exist in the type " + objectContainingProperty.GetType());
|
||||
property.SetValue(objectContainingProperty, value);
|
||||
return objectContainingProperty;
|
||||
}
|
||||
|
||||
/// <summary>Sets the value of a private field on an object.</summary>
|
||||
/// <param name="name">The name of the field we want to set.</param>
|
||||
/// <param name="value">The value we want to set the field to.</param>
|
||||
/// <param name="objectContainingField">The object containing the field we want to set.</param>
|
||||
/// <returns>The objectContainingField object. This is helpful if you're setting a private property on a struct or other immutable type and need to return the boxed value.</returns>
|
||||
public object SetPrivateField(string name, object value, object objectContainingField)
|
||||
{
|
||||
var field = EasySaveReflection.GetEasySaveReflectedMember(objectContainingField.GetType(), name);
|
||||
if(field.IsNull)
|
||||
throw new MissingMemberException("A private field named "+ name + " does not exist in the type "+objectContainingField.GetType());
|
||||
field.SetValue(objectContainingField, value);
|
||||
return objectContainingField;
|
||||
}
|
||||
|
||||
#region Read(key) & Read(key, obj) methods
|
||||
|
||||
/// <summary>Reads a value from the reader with the given key.</summary>
|
||||
/// <param name="key">The key which uniquely identifies our value.</param>
|
||||
public virtual T Read<T>(string key)
|
||||
{
|
||||
if(!Goto(key))
|
||||
throw new KeyNotFoundException("Key \"" + key + "\" was not found in file \""+settings.FullPath+"\". Use Load<T>(key, defaultValue) if you want to return a default value if the key does not exist.");
|
||||
|
||||
Type type = ReadTypeFromHeader<T>();
|
||||
|
||||
T obj = Read<T>(EasySaveTypeMgr.GetOrCreateEasySaveType(type));
|
||||
|
||||
//ReadKeySuffix(); //No need to read key suffix as we're returning. Doing so would throw an error at this point for BinaryReaders.
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>Reads a value from the reader with the given key, returning the default value if the key does not exist.</summary>
|
||||
/// <param name="key">The key which uniquely identifies our value.</param>
|
||||
/// <param name="defaultValue">The value we want to return if this key does not exist in the reader.</param>
|
||||
public virtual T Read<T>(string key, T defaultValue)
|
||||
{
|
||||
if(!Goto(key))
|
||||
return defaultValue;
|
||||
|
||||
Type type = ReadTypeFromHeader<T>();
|
||||
T obj = Read<T>(EasySaveTypeMgr.GetOrCreateEasySaveType(type));
|
||||
|
||||
//ReadKeySuffix(); //No need to read key suffix as we're returning. Doing so would throw an error at this point for BinaryReaders.
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>Reads a value from the reader with the given key into the provided object.</summary>
|
||||
/// <param name="key">The key which uniquely identifies our value.</param>
|
||||
/// <param name="obj">The object we want to load the value into.</param>
|
||||
public virtual void ReadInto<T>(string key, T obj) where T : class
|
||||
{
|
||||
if(!Goto(key))
|
||||
throw new KeyNotFoundException("Key \"" + key + "\" was not found in file \""+settings.FullPath+"\"");
|
||||
|
||||
Type type = ReadTypeFromHeader<T>();
|
||||
|
||||
ReadInto<T>(obj, EasySaveTypeMgr.GetOrCreateEasySaveType(type));
|
||||
|
||||
//ReadKeySuffix(); //No need to read key suffix as we're returning. Doing so would throw an error at this point for BinaryReaders.
|
||||
}
|
||||
|
||||
protected virtual void ReadObject<T>(object obj, EasySaveType type)
|
||||
{
|
||||
// Check for null.
|
||||
if(StartReadObject())
|
||||
return;
|
||||
|
||||
type.ReadInto<T>(this, obj);
|
||||
|
||||
EndReadObject();
|
||||
}
|
||||
|
||||
protected virtual T ReadObject<T>(EasySaveType type)
|
||||
{
|
||||
if(StartReadObject())
|
||||
return default(T);
|
||||
|
||||
object obj = type.Read<T>(this);
|
||||
|
||||
EndReadObject();
|
||||
return (T)obj;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Read(EasySaveType) & Read(obj,EasySaveType) methods
|
||||
|
||||
/*
|
||||
* Parses the next JSON Object in the stream (i.e. must be between '{' and '}' chars).
|
||||
* If the first character in the Stream is not a '{', it will throw an error.
|
||||
* Will also read the terminating '}'.
|
||||
* If we have reached the end of stream, it will return null.
|
||||
*/
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public virtual T Read<T>(EasySaveType type)
|
||||
{
|
||||
if (type == null || type.isUnsupported)
|
||||
throw new NotSupportedException("Type of " + type + " is not currently supported, and could not be loaded using reflection.");
|
||||
else if (type.isPrimitive)
|
||||
return (T)type.Read<T>(this);
|
||||
else if (type.isCollection)
|
||||
return (T)((ECollectionType)type).Read(this);
|
||||
else if (type.isDictionary)
|
||||
return (T)((EasySaveDictionaryType)type).Read(this);
|
||||
else
|
||||
return ReadObject<T>(type);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public virtual void ReadInto<T>(object obj, EasySaveType type)
|
||||
{
|
||||
if(type == null || type.isUnsupported)
|
||||
throw new NotSupportedException("Type of "+obj.GetType()+" is not currently supported, and could not be loaded using reflection.");
|
||||
|
||||
else if(type.isCollection)
|
||||
((ECollectionType)type).ReadInto(this, obj);
|
||||
else if(type.isDictionary)
|
||||
((EasySaveDictionaryType)type).ReadInto(this, obj);
|
||||
else
|
||||
ReadObject<T>(obj, type);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
internal Type ReadTypeFromHeader<T>()
|
||||
{
|
||||
// Check whether we need to determine the type by reading the header.
|
||||
if(typeof(T) == typeof(object))
|
||||
return ReadKeyPrefix();
|
||||
else if(settings.typeChecking)
|
||||
{
|
||||
Type type = ReadKeyPrefix();
|
||||
if(type != typeof(T))
|
||||
throw new InvalidOperationException("Trying to load data of type "+typeof(T)+", but data contained in file is type of "+type+".");
|
||||
return type;
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadKeyPrefix(true);
|
||||
return typeof(T);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Creates a new EasySaveReader and loads the default file into it.</summary>
|
||||
public static EasySaveReader Create()
|
||||
{
|
||||
return Create(new EasySaveSettings());
|
||||
}
|
||||
|
||||
/// <summary>Creates a new EasySaveReader and loads a file in storage into it.</summary>
|
||||
/// <param name="filePath">The relative or absolute path of the file we want to load into the reader.</param>
|
||||
public static EasySaveReader Create(string filePath)
|
||||
{
|
||||
return Create(new EasySaveSettings(filePath));
|
||||
}
|
||||
|
||||
/// <summary>Creates a new EasySaveReader and loads a file in storage into it.</summary>
|
||||
/// <param name="filePath">The relative or absolute path of the file we want to load into the reader.</param>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public static EasySaveReader Create(string filePath, EasySaveSettings settings)
|
||||
{
|
||||
return Create(new EasySaveSettings(filePath, settings));
|
||||
}
|
||||
|
||||
/// <summary>Creates a new EasySaveReader and loads a file in storage into it.</summary>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public static EasySaveReader Create(EasySaveSettings settings)
|
||||
{
|
||||
Stream stream = EasySaveStream.CreateStream(settings, EasySaveFileMode.Read);
|
||||
if(stream == null)
|
||||
return null;
|
||||
|
||||
// Get the baseWriter using the given Stream.
|
||||
if (settings.format == EasySave.Format.JSON)
|
||||
return new EasySaveJSONReader(stream, settings);
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>Creates a new EasySaveReader and loads the bytes provided into it.</summary>
|
||||
public static EasySaveReader Create(byte[] bytes)
|
||||
{
|
||||
return Create(bytes, new EasySaveSettings());
|
||||
}
|
||||
|
||||
/// <summary>Creates a new EasySaveReader and loads the bytes provided into it.</summary>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public static EasySaveReader Create(byte[] bytes, EasySaveSettings settings)
|
||||
{
|
||||
Stream stream = EasySaveStream.CreateStream(new MemoryStream(bytes), settings, EasySaveFileMode.Read);
|
||||
if(stream == null)
|
||||
return null;
|
||||
|
||||
// Get the baseWriter using the given Stream.
|
||||
if(settings.format == EasySave.Format.JSON)
|
||||
return new EasySaveJSONReader(stream, settings);
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static EasySaveReader Create(Stream stream, EasySaveSettings settings)
|
||||
{
|
||||
stream = EasySaveStream.CreateStream(stream, settings, EasySaveFileMode.Read);
|
||||
|
||||
// Get the baseWriter using the given Stream.
|
||||
if(settings.format == EasySave.Format.JSON)
|
||||
return new EasySaveJSONReader(stream, settings);
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static EasySaveReader Create(Stream stream, EasySaveSettings settings, bool readHeaderAndFooter)
|
||||
{
|
||||
// Get the baseWriter using the given Stream.
|
||||
if(settings.format == EasySave.Format.JSON)
|
||||
return new EasySaveJSONReader(stream, settings, readHeaderAndFooter);
|
||||
return null;
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public class EasySaveReaderPropertyEnumerator
|
||||
{
|
||||
public EasySaveReader reader;
|
||||
|
||||
public EasySaveReaderPropertyEnumerator(EasySaveReader reader)
|
||||
{
|
||||
this.reader = reader;
|
||||
}
|
||||
|
||||
public IEnumerator GetEnumerator()
|
||||
{
|
||||
string propertyName;
|
||||
while(true)
|
||||
{
|
||||
// Allows us to repeat a property name or insert one of our own.
|
||||
if(reader.overridePropertiesName != null)
|
||||
{
|
||||
string tempName = reader.overridePropertiesName;
|
||||
reader.overridePropertiesName = null;
|
||||
yield return tempName;
|
||||
}
|
||||
else
|
||||
{
|
||||
if((propertyName = reader.ReadPropertyName()) == null)
|
||||
yield break;
|
||||
yield return propertyName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public class EasySaveReaderRawEnumerator
|
||||
{
|
||||
public EasySaveReader reader;
|
||||
|
||||
public EasySaveReaderRawEnumerator(EasySaveReader reader)
|
||||
{
|
||||
this.reader = reader;
|
||||
}
|
||||
|
||||
public IEnumerator GetEnumerator()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
string key = reader.ReadPropertyName();
|
||||
if(key == null)
|
||||
yield break;
|
||||
|
||||
Type type = reader.ReadTypeFromHeader<object>();
|
||||
|
||||
byte[] bytes = reader.ReadElement();
|
||||
|
||||
reader.ReadKeySuffix();
|
||||
|
||||
if(type != null)
|
||||
yield return new KeyValuePair<string,EasySaveData>(key, new EasySaveData(type, bytes));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user