451 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			451 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C#
		
	
	
	
using UnityEngine;
 | 
						|
using System.IO;
 | 
						|
using System.Collections;
 | 
						|
using System.Collections.Generic;
 | 
						|
using System;
 | 
						|
using System.ComponentModel;
 | 
						|
using ES3Types;
 | 
						|
using ES3Internal;
 | 
						|
 | 
						|
public abstract class ES3Reader : System.IDisposable
 | 
						|
{
 | 
						|
	/// <summary>The settings used to create this reader.</summary>
 | 
						|
	public ES3Settings settings;
 | 
						|
 | 
						|
    protected int serializationDepth = 0;
 | 
						|
 | 
						|
	#region ES3Reader 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 ES3Reader(ES3Settings 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 ES3Type file.</summary>
 | 
						|
	public virtual ES3ReaderPropertyEnumerator Properties
 | 
						|
	{
 | 
						|
		get
 | 
						|
		{
 | 
						|
			return new ES3ReaderPropertyEnumerator (this);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	internal virtual ES3ReaderRawEnumerator RawEnumerator
 | 
						|
	{
 | 
						|
		get
 | 
						|
		{
 | 
						|
			return new ES3ReaderRawEnumerator (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>(ES3TypeMgr.GetOrCreateES3Type(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, ES3TypeMgr.GetOrCreateES3Type(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>(ES3TypeMgr.GetOrCreateES3Type(typeof(T)));
 | 
						|
	}
 | 
						|
 | 
						|
	[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
 | 
						|
	public T ReadProperty<T>(ES3Type type)
 | 
						|
	{
 | 
						|
		ReadPropertyName();
 | 
						|
		return Read<T>(type);
 | 
						|
	}
 | 
						|
 | 
						|
    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
 | 
						|
    public long ReadRefProperty()
 | 
						|
    {
 | 
						|
        ReadPropertyName();
 | 
						|
        return Read_ref();
 | 
						|
    }
 | 
						|
 | 
						|
    internal Type ReadType()
 | 
						|
	{
 | 
						|
		return ES3Reflection.GetType(Read<string>(ES3Type_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>
 | 
						|
	public void SetPrivateProperty(string name, object value, object objectContainingProperty)
 | 
						|
	{
 | 
						|
		var property = ES3Reflection.GetES3ReflectedProperty(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);
 | 
						|
	}
 | 
						|
 | 
						|
	/// <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="objectContainingProperty">The object containing the field we want to set.</param>
 | 
						|
	public void SetPrivateField(string name, object value, object objectContainingField)
 | 
						|
	{
 | 
						|
		var field = ES3Reflection.GetES3ReflectedMember(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);
 | 
						|
	}
 | 
						|
 | 
						|
	#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>(ES3TypeMgr.GetOrCreateES3Type(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>(ES3TypeMgr.GetOrCreateES3Type(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, ES3TypeMgr.GetOrCreateES3Type(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, ES3Type type)
 | 
						|
	{
 | 
						|
		// Check for null.
 | 
						|
		if(StartReadObject())
 | 
						|
			return;
 | 
						|
 | 
						|
		type.ReadInto<T>(this, obj);
 | 
						|
 | 
						|
		EndReadObject();
 | 
						|
	}
 | 
						|
 | 
						|
	protected virtual T ReadObject<T>(ES3Type type)
 | 
						|
	{
 | 
						|
		if(StartReadObject())
 | 
						|
			return default(T);
 | 
						|
 | 
						|
		object obj = type.Read<T>(this);
 | 
						|
 | 
						|
		EndReadObject();
 | 
						|
		return (T)obj;
 | 
						|
	}
 | 
						|
		
 | 
						|
 | 
						|
	#endregion
 | 
						|
 | 
						|
	#region Read(ES3Type) & Read(obj,ES3Type) 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>(ES3Type 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)((ES3CollectionType)type).Read(this);
 | 
						|
		else if(type.isDictionary)
 | 
						|
			return (T)((ES3DictionaryType)type).Read(this);
 | 
						|
		else
 | 
						|
			return ReadObject<T>(type);
 | 
						|
	}
 | 
						|
 | 
						|
	[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
 | 
						|
	public virtual void ReadInto<T>(object obj, ES3Type 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)
 | 
						|
			((ES3CollectionType)type).ReadInto(this, obj);
 | 
						|
		else if(type.isDictionary)
 | 
						|
			((ES3DictionaryType)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 ES3Reader and loads the default file into it.</summary>
 | 
						|
	public static ES3Reader Create()
 | 
						|
	{
 | 
						|
		return Create(new ES3Settings());
 | 
						|
	}
 | 
						|
 | 
						|
	/// <summary>Creates a new ES3Reader 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 ES3Reader Create(string filePath)
 | 
						|
	{
 | 
						|
		return Create(new ES3Settings(filePath));
 | 
						|
	}
 | 
						|
 | 
						|
	/// <summary>Creates a new ES3Reader 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 ES3Reader Create(string filePath, ES3Settings settings)
 | 
						|
	{
 | 
						|
		return Create(new ES3Settings(filePath, settings));
 | 
						|
	}
 | 
						|
 | 
						|
	/// <summary>Creates a new ES3Reader 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 ES3Reader Create(ES3Settings settings)
 | 
						|
	{
 | 
						|
		Stream stream = ES3Stream.CreateStream(settings, ES3FileMode.Read);
 | 
						|
		if(stream == null)
 | 
						|
			return null;
 | 
						|
 | 
						|
        // Get the baseWriter using the given Stream.
 | 
						|
        if (settings.format == ES3.Format.JSON)
 | 
						|
            return new ES3JSONReader(stream, settings);
 | 
						|
		return null;
 | 
						|
	}
 | 
						|
 | 
						|
	/// <summary>Creates a new ES3Reader and loads the bytes provided into it.</summary>
 | 
						|
	public static ES3Reader Create(byte[] bytes)
 | 
						|
	{
 | 
						|
		return Create(bytes, new ES3Settings());
 | 
						|
	}
 | 
						|
 | 
						|
	/// <summary>Creates a new ES3Reader 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 ES3Reader Create(byte[] bytes, ES3Settings settings)
 | 
						|
	{
 | 
						|
		Stream stream = ES3Stream.CreateStream(new MemoryStream(bytes), settings, ES3FileMode.Read);
 | 
						|
		if(stream == null)
 | 
						|
			return null;
 | 
						|
 | 
						|
		// Get the baseWriter using the given Stream.
 | 
						|
		if(settings.format == ES3.Format.JSON)
 | 
						|
			return new ES3JSONReader(stream, settings);
 | 
						|
        return null;
 | 
						|
	}
 | 
						|
 | 
						|
	internal static ES3Reader Create(Stream stream, ES3Settings settings)
 | 
						|
	{
 | 
						|
		stream = ES3Stream.CreateStream(stream, settings, ES3FileMode.Read);
 | 
						|
 | 
						|
		// Get the baseWriter using the given Stream.
 | 
						|
		if(settings.format == ES3.Format.JSON)
 | 
						|
			return new ES3JSONReader(stream, settings);
 | 
						|
        return null;
 | 
						|
	}
 | 
						|
 | 
						|
	internal static ES3Reader Create(Stream stream, ES3Settings settings, bool readHeaderAndFooter)
 | 
						|
	{
 | 
						|
		// Get the baseWriter using the given Stream.
 | 
						|
		if(settings.format == ES3.Format.JSON)
 | 
						|
			return new ES3JSONReader(stream, settings, readHeaderAndFooter);
 | 
						|
        return null;
 | 
						|
	}
 | 
						|
 | 
						|
	[EditorBrowsable(EditorBrowsableState.Never)]
 | 
						|
	public class ES3ReaderPropertyEnumerator
 | 
						|
	{
 | 
						|
		public ES3Reader reader;
 | 
						|
 | 
						|
		public ES3ReaderPropertyEnumerator(ES3Reader 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 ES3ReaderRawEnumerator
 | 
						|
	{
 | 
						|
		public ES3Reader reader;
 | 
						|
 | 
						|
		public ES3ReaderRawEnumerator(ES3Reader 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,ES3Data>(key, new ES3Data(type, bytes));
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
} |