using System.Collections;
using System.Collections.Generic;
using System.IO;
using System;
using ES3Types;
using UnityEngine;
using ES3Internal;
using System.Linq;
/// Represents a cached file which can be saved to and loaded from, and commited to storage when necessary.
public class ES3File
{
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public static Dictionary cachedFiles = new Dictionary();
public ES3Settings settings;
private Dictionary cache = new Dictionary();
private bool syncWithFile = false;
private DateTime timestamp = DateTime.UtcNow;
/// Creates a new ES3File and loads the default file into the ES3File if there is data to load.
public ES3File() : this(new ES3Settings(), true) { }
/// Creates a new ES3File and loads the specified file into the ES3File if there is data to load.
/// The relative or absolute path of the file in storage our ES3File is associated with.
public ES3File(string filePath) : this(new ES3Settings(filePath), true) { }
/// Creates a new ES3File and loads the specified file into the ES3File if there is data to load.
/// The relative or absolute path of the file in storage our ES3File is associated with.
/// The settings we want to use to override the default settings.
public ES3File(string filePath, ES3Settings settings) : this(new ES3Settings(filePath, settings), true) { }
/// Creates a new ES3File and loads the specified file into the ES3File if there is data to load.
/// The settings we want to use to override the default settings.
public ES3File(ES3Settings settings) : this(settings, true) { }
/// Creates a new ES3File and only loads the default file into it if syncWithFile is set to true.
/// Whether we should sync this ES3File with the one in storage immediately after creating it.
public ES3File(bool syncWithFile) : this(new ES3Settings(), syncWithFile) { }
/// Creates a new ES3File and only loads the specified file into it if syncWithFile is set to true.
/// The relative or absolute path of the file in storage our ES3File is associated with.
/// Whether we should sync this ES3File with the one in storage immediately after creating it.
public ES3File(string filePath, bool syncWithFile) : this(new ES3Settings(filePath), syncWithFile) { }
/// Creates a new ES3File and only loads the specified file into it if syncWithFile is set to true.
/// The relative or absolute path of the file in storage our ES3File is associated with.
/// The settings we want to use to override the default settings.
/// Whether we should sync this ES3File with the one in storage immediately after creating it.
public ES3File(string filePath, ES3Settings settings, bool syncWithFile) : this(new ES3Settings(filePath, settings), syncWithFile) { }
/// Creates a new ES3File and loads the specified file into the ES3File if there is data to load.
/// The settings we want to use to override the default settings.
/// Whether we should sync this ES3File with the one in storage immediately after creating it.
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 kvp in reader.RawEnumerator)
cache[kvp.Key] = kvp.Value;
}
timestamp = ES3.GetTimestamp(settingsWithTypeChecking);
}
}
/// Creates a new ES3File and loads the bytes into the ES3File. Note the bytes must represent that of a file.
/// The bytes representing our file.
/// The settings we want to use to override the default settings.
/// Whether we should sync this ES3File with the one in storage immediately after creating it.
public ES3File(byte[] bytes, ES3Settings settings = null)
{
if (settings == null)
this.settings = new ES3Settings();
else
this.settings = settings;
syncWithFile = true; // This ensures that the file won't be merged, which would prevent deleted keys from being deleted.
SaveRaw(bytes, settings);
}
/// Synchronises this ES3File with a file in storage.
public void Sync()
{
Sync(this.settings);
}
/// Synchronises this ES3File with a file in storage.
/// The relative or absolute path of the file in storage we want to synchronise with.
/// The settings we want to use to override the default settings.
public void Sync(string filePath, ES3Settings settings = null)
{
Sync(new ES3Settings(filePath, settings));
}
/// Synchronises this ES3File with a file in storage.
/// The settings we want to use to override the default settings.
public void Sync(ES3Settings settings = null)
{
if (settings == null)
settings = new ES3Settings();
if (cache.Count == 0)
{
ES3.DeleteFile(settings);
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);
}
}
/// Removes the data stored in this ES3File. The ES3File will be empty after calling this method.
public void Clear()
{
cache.Clear();
}
/// Returns an array of all of the key names in this ES3File.
public string[] GetKeys()
{
var keyCollection = cache.Keys;
var keys = new string[keyCollection.Count];
keyCollection.CopyTo(keys, 0);
return keys;
}
#region Save Methods
/// Saves a value to a key in this ES3File.
/// The key we want to use to identify our value in the file.
/// The value we want to save.
public void Save(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.
Type type;
if (value == null)
type = typeof(T);
else
type = value.GetType();
ES3Type es3Type = ES3TypeMgr.GetOrCreateES3Type(type);
cache[key] = new ES3Data(es3Type, ES3.Serialize(value, es3Type, unencryptedSettings));
}
/// Merges the data specified by the bytes parameter into this ES3File.
/// The bytes we want to merge with this ES3File.
/// The settings we want to use to override the default settings.
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 kvp in reader.RawEnumerator)
cache[kvp.Key] = kvp.Value;
}
}
/// Merges the data specified by the bytes parameter into this ES3File.
/// The bytes we want to merge with this ES3File.
/// The settings we want to use to override the default settings.
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 */
/// Loads the value from this ES3File with the given key.
/// The key which identifies the value we want to load.
public object Load(string key)
{
return Load