498 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C#
		
	
	
	
		
		
			
		
	
	
			498 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C#
		
	
	
	
| 
								 | 
							
								using System.Collections;
							 | 
						|||
| 
								 | 
							
								using System.Collections.Generic;
							 | 
						|||
| 
								 | 
							
								using System.IO;
							 | 
						|||
| 
								 | 
							
								using System;
							 | 
						|||
| 
								 | 
							
								using ES3Types;
							 | 
						|||
| 
								 | 
							
								using UnityEngine;
							 | 
						|||
| 
								 | 
							
								using ES3Internal;
							 | 
						|||
| 
								 | 
							
								using System.Linq;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								/// <summary>Represents a cached file which can be saved to and loaded from, and commited to storage when necessary.</summary>
							 | 
						|||
| 
								 | 
							
								public class ES3File
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
							 | 
						|||
| 
								 | 
							
								    internal static Dictionary<string, ES3File> cachedFiles = new Dictionary<string, ES3File>();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    public ES3Settings settings;
							 | 
						|||
| 
								 | 
							
								    private Dictionary<string, ES3Data> cache = new Dictionary<string, ES3Data>();
							 | 
						|||
| 
								 | 
							
								    private bool syncWithFile = false;
							 | 
						|||
| 
								 | 
							
								    private DateTime timestamp = DateTime.UtcNow;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Creates a new ES3File and loads the default file into the ES3File if there is data to load.</summary>
							 | 
						|||
| 
								 | 
							
								    public ES3File() : this(new ES3Settings(), true) { }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Creates a new ES3File and loads the specified file into the ES3File if there is data to load.</summary>
							 | 
						|||
| 
								 | 
							
								    /// <param name="filepath">The relative or absolute path of the file in storage our ES3File is associated with.</param>
							 | 
						|||
| 
								 | 
							
								    public ES3File(string filePath) : this(new ES3Settings(filePath), true) { }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Creates a new ES3File and loads the specified file into the ES3File if there is data to load.</summary>
							 | 
						|||
| 
								 | 
							
								    /// <param name="filepath">The relative or absolute path of the file in storage our ES3File is associated with.</param>
							 | 
						|||
| 
								 | 
							
								    /// <param name="settings">The settings we want to use to override the default settings.</param>
							 | 
						|||
| 
								 | 
							
								    public ES3File(string filePath, ES3Settings settings) : this(new ES3Settings(filePath, settings), true) { }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Creates a new ES3File and loads the specified file into the ES3File if there is data to load.</summary>
							 | 
						|||
| 
								 | 
							
								    /// <param name="settings">The settings we want to use to override the default settings.</param>
							 | 
						|||
| 
								 | 
							
								    public ES3File(ES3Settings settings) : this(settings, true) { }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Creates a new ES3File and only loads the default file into it if syncWithFile is set to true.</summary>
							 | 
						|||
| 
								 | 
							
								    /// <param name="syncWithFile">Whether we should sync this ES3File with the one in storage immediately after creating it.</param>
							 | 
						|||
| 
								 | 
							
								    public ES3File(bool syncWithFile) : this(new ES3Settings(), syncWithFile) { }
							 | 
						|||
| 
								 | 
							
								    /// <summary>Creates a new ES3File and only loads the specified file into it if syncWithFile is set to true.</summary>
							 | 
						|||
| 
								 | 
							
								    /// <param name="filepath">The relative or absolute path of the file in storage our ES3File is associated with.</param>
							 | 
						|||
| 
								 | 
							
								    /// <param name="syncWithFile">Whether we should sync this ES3File with the one in storage immediately after creating it.</param>
							 | 
						|||
| 
								 | 
							
								    public ES3File(string filePath, bool syncWithFile) : this(new ES3Settings(filePath), syncWithFile) { }
							 | 
						|||
| 
								 | 
							
								    /// <summary>Creates a new ES3File and only loads the specified file into it if syncWithFile is set to true.</summary>
							 | 
						|||
| 
								 | 
							
								    /// <param name="filepath">The relative or absolute path of the file in storage our ES3File is associated with.</param>
							 | 
						|||
| 
								 | 
							
								    /// <param name="settings">The settings we want to use to override the default settings.</param>
							 | 
						|||
| 
								 | 
							
								    /// <param name="syncWithFile">Whether we should sync this ES3File with the one in storage immediately after creating it.</param>
							 | 
						|||
| 
								 | 
							
								    public ES3File(string filePath, ES3Settings settings, bool syncWithFile) : this(new ES3Settings(filePath, settings), syncWithFile) { }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Creates a new ES3File and loads the specified file into the ES3File if there is data to load.</summary>
							 | 
						|||
| 
								 | 
							
								    /// <param name="settings">The settings we want to use to override the default settings.</param>
							 | 
						|||
| 
								 | 
							
								    /// <param name="syncWithFile">Whether we should sync this ES3File with the one in storage immediately after creating it.</param>
							 | 
						|||
| 
								 | 
							
								    public ES3File(ES3Settings settings, bool syncWithFile)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        this.settings = settings;
							 | 
						|||
| 
								 | 
							
								        this.syncWithFile = syncWithFile;
							 | 
						|||
| 
								 | 
							
								        if (syncWithFile)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            // Type checking must be enabled when syncing.
							 | 
						|||
| 
								 | 
							
								            var settingsWithTypeChecking = (ES3Settings)settings.Clone();
							 | 
						|||
| 
								 | 
							
								            settingsWithTypeChecking.typeChecking = true;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            using (var reader = ES3Reader.Create(settingsWithTypeChecking))
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                if (reader == null)
							 | 
						|||
| 
								 | 
							
								                    return;
							 | 
						|||
| 
								 | 
							
								                foreach (KeyValuePair<string, ES3Data> kvp in reader.RawEnumerator)
							 | 
						|||
| 
								 | 
							
								                    cache[kvp.Key] = kvp.Value;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Creates a new ES3File and loads the bytes into the ES3File. Note the bytes must represent that of a file.</summary>
							 | 
						|||
| 
								 | 
							
								    /// <param name="bytes">The bytes representing our file.</param>
							 | 
						|||
| 
								 | 
							
								    /// <param name="settings">The settings we want to use to override the default settings.</param>
							 | 
						|||
| 
								 | 
							
								    /// <param name="syncWithFile">Whether we should sync this ES3File with the one in storage immediately after creating it.</param>
							 | 
						|||
| 
								 | 
							
								    public ES3File(byte[] bytes, ES3Settings settings = null)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        if (settings == null)
							 | 
						|||
| 
								 | 
							
								            this.settings = new ES3Settings();
							 | 
						|||
| 
								 | 
							
								        else
							 | 
						|||
| 
								 | 
							
								            this.settings = settings;
							 | 
						|||
| 
								 | 
							
								        SaveRaw(bytes, settings);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Synchronises this ES3File with a file in storage.</summary>
							 | 
						|||
| 
								 | 
							
								    public void Sync()
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        Sync(this.settings);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Synchronises this ES3File with a file in storage.</summary>
							 | 
						|||
| 
								 | 
							
								    /// <param name="filepath">The relative or absolute path of the file in storage we want to synchronise with.</param>
							 | 
						|||
| 
								 | 
							
								    /// <param name="settings">The settings we want to use to override the default settings.</param>
							 | 
						|||
| 
								 | 
							
								    public void Sync(string filePath, ES3Settings settings = null)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        Sync(new ES3Settings(filePath, settings));
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Synchronises this ES3File with a file in storage.</summary>
							 | 
						|||
| 
								 | 
							
								    /// <param name="settings">The settings we want to use to override the default settings.</param>
							 | 
						|||
| 
								 | 
							
								    public void Sync(ES3Settings settings = null)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        if (settings == null)
							 | 
						|||
| 
								 | 
							
								            settings = new ES3Settings();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        ES3.DeleteFile(settings);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        if (cache.Count == 0)
							 | 
						|||
| 
								 | 
							
								            return;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        using (var baseWriter = ES3Writer.Create(settings, true, !syncWithFile, false))
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            foreach (var kvp in cache)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                // If we change the name of a type, the type may be null.
							 | 
						|||
| 
								 | 
							
								                // In this case, use System.Object as the type.
							 | 
						|||
| 
								 | 
							
								                Type type;
							 | 
						|||
| 
								 | 
							
								                if (kvp.Value.type == null)
							 | 
						|||
| 
								 | 
							
								                    type = typeof(System.Object);
							 | 
						|||
| 
								 | 
							
								                else
							 | 
						|||
| 
								 | 
							
								                    type = kvp.Value.type.type;
							 | 
						|||
| 
								 | 
							
								                baseWriter.Write(kvp.Key, type, kvp.Value.bytes);
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            baseWriter.Save(!syncWithFile);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Removes the data stored in this ES3File. The ES3File will be empty after calling this method.</summary>
							 | 
						|||
| 
								 | 
							
								    public void Clear()
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        cache.Clear();
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Returns an array of all of the key names in this ES3File.</summary>
							 | 
						|||
| 
								 | 
							
								    public string[] GetKeys()
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        var keyCollection = cache.Keys;
							 | 
						|||
| 
								 | 
							
								        var keys = new string[keyCollection.Count];
							 | 
						|||
| 
								 | 
							
								        keyCollection.CopyTo(keys, 0);
							 | 
						|||
| 
								 | 
							
								        return keys;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    #region Save Methods
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Saves a value to a key in this ES3File.</summary>
							 | 
						|||
| 
								 | 
							
								    /// <param name="key">The key we want to use to identify our value in the file.</param>
							 | 
						|||
| 
								 | 
							
								    /// <param name="value">The value we want to save.</param>
							 | 
						|||
| 
								 | 
							
								    public void Save<T>(string key, T value)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        var unencryptedSettings = (ES3Settings)settings.Clone();
							 | 
						|||
| 
								 | 
							
								        unencryptedSettings.encryptionType = ES3.EncryptionType.None;
							 | 
						|||
| 
								 | 
							
								        unencryptedSettings.compressionType = ES3.CompressionType.None;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        // If T is object, use the value to get it's type. Otherwise, use T so that it works with inheritence.
							 | 
						|||
| 
								 | 
							
								        var type = typeof(T) != typeof(object) ? typeof(T) : (value == null ? typeof(T) : value.GetType());
							 | 
						|||
| 
								 | 
							
								        cache[key] = new ES3Data(ES3TypeMgr.GetOrCreateES3Type(type), ES3.Serialize(value, unencryptedSettings));
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Merges the data specified by the bytes parameter into this ES3File.</summary>
							 | 
						|||
| 
								 | 
							
								    /// <param name="bytes">The bytes we want to merge with this ES3File.</param>
							 | 
						|||
| 
								 | 
							
								    /// <param name="settings">The settings we want to use to override the default settings.</param>
							 | 
						|||
| 
								 | 
							
								    public void SaveRaw(byte[] bytes, ES3Settings settings = null)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        if (settings == null)
							 | 
						|||
| 
								 | 
							
								            settings = new ES3Settings();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        // Type checking must be enabled when syncing.
							 | 
						|||
| 
								 | 
							
								        var settingsWithTypeChecking = (ES3Settings)settings.Clone();
							 | 
						|||
| 
								 | 
							
								        settingsWithTypeChecking.typeChecking = true;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        using (var reader = ES3Reader.Create(bytes, settingsWithTypeChecking))
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            if (reader == null)
							 | 
						|||
| 
								 | 
							
								                return;
							 | 
						|||
| 
								 | 
							
								            foreach (KeyValuePair<string, ES3Data> kvp in reader.RawEnumerator)
							 | 
						|||
| 
								 | 
							
								                cache[kvp.Key] = kvp.Value;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Merges the data specified by the bytes parameter into this ES3File.</summary>
							 | 
						|||
| 
								 | 
							
								    /// <param name="bytes">The bytes we want to merge with this ES3File.</param>
							 | 
						|||
| 
								 | 
							
								    /// <param name="settings">The settings we want to use to override the default settings.</param>
							 | 
						|||
| 
								 | 
							
								    public void AppendRaw(byte[] bytes, ES3Settings settings = null)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        if (settings == null)
							 | 
						|||
| 
								 | 
							
								            settings = new ES3Settings();
							 | 
						|||
| 
								 | 
							
								        // AppendRaw just does the same thing as SaveRaw in ES3File.
							 | 
						|||
| 
								 | 
							
								        SaveRaw(bytes, settings);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    #endregion
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    #region Load Methods
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /* Standard load methods */
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Loads the value from this ES3File with the given key.</summary>
							 | 
						|||
| 
								 | 
							
								    /// <param name="key">The key which identifies the value we want to load.</param>
							 | 
						|||
| 
								 | 
							
								    public object Load(string key)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        return Load<object>(key);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Loads the value from this ES3File with the given key.</summary>
							 | 
						|||
| 
								 | 
							
								    /// <param name="key">The key which identifies the value we want to load.</param>
							 | 
						|||
| 
								 | 
							
								    /// <param name="defaultValue">The value we want to return if the key does not exist in this ES3File.</param>
							 | 
						|||
| 
								 | 
							
								    public object Load(string key, object defaultValue)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        return Load<object>(key, defaultValue);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Loads the value from this ES3File with the given key.</summary>
							 | 
						|||
| 
								 | 
							
								    /// <param name="key">The key which identifies the value we want to load.</param>
							 | 
						|||
| 
								 | 
							
								    public T Load<T>(string key)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        ES3Data es3Data;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        if (!cache.TryGetValue(key, out es3Data))
							 | 
						|||
| 
								 | 
							
								            throw new KeyNotFoundException("Key \"" + key + "\" was not found in this ES3File. Use Load<T>(key, defaultValue) if you want to return a default value if the key does not exist.");
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        var unencryptedSettings = (ES3Settings)this.settings.Clone();
							 | 
						|||
| 
								 | 
							
								        unencryptedSettings.encryptionType = ES3.EncryptionType.None;
							 | 
						|||
| 
								 | 
							
								        unencryptedSettings.compressionType = ES3.CompressionType.None;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        if (typeof(T) == typeof(object))
							 | 
						|||
| 
								 | 
							
								            return (T)ES3.Deserialize(es3Data.type, es3Data.bytes, unencryptedSettings);
							 | 
						|||
| 
								 | 
							
								        return ES3.Deserialize<T>(es3Data.bytes, unencryptedSettings);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Loads the value from this ES3File with the given key.</summary>
							 | 
						|||
| 
								 | 
							
								    /// <param name="key">The key which identifies the value we want to load.</param>
							 | 
						|||
| 
								 | 
							
								    /// <param name="defaultValue">The value we want to return if the key does not exist in this ES3File.</param>
							 | 
						|||
| 
								 | 
							
								    public T Load<T>(string key, T defaultValue)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        ES3Data es3Data;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        if (!cache.TryGetValue(key, out es3Data))
							 | 
						|||
| 
								 | 
							
								            return defaultValue;
							 | 
						|||
| 
								 | 
							
								        var unencryptedSettings = (ES3Settings)this.settings.Clone();
							 | 
						|||
| 
								 | 
							
								        unencryptedSettings.encryptionType = ES3.EncryptionType.None;
							 | 
						|||
| 
								 | 
							
								        unencryptedSettings.compressionType = ES3.CompressionType.None;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        if (typeof(T) == typeof(object))
							 | 
						|||
| 
								 | 
							
								            return (T)ES3.Deserialize(es3Data.type, es3Data.bytes, unencryptedSettings);
							 | 
						|||
| 
								 | 
							
								        return ES3.Deserialize<T>(es3Data.bytes, unencryptedSettings);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Loads the value from this ES3File with the given key into an existing object.</summary>
							 | 
						|||
| 
								 | 
							
								    /// <param name="key">The key which identifies the value we want to load.</param>
							 | 
						|||
| 
								 | 
							
								    /// <param name="obj">The object we want to load the value into.</param>
							 | 
						|||
| 
								 | 
							
								    public void LoadInto<T>(string key, T obj) where T : class
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        ES3Data es3Data;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        if (!cache.TryGetValue(key, out es3Data))
							 | 
						|||
| 
								 | 
							
								            throw new KeyNotFoundException("Key \"" + key + "\" was not found in this ES3File. Use Load<T>(key, defaultValue) if you want to return a default value if the key does not exist.");
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        var unencryptedSettings = (ES3Settings)this.settings.Clone();
							 | 
						|||
| 
								 | 
							
								        unencryptedSettings.encryptionType = ES3.EncryptionType.None;
							 | 
						|||
| 
								 | 
							
								        unencryptedSettings.compressionType = ES3.CompressionType.None;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        if (typeof(T) == typeof(object))
							 | 
						|||
| 
								 | 
							
								            ES3.DeserializeInto(es3Data.type, es3Data.bytes, obj, unencryptedSettings);
							 | 
						|||
| 
								 | 
							
								        else
							 | 
						|||
| 
								 | 
							
								            ES3.DeserializeInto(es3Data.bytes, obj, unencryptedSettings);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    #endregion
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    #region Load Raw Methods
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Loads the ES3File as a raw, unencrypted, uncompressed byte array.</summary>
							 | 
						|||
| 
								 | 
							
								    public byte[] LoadRawBytes()
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        var unencryptedSettings = (ES3Settings)settings.Clone();
							 | 
						|||
| 
								 | 
							
								        unencryptedSettings.encryptionType = ES3.EncryptionType.None;
							 | 
						|||
| 
								 | 
							
								        unencryptedSettings.compressionType = ES3.CompressionType.None;
							 | 
						|||
| 
								 | 
							
								        return GetBytes(unencryptedSettings);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Loads the ES3File as a raw, unencrypted, uncompressed string, using the encoding defined in the ES3File's settings variable.</summary>
							 | 
						|||
| 
								 | 
							
								    public string LoadRawString()
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        if (cache.Count == 0)
							 | 
						|||
| 
								 | 
							
								            return "";
							 | 
						|||
| 
								 | 
							
								        return settings.encoding.GetString(LoadRawBytes());
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /*
							 | 
						|||
| 
								 | 
							
								     * Same as LoadRawString, except it will return an encrypted/compressed file if these are enabled.
							 | 
						|||
| 
								 | 
							
								     */
							 | 
						|||
| 
								 | 
							
								    internal byte[] GetBytes(ES3Settings settings = null)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        if (cache.Count == 0)
							 | 
						|||
| 
								 | 
							
								            return new byte[0];
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        if (settings == null)
							 | 
						|||
| 
								 | 
							
								            settings = this.settings;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        using (var ms = new System.IO.MemoryStream())
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            var memorySettings = (ES3Settings)settings.Clone();
							 | 
						|||
| 
								 | 
							
								            memorySettings.location = ES3.Location.InternalMS;
							 | 
						|||
| 
								 | 
							
								            // Ensure we return unencrypted bytes.
							 | 
						|||
| 
								 | 
							
								            memorySettings.encryptionType = ES3.EncryptionType.None;
							 | 
						|||
| 
								 | 
							
								            memorySettings.compressionType = ES3.CompressionType.None;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            using (var baseWriter = ES3Writer.Create(ES3Stream.CreateStream(ms, memorySettings, ES3FileMode.Write), memorySettings, true, false))
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                foreach (var kvp in cache)
							 | 
						|||
| 
								 | 
							
								                    baseWriter.Write(kvp.Key, kvp.Value.type.type, kvp.Value.bytes);
							 | 
						|||
| 
								 | 
							
								                baseWriter.Save(false);
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            return ms.ToArray();
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    #endregion
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    #region Other ES3 Methods
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Deletes a key from this ES3File.</summary>
							 | 
						|||
| 
								 | 
							
								    /// <param name="key">The key we want to delete.</param>
							 | 
						|||
| 
								 | 
							
								    public void DeleteKey(string key)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        cache.Remove(key);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Checks whether a key exists in this ES3File.</summary>
							 | 
						|||
| 
								 | 
							
								    /// <param name="key">The key we want to check the existence of.</param>
							 | 
						|||
| 
								 | 
							
								    /// <returns>True if the key exists, otherwise False.</returns>
							 | 
						|||
| 
								 | 
							
								    public bool KeyExists(string key)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        return cache.ContainsKey(key);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    /// <summary>Gets the size of the cached data in bytes.</summary>
							 | 
						|||
| 
								 | 
							
								    public int Size()
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        int size = 0;
							 | 
						|||
| 
								 | 
							
								        foreach (var kvp in cache)
							 | 
						|||
| 
								 | 
							
								            size += kvp.Value.bytes.Length;
							 | 
						|||
| 
								 | 
							
								        return size;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    public Type GetKeyType(string key)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        ES3Data es3data;
							 | 
						|||
| 
								 | 
							
								        if (!cache.TryGetValue(key, out es3data))
							 | 
						|||
| 
								 | 
							
								            throw new KeyNotFoundException("Key \"" + key + "\" was not found in this ES3File. Use Load<T>(key, defaultValue) if you want to return a default value if the key does not exist.");
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        return es3data.type.type;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    #endregion
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
							 | 
						|||
| 
								 | 
							
								    internal static ES3File GetOrCreateCachedFile(ES3Settings settings)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        ES3File cachedFile;
							 | 
						|||
| 
								 | 
							
								        if (!cachedFiles.TryGetValue(settings.path, out cachedFile))
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            cachedFile = new ES3File(settings, false);
							 | 
						|||
| 
								 | 
							
								            cachedFiles.Add(settings.path, cachedFile);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        // Settings might refer to the same file, but might have changed.
							 | 
						|||
| 
								 | 
							
								        // To account for this, we update the settings of the ES3File each time we access it.
							 | 
						|||
| 
								 | 
							
								        cachedFile.settings = settings;
							 | 
						|||
| 
								 | 
							
								        return cachedFile;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    internal static void CacheFile(ES3Settings settings)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        // If we're still using cached settings, default to file.
							 | 
						|||
| 
								 | 
							
								        if (settings.location == ES3.Location.Cache)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            settings = (ES3Settings)settings.Clone();
							 | 
						|||
| 
								 | 
							
								            settings.location = ES3.Location.File;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        if (!ES3.FileExists(settings))
							 | 
						|||
| 
								 | 
							
								            return;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        // Disable compression and encryption when loading the raw bytes, and the ES3File constructor will expect encrypted/compressed bytes.
							 | 
						|||
| 
								 | 
							
								        var loadSettings = (ES3Settings)settings.Clone();
							 | 
						|||
| 
								 | 
							
								        loadSettings.compressionType = ES3.CompressionType.None;
							 | 
						|||
| 
								 | 
							
								        loadSettings.encryptionType = ES3.EncryptionType.None;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        cachedFiles[settings.path] = new ES3File(ES3.LoadRawBytes(loadSettings), settings);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
							 | 
						|||
| 
								 | 
							
								    internal static void Store(ES3Settings settings = null)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        if (settings == null)
							 | 
						|||
| 
								 | 
							
								            settings = new ES3Settings(ES3.Location.File);
							 | 
						|||
| 
								 | 
							
								        // If we're still using cached settings, default to file.
							 | 
						|||
| 
								 | 
							
								        else if (settings.location == ES3.Location.Cache)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            settings = (ES3Settings)settings.Clone();
							 | 
						|||
| 
								 | 
							
								            settings.location = ES3.Location.File;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        ES3File cachedFile;
							 | 
						|||
| 
								 | 
							
								        if (!cachedFiles.TryGetValue(settings.path, out cachedFile))
							 | 
						|||
| 
								 | 
							
								            throw new FileNotFoundException("The file '" + settings.path + "' could not be stored because it could not be found in the cache.");
							 | 
						|||
| 
								 | 
							
								        cachedFile.Sync(settings);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
							 | 
						|||
| 
								 | 
							
								    internal static void RemoveCachedFile(ES3Settings settings)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        cachedFiles.Remove(settings.path);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
							 | 
						|||
| 
								 | 
							
								    internal static void CopyCachedFile(ES3Settings oldSettings, ES3Settings newSettings)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        ES3File cachedFile;
							 | 
						|||
| 
								 | 
							
								        if (!cachedFiles.TryGetValue(oldSettings.path, out cachedFile))
							 | 
						|||
| 
								 | 
							
								            throw new FileNotFoundException("The file '" + oldSettings.path + "' could not be copied because it could not be found in the cache.");
							 | 
						|||
| 
								 | 
							
								        if (cachedFiles.ContainsKey(newSettings.path))
							 | 
						|||
| 
								 | 
							
								            throw new InvalidOperationException("Cannot copy file '" + oldSettings.path + "' to '" + newSettings.path + "' because '" + newSettings.path + "' already exists");
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        cachedFiles.Add(newSettings.path, (ES3File)cachedFile.MemberwiseClone());
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
							 | 
						|||
| 
								 | 
							
								    internal static void DeleteKey(string key, ES3Settings settings)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        ES3File cachedFile;
							 | 
						|||
| 
								 | 
							
								        if (cachedFiles.TryGetValue(settings.path, out cachedFile))
							 | 
						|||
| 
								 | 
							
								            cachedFile.DeleteKey(key);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
							 | 
						|||
| 
								 | 
							
								    internal static bool KeyExists(string key, ES3Settings settings)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        ES3File cachedFile;
							 | 
						|||
| 
								 | 
							
								        if (cachedFiles.TryGetValue(settings.path, out cachedFile))
							 | 
						|||
| 
								 | 
							
								            return cachedFile.KeyExists(key);
							 | 
						|||
| 
								 | 
							
								        return false;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
							 | 
						|||
| 
								 | 
							
								    internal static bool FileExists(ES3Settings settings)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        return cachedFiles.ContainsKey(settings.path);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
							 | 
						|||
| 
								 | 
							
								    internal static string[] GetKeys(ES3Settings settings)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        ES3File cachedFile;
							 | 
						|||
| 
								 | 
							
								        if (!cachedFiles.TryGetValue(settings.path, out cachedFile))
							 | 
						|||
| 
								 | 
							
								            throw new FileNotFoundException("Could not get keys from the file '" + settings.path + "' because it could not be found in the cache.");
							 | 
						|||
| 
								 | 
							
								        return cachedFile.cache.Keys.ToArray();
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
							 | 
						|||
| 
								 | 
							
								    internal static string[] GetFiles()
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        return cachedFiles.Keys.ToArray();
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    internal static DateTime GetTimestamp(ES3Settings settings)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        ES3File cachedFile;
							 | 
						|||
| 
								 | 
							
								        if (!cachedFiles.TryGetValue(settings.path, out cachedFile))
							 | 
						|||
| 
								 | 
							
								            throw new FileNotFoundException("Could not get timestamp from the file '" + settings.path + "' because it could not be found in the cache.");
							 | 
						|||
| 
								 | 
							
								        return cachedFile.timestamp;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								namespace ES3Internal
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    public struct ES3Data
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        public ES3Type type;
							 | 
						|||
| 
								 | 
							
								        public byte[] bytes;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        public ES3Data(Type type, byte[] bytes)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            this.type = type == null ? null : ES3TypeMgr.GetOrCreateES3Type(type);
							 | 
						|||
| 
								 | 
							
								            this.bytes = bytes;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        public ES3Data(ES3Type type, byte[] bytes)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            this.type = type;
							 | 
						|||
| 
								 | 
							
								            this.bytes = bytes;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								}
							 |