BS 0.0.1 EasySave完成
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
using System;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class EasySaved : Attribute{}
|
||||
namespace Convention.EasySave
|
||||
{
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class EasySaveIgnored : Attribute { }
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class EasySaved : Attribute { }
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class EasySaveIgnored : Attribute { }
|
||||
}
|
@@ -2,6 +2,7 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Convention.EasySave.Internal;
|
||||
using Convention.EasySave.Types;
|
||||
|
||||
namespace Convention.EasySave
|
||||
{
|
||||
@@ -260,81 +261,6 @@ namespace Convention.EasySave
|
||||
stream.Write(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
/// <summary>Saves a Texture2D as a PNG or JPG, depending on the file extension used for the filePath.</summary>
|
||||
/// <param name="texture">The Texture2D we want to save as a JPG or PNG.</param>
|
||||
/// <param name="imagePath">The relative or absolute path of the PNG or JPG file we want to create.</param>
|
||||
public static void SaveImage(Texture2D texture, string imagePath)
|
||||
{
|
||||
SaveImage(texture, new EasySaveSettings(imagePath));
|
||||
}
|
||||
|
||||
/// <summary>Saves a Texture2D as a PNG or JPG, depending on the file extension used for the filePath.</summary>
|
||||
/// <param name="texture">The Texture2D we want to save as a JPG or PNG.</param>
|
||||
/// <param name="imagePath">The relative or absolute path of the PNG or JPG file we want to create.</param>
|
||||
public static void SaveImage(Texture2D texture, string imagePath, EasySaveSettings settings)
|
||||
{
|
||||
SaveImage(texture, new EasySaveSettings(imagePath, settings));
|
||||
}
|
||||
|
||||
/// <summary>Saves a Texture2D as a PNG or JPG, depending on the file extension used for the filePath.</summary>
|
||||
/// <param name="texture">The Texture2D we want to save as a JPG or PNG.</param>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public static void SaveImage(Texture2D texture, EasySaveSettings settings)
|
||||
{
|
||||
SaveImage(texture, 75, settings);
|
||||
}
|
||||
|
||||
/// <summary>Saves a Texture2D as a PNG or JPG, depending on the file extension used for the filePath.</summary>
|
||||
/// <param name="texture">The Texture2D we want to save as a JPG or PNG.</param>
|
||||
/// <param name="quality">Quality to encode with, where 1 is minimum and 100 is maximum. Note that this only applies to JPGs.</param>
|
||||
/// <param name="imagePath">The relative or absolute path of the PNG or JPG file we want to create.</param>
|
||||
public static void SaveImage(Texture2D texture, int quality, string imagePath)
|
||||
{
|
||||
SaveImage(texture, quality, new EasySaveSettings(imagePath));
|
||||
}
|
||||
|
||||
/// <summary>Saves a Texture2D as a PNG or JPG, depending on the file extension used for the filePath.</summary>
|
||||
/// <param name="texture">The Texture2D we want to save as a JPG or PNG.</param>
|
||||
/// <param name="quality">Quality to encode with, where 1 is minimum and 100 is maximum. Note that this only applies to JPGs.</param>
|
||||
/// <param name="imagePath">The relative or absolute path of the PNG or JPG file we want to create.</param>
|
||||
public static void SaveImage(Texture2D texture, int quality, string imagePath, EasySaveSettings settings)
|
||||
{
|
||||
SaveImage(texture, quality, new EasySaveSettings(imagePath, settings));
|
||||
}
|
||||
|
||||
/// <summary>Saves a Texture2D as a PNG or JPG, depending on the file extension used for the filePath.</summary>
|
||||
/// <param name="texture">The Texture2D we want to save as a JPG or PNG.</param>
|
||||
/// <param name="quality">Quality to encode with, where 1 is minimum and 100 is maximum. Note that this only applies to JPGs.</param>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public static void SaveImage(Texture2D texture, int quality, EasySaveSettings settings)
|
||||
{
|
||||
// Get the file extension to determine what format we want to save the image as.
|
||||
string extension = EasySaveIO.GetExtension(settings.path).ToLower();
|
||||
if (string.IsNullOrEmpty(extension))
|
||||
throw new System.ArgumentException("File path must have a file extension when using EasySave.SaveImage.");
|
||||
byte[] bytes;
|
||||
if (extension == ".jpg" || extension == ".jpeg")
|
||||
bytes = texture.EncodeToJPG(quality);
|
||||
else if (extension == ".png")
|
||||
bytes = texture.EncodeToPNG();
|
||||
else
|
||||
throw new System.ArgumentException("File path must have extension of .png, .jpg or .jpeg when using EasySave.SaveImage.");
|
||||
|
||||
EasySave.SaveRaw(bytes, settings);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Saves a Texture2D as a PNG or JPG, depending on the file extension used for the filePath.</summary>
|
||||
/// <param name="texture">The Texture2D we want to save as a JPG or PNG.</param>
|
||||
/// <param name="quality">Quality to encode with, where 1 is minimum and 100 is maximum. Note that this only applies to JPGs.</param>
|
||||
public static byte[] SaveImageToBytes(Texture2D texture, int quality, EasySave.ImageType imageType)
|
||||
{
|
||||
if (imageType == ImageType.JPEG)
|
||||
return texture.EncodeToJPG(quality);
|
||||
else
|
||||
return texture.EncodeToPNG();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region EasySave.Load<T>
|
||||
@@ -720,7 +646,7 @@ namespace Convention.EasySave
|
||||
return Serialize(value, EasySaveTypeMgr.GetOrCreateEasySaveType(typeof(T)), settings);
|
||||
}
|
||||
|
||||
internal static byte[] Serialize(object value, Convention.EasySave.Types.EasySaveType type, EasySaveSettings settings = null)
|
||||
internal static byte[] Serialize(object value, EasySaveType type, EasySaveSettings settings = null)
|
||||
{
|
||||
if (settings == null) settings = new EasySaveSettings();
|
||||
|
||||
@@ -745,7 +671,7 @@ namespace Convention.EasySave
|
||||
return (T)Deserialize(EasySaveTypeMgr.GetOrCreateEasySaveType(typeof(T)), bytes, settings);
|
||||
}
|
||||
|
||||
internal static object Deserialize(Convention.EasySave.Types.EasySaveType type, byte[] bytes, EasySaveSettings settings = null)
|
||||
internal static object Deserialize(EasySaveType type, byte[] bytes, EasySaveSettings settings = null)
|
||||
{
|
||||
if (settings == null)
|
||||
settings = new EasySaveSettings();
|
||||
@@ -761,7 +687,7 @@ namespace Convention.EasySave
|
||||
DeserializeInto(EasySaveTypeMgr.GetOrCreateEasySaveType(typeof(T)), bytes, obj, settings);
|
||||
}
|
||||
|
||||
public static void DeserializeInto<T>(Convention.EasySave.Types.EasySaveType type, byte[] bytes, T obj, EasySaveSettings settings = null) where T : class
|
||||
public static void DeserializeInto<T>(EasySaveType type, byte[] bytes, T obj, EasySaveSettings settings = null) where T : class
|
||||
{
|
||||
if (settings == null)
|
||||
settings = new EasySaveSettings();
|
||||
|
@@ -6,510 +6,514 @@ using Convention.EasySave.Types;
|
||||
using Convention.EasySave.Internal;
|
||||
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 EasySaveFile
|
||||
namespace Convention.EasySave
|
||||
{
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public static Dictionary<string, EasySaveFile> cachedFiles = new Dictionary<string, EasySaveFile>();
|
||||
|
||||
public EasySaveSettings settings;
|
||||
private Dictionary<string, EasySaveData> cache = new Dictionary<string, EasySaveData>();
|
||||
private bool syncWithFile = false;
|
||||
private DateTime timestamp = DateTime.UtcNow;
|
||||
|
||||
/// <summary>Creates a new EasySaveFile and loads the default file into the EasySaveFile if there is data to load.</summary>
|
||||
public EasySaveFile() : this(new EasySaveSettings(), true) { }
|
||||
|
||||
/// <summary>Creates a new EasySaveFile and loads the specified file into the EasySaveFile if there is data to load.</summary>
|
||||
/// <param name="filepath">The relative or absolute path of the file in storage our EasySaveFile is associated with.</param>
|
||||
public EasySaveFile(string filePath) : this(new EasySaveSettings(filePath), true) { }
|
||||
|
||||
/// <summary>Creates a new EasySaveFile and loads the specified file into the EasySaveFile if there is data to load.</summary>
|
||||
/// <param name="filepath">The relative or absolute path of the file in storage our EasySaveFile is associated with.</param>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public EasySaveFile(string filePath, EasySaveSettings settings) : this(new EasySaveSettings(filePath, settings), true) { }
|
||||
|
||||
/// <summary>Creates a new EasySaveFile and loads the specified file into the EasySaveFile if there is data to load.</summary>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public EasySaveFile(EasySaveSettings settings) : this(settings, true) { }
|
||||
|
||||
/// <summary>Creates a new EasySaveFile and only loads the default file into it if syncWithFile is set to true.</summary>
|
||||
/// <param name="syncWithFile">Whether we should sync this EasySaveFile with the one in storage immediately after creating it.</param>
|
||||
public EasySaveFile(bool syncWithFile) : this(new EasySaveSettings(), syncWithFile) { }
|
||||
/// <summary>Creates a new EasySaveFile 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 EasySaveFile is associated with.</param>
|
||||
/// <param name="syncWithFile">Whether we should sync this EasySaveFile with the one in storage immediately after creating it.</param>
|
||||
public EasySaveFile(string filePath, bool syncWithFile) : this(new EasySaveSettings(filePath), syncWithFile) { }
|
||||
/// <summary>Creates a new EasySaveFile 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 EasySaveFile 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 EasySaveFile with the one in storage immediately after creating it.</param>
|
||||
public EasySaveFile(string filePath, EasySaveSettings settings, bool syncWithFile) : this(new EasySaveSettings(filePath, settings), syncWithFile) { }
|
||||
|
||||
/// <summary>Creates a new EasySaveFile and loads the specified file into the EasySaveFile 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 EasySaveFile with the one in storage immediately after creating it.</param>
|
||||
public EasySaveFile(EasySaveSettings settings, bool syncWithFile)
|
||||
/// <summary>Represents a cached file which can be saved to and loaded from, and commited to storage when necessary.</summary>
|
||||
public class EasySaveFile
|
||||
{
|
||||
this.settings = settings;
|
||||
this.syncWithFile = syncWithFile;
|
||||
if (syncWithFile)
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public static Dictionary<string, EasySaveFile> cachedFiles = new Dictionary<string, EasySaveFile>();
|
||||
|
||||
public EasySaveSettings settings;
|
||||
private Dictionary<string, EasySaveData> cache = new Dictionary<string, EasySaveData>();
|
||||
private bool syncWithFile = false;
|
||||
private DateTime timestamp = DateTime.UtcNow;
|
||||
|
||||
/// <summary>Creates a new EasySaveFile and loads the default file into the EasySaveFile if there is data to load.</summary>
|
||||
public EasySaveFile() : this(new EasySaveSettings(), true) { }
|
||||
|
||||
/// <summary>Creates a new EasySaveFile and loads the specified file into the EasySaveFile if there is data to load.</summary>
|
||||
/// <param name="filepath">The relative or absolute path of the file in storage our EasySaveFile is associated with.</param>
|
||||
public EasySaveFile(string filePath) : this(new EasySaveSettings(filePath), true) { }
|
||||
|
||||
/// <summary>Creates a new EasySaveFile and loads the specified file into the EasySaveFile if there is data to load.</summary>
|
||||
/// <param name="filepath">The relative or absolute path of the file in storage our EasySaveFile is associated with.</param>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public EasySaveFile(string filePath, EasySaveSettings settings) : this(new EasySaveSettings(filePath, settings), true) { }
|
||||
|
||||
/// <summary>Creates a new EasySaveFile and loads the specified file into the EasySaveFile if there is data to load.</summary>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public EasySaveFile(EasySaveSettings settings) : this(settings, true) { }
|
||||
|
||||
/// <summary>Creates a new EasySaveFile and only loads the default file into it if syncWithFile is set to true.</summary>
|
||||
/// <param name="syncWithFile">Whether we should sync this EasySaveFile with the one in storage immediately after creating it.</param>
|
||||
public EasySaveFile(bool syncWithFile) : this(new EasySaveSettings(), syncWithFile) { }
|
||||
/// <summary>Creates a new EasySaveFile 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 EasySaveFile is associated with.</param>
|
||||
/// <param name="syncWithFile">Whether we should sync this EasySaveFile with the one in storage immediately after creating it.</param>
|
||||
public EasySaveFile(string filePath, bool syncWithFile) : this(new EasySaveSettings(filePath), syncWithFile) { }
|
||||
/// <summary>Creates a new EasySaveFile 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 EasySaveFile 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 EasySaveFile with the one in storage immediately after creating it.</param>
|
||||
public EasySaveFile(string filePath, EasySaveSettings settings, bool syncWithFile) : this(new EasySaveSettings(filePath, settings), syncWithFile) { }
|
||||
|
||||
/// <summary>Creates a new EasySaveFile and loads the specified file into the EasySaveFile 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 EasySaveFile with the one in storage immediately after creating it.</param>
|
||||
public EasySaveFile(EasySaveSettings settings, bool syncWithFile)
|
||||
{
|
||||
this.settings = settings;
|
||||
this.syncWithFile = syncWithFile;
|
||||
if (syncWithFile)
|
||||
{
|
||||
// Type checking must be enabled when syncing.
|
||||
var settingsWithTypeChecking = (EasySaveSettings)settings.Clone();
|
||||
settingsWithTypeChecking.typeChecking = true;
|
||||
|
||||
using (var reader = EasySaveReader.Create(settingsWithTypeChecking))
|
||||
{
|
||||
if (reader == null)
|
||||
return;
|
||||
foreach (KeyValuePair<string, EasySaveData> kvp in reader.RawEnumerator)
|
||||
cache[kvp.Key] = kvp.Value;
|
||||
}
|
||||
|
||||
timestamp = EasySave.GetTimestamp(settingsWithTypeChecking);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Creates a new EasySaveFile and loads the bytes into the EasySaveFile. 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 EasySaveFile with the one in storage immediately after creating it.</param>
|
||||
public EasySaveFile(byte[] bytes, EasySaveSettings settings = null)
|
||||
{
|
||||
if (settings == null)
|
||||
this.settings = new EasySaveSettings();
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>Synchronises this EasySaveFile with a file in storage.</summary>
|
||||
public void Sync()
|
||||
{
|
||||
Sync(this.settings);
|
||||
}
|
||||
|
||||
/// <summary>Synchronises this EasySaveFile 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, EasySaveSettings settings = null)
|
||||
{
|
||||
Sync(new EasySaveSettings(filePath, settings));
|
||||
}
|
||||
|
||||
/// <summary>Synchronises this EasySaveFile with a file in storage.</summary>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public void Sync(EasySaveSettings settings = null)
|
||||
{
|
||||
if (settings == null)
|
||||
settings = new EasySaveSettings();
|
||||
|
||||
if (cache.Count == 0)
|
||||
{
|
||||
EasySave.DeleteFile(settings);
|
||||
return;
|
||||
}
|
||||
|
||||
using (var baseWriter = EasySaveWriter.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 EasySaveFile. The EasySaveFile 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 EasySaveFile.</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 EasySaveFile.</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 = (EasySaveSettings)settings.Clone();
|
||||
unencryptedSettings.encryptionType = EasySave.EncryptionType.None;
|
||||
unencryptedSettings.compressionType = EasySave.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();
|
||||
|
||||
cache[key] = new EasySaveData(EasySaveTypeMgr.GetOrCreateEasySaveType(type), EasySave.Serialize(value, unencryptedSettings));
|
||||
}
|
||||
|
||||
/// <summary>Merges the data specified by the bytes parameter into this EasySaveFile.</summary>
|
||||
/// <param name="bytes">The bytes we want to merge with this EasySaveFile.</param>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public void SaveRaw(byte[] bytes, EasySaveSettings settings = null)
|
||||
{
|
||||
if (settings == null)
|
||||
settings = new EasySaveSettings();
|
||||
|
||||
// Type checking must be enabled when syncing.
|
||||
var settingsWithTypeChecking = (EasySaveSettings)settings.Clone();
|
||||
settingsWithTypeChecking.typeChecking = true;
|
||||
|
||||
using (var reader = EasySaveReader.Create(settingsWithTypeChecking))
|
||||
using (var reader = EasySaveReader.Create(bytes, settingsWithTypeChecking))
|
||||
{
|
||||
if (reader == null)
|
||||
return;
|
||||
foreach (KeyValuePair<string, EasySaveData> kvp in reader.RawEnumerator)
|
||||
cache[kvp.Key] = kvp.Value;
|
||||
}
|
||||
|
||||
timestamp = EasySave.GetTimestamp(settingsWithTypeChecking);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Creates a new EasySaveFile and loads the bytes into the EasySaveFile. 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 EasySaveFile with the one in storage immediately after creating it.</param>
|
||||
public EasySaveFile(byte[] bytes, EasySaveSettings settings = null)
|
||||
{
|
||||
if (settings == null)
|
||||
this.settings = new EasySaveSettings();
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>Synchronises this EasySaveFile with a file in storage.</summary>
|
||||
public void Sync()
|
||||
{
|
||||
Sync(this.settings);
|
||||
}
|
||||
|
||||
/// <summary>Synchronises this EasySaveFile 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, EasySaveSettings settings = null)
|
||||
{
|
||||
Sync(new EasySaveSettings(filePath, settings));
|
||||
}
|
||||
|
||||
/// <summary>Synchronises this EasySaveFile with a file in storage.</summary>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public void Sync(EasySaveSettings settings = null)
|
||||
{
|
||||
if (settings == null)
|
||||
settings = new EasySaveSettings();
|
||||
|
||||
if (cache.Count == 0)
|
||||
{
|
||||
EasySave.DeleteFile(settings);
|
||||
return;
|
||||
}
|
||||
|
||||
using (var baseWriter = EasySaveWriter.Create(settings, true, !syncWithFile, false))
|
||||
/// <summary>Merges the data specified by the bytes parameter into this EasySaveFile.</summary>
|
||||
/// <param name="bytes">The bytes we want to merge with this EasySaveFile.</param>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public void AppendRaw(byte[] bytes, EasySaveSettings settings = null)
|
||||
{
|
||||
if (settings == null)
|
||||
settings = new EasySaveSettings();
|
||||
// AppendRaw just does the same thing as SaveRaw in EasySaveFile.
|
||||
SaveRaw(bytes, settings);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Load Methods
|
||||
|
||||
/* Standard load methods */
|
||||
|
||||
/// <summary>Loads the value from this EasySaveFile 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 EasySaveFile 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 EasySaveFile.</param>
|
||||
public object Load(string key, object defaultValue)
|
||||
{
|
||||
return Load<object>(key, defaultValue);
|
||||
}
|
||||
|
||||
/// <summary>Loads the value from this EasySaveFile 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)
|
||||
{
|
||||
EasySaveData es3Data;
|
||||
|
||||
if (!cache.TryGetValue(key, out es3Data))
|
||||
throw new KeyNotFoundException("Key \"" + key + "\" was not found in this EasySaveFile. Use Load<T>(key, defaultValue) if you want to return a default value if the key does not exist.");
|
||||
|
||||
var unencryptedSettings = (EasySaveSettings)this.settings.Clone();
|
||||
unencryptedSettings.encryptionType = EasySave.EncryptionType.None;
|
||||
unencryptedSettings.compressionType = EasySave.CompressionType.None;
|
||||
|
||||
if (typeof(T) == typeof(object))
|
||||
return (T)EasySave.Deserialize(es3Data.type, es3Data.bytes, unencryptedSettings);
|
||||
return EasySave.Deserialize<T>(es3Data.bytes, unencryptedSettings);
|
||||
}
|
||||
|
||||
/// <summary>Loads the value from this EasySaveFile 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 EasySaveFile.</param>
|
||||
public T Load<T>(string key, T defaultValue)
|
||||
{
|
||||
EasySaveData es3Data;
|
||||
|
||||
if (!cache.TryGetValue(key, out es3Data))
|
||||
return defaultValue;
|
||||
var unencryptedSettings = (EasySaveSettings)this.settings.Clone();
|
||||
unencryptedSettings.encryptionType = EasySave.EncryptionType.None;
|
||||
unencryptedSettings.compressionType = EasySave.CompressionType.None;
|
||||
|
||||
if (typeof(T) == typeof(object))
|
||||
return (T)EasySave.Deserialize(es3Data.type, es3Data.bytes, unencryptedSettings);
|
||||
return EasySave.Deserialize<T>(es3Data.bytes, unencryptedSettings);
|
||||
}
|
||||
|
||||
/// <summary>Loads the value from this EasySaveFile 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
|
||||
{
|
||||
EasySaveData es3Data;
|
||||
|
||||
if (!cache.TryGetValue(key, out es3Data))
|
||||
throw new KeyNotFoundException("Key \"" + key + "\" was not found in this EasySaveFile. Use Load<T>(key, defaultValue) if you want to return a default value if the key does not exist.");
|
||||
|
||||
var unencryptedSettings = (EasySaveSettings)this.settings.Clone();
|
||||
unencryptedSettings.encryptionType = EasySave.EncryptionType.None;
|
||||
unencryptedSettings.compressionType = EasySave.CompressionType.None;
|
||||
|
||||
if (typeof(T) == typeof(object))
|
||||
EasySave.DeserializeInto(es3Data.type, es3Data.bytes, obj, unencryptedSettings);
|
||||
else
|
||||
EasySave.DeserializeInto(es3Data.bytes, obj, unencryptedSettings);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Load Raw Methods
|
||||
|
||||
/// <summary>Loads the EasySaveFile as a raw, unencrypted, uncompressed byte array.</summary>
|
||||
public byte[] LoadRawBytes()
|
||||
{
|
||||
var newSettings = (EasySaveSettings)settings.Clone();
|
||||
if (!newSettings.postprocessRawCachedData)
|
||||
{
|
||||
newSettings.encryptionType = EasySave.EncryptionType.None;
|
||||
newSettings.compressionType = EasySave.CompressionType.None;
|
||||
}
|
||||
return GetBytes(newSettings);
|
||||
}
|
||||
|
||||
/// <summary>Loads the EasySaveFile as a raw, unencrypted, uncompressed string, using the encoding defined in the EasySaveFile'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(EasySaveSettings 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 = (EasySaveSettings)settings.Clone();
|
||||
memorySettings.location = EasySave.Location.InternalMS;
|
||||
// Ensure we return unencrypted bytes.
|
||||
if (!memorySettings.postprocessRawCachedData)
|
||||
{
|
||||
memorySettings.encryptionType = EasySave.EncryptionType.None;
|
||||
memorySettings.compressionType = EasySave.CompressionType.None;
|
||||
}
|
||||
|
||||
using (var baseWriter = EasySaveWriter.Create(EasySaveStream.CreateStream(ms, memorySettings, EasySaveFileMode.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 EasySave Methods
|
||||
|
||||
/// <summary>Deletes a key from this EasySaveFile.</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 EasySaveFile.</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)
|
||||
{
|
||||
// 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);
|
||||
size += kvp.Value.bytes.Length;
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Removes the data stored in this EasySaveFile. The EasySaveFile 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 EasySaveFile.</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 EasySaveFile.</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 = (EasySaveSettings)settings.Clone();
|
||||
unencryptedSettings.encryptionType = EasySave.EncryptionType.None;
|
||||
unencryptedSettings.compressionType = EasySave.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();
|
||||
|
||||
cache[key] = new EasySaveData(EasySaveTypeMgr.GetOrCreateEasySaveType(type), EasySave.Serialize(value, unencryptedSettings));
|
||||
}
|
||||
|
||||
/// <summary>Merges the data specified by the bytes parameter into this EasySaveFile.</summary>
|
||||
/// <param name="bytes">The bytes we want to merge with this EasySaveFile.</param>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public void SaveRaw(byte[] bytes, EasySaveSettings settings = null)
|
||||
{
|
||||
if (settings == null)
|
||||
settings = new EasySaveSettings();
|
||||
|
||||
// Type checking must be enabled when syncing.
|
||||
var settingsWithTypeChecking = (EasySaveSettings)settings.Clone();
|
||||
settingsWithTypeChecking.typeChecking = true;
|
||||
|
||||
using (var reader = EasySaveReader.Create(bytes, settingsWithTypeChecking))
|
||||
public Type GetKeyType(string key)
|
||||
{
|
||||
if (reader == null)
|
||||
EasySaveData es3data;
|
||||
if (!cache.TryGetValue(key, out es3data))
|
||||
throw new KeyNotFoundException("Key \"" + key + "\" was not found in this EasySaveFile. 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 EasySaveFile GetOrCreateCachedFile(EasySaveSettings settings)
|
||||
{
|
||||
EasySaveFile cachedFile;
|
||||
if (!cachedFiles.TryGetValue(settings.path, out cachedFile))
|
||||
{
|
||||
cachedFile = new EasySaveFile(settings, false);
|
||||
cachedFiles.Add(settings.path, cachedFile);
|
||||
cachedFile.syncWithFile = true; // This ensures that the file won't be merged, which would prevent deleted keys from being deleted.
|
||||
}
|
||||
// Settings might refer to the same file, but might have changed.
|
||||
// To account for this, we update the settings of the EasySaveFile each time we access it.
|
||||
cachedFile.settings = settings;
|
||||
return cachedFile;
|
||||
}
|
||||
|
||||
internal static void CacheFile(EasySaveSettings settings)
|
||||
{
|
||||
// If we're still using cached settings, set it to the default location.
|
||||
if (settings.location == EasySave.Location.Cache)
|
||||
{
|
||||
settings = (EasySaveSettings)settings.Clone();
|
||||
// If the default settings are also set to cache, assume EasySave.Location.File. Otherwise, set it to the default location.
|
||||
settings.location = EasySaveSettings.defaultSettings.location == EasySave.Location.Cache ? EasySave.Location.File : EasySaveSettings.defaultSettings.location;
|
||||
}
|
||||
|
||||
if (!EasySave.FileExists(settings))
|
||||
return;
|
||||
foreach (KeyValuePair<string, EasySaveData> kvp in reader.RawEnumerator)
|
||||
cache[kvp.Key] = kvp.Value;
|
||||
|
||||
// Disable compression and encryption when loading the raw bytes, and the EasySaveFile constructor will expect encrypted/compressed bytes.
|
||||
var loadSettings = (EasySaveSettings)settings.Clone();
|
||||
loadSettings.compressionType = EasySave.CompressionType.None;
|
||||
loadSettings.encryptionType = EasySave.EncryptionType.None;
|
||||
|
||||
cachedFiles[settings.path] = new EasySaveFile(EasySave.LoadRawBytes(loadSettings), settings);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Merges the data specified by the bytes parameter into this EasySaveFile.</summary>
|
||||
/// <param name="bytes">The bytes we want to merge with this EasySaveFile.</param>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public void AppendRaw(byte[] bytes, EasySaveSettings settings = null)
|
||||
{
|
||||
if (settings == null)
|
||||
settings = new EasySaveSettings();
|
||||
// AppendRaw just does the same thing as SaveRaw in EasySaveFile.
|
||||
SaveRaw(bytes, settings);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Load Methods
|
||||
|
||||
/* Standard load methods */
|
||||
|
||||
/// <summary>Loads the value from this EasySaveFile 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 EasySaveFile 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 EasySaveFile.</param>
|
||||
public object Load(string key, object defaultValue)
|
||||
{
|
||||
return Load<object>(key, defaultValue);
|
||||
}
|
||||
|
||||
/// <summary>Loads the value from this EasySaveFile 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)
|
||||
{
|
||||
EasySaveData es3Data;
|
||||
|
||||
if (!cache.TryGetValue(key, out es3Data))
|
||||
throw new KeyNotFoundException("Key \"" + key + "\" was not found in this EasySaveFile. Use Load<T>(key, defaultValue) if you want to return a default value if the key does not exist.");
|
||||
|
||||
var unencryptedSettings = (EasySaveSettings)this.settings.Clone();
|
||||
unencryptedSettings.encryptionType = EasySave.EncryptionType.None;
|
||||
unencryptedSettings.compressionType = EasySave.CompressionType.None;
|
||||
|
||||
if (typeof(T) == typeof(object))
|
||||
return (T)EasySave.Deserialize(es3Data.type, es3Data.bytes, unencryptedSettings);
|
||||
return EasySave.Deserialize<T>(es3Data.bytes, unencryptedSettings);
|
||||
}
|
||||
|
||||
/// <summary>Loads the value from this EasySaveFile 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 EasySaveFile.</param>
|
||||
public T Load<T>(string key, T defaultValue)
|
||||
{
|
||||
EasySaveData es3Data;
|
||||
|
||||
if (!cache.TryGetValue(key, out es3Data))
|
||||
return defaultValue;
|
||||
var unencryptedSettings = (EasySaveSettings)this.settings.Clone();
|
||||
unencryptedSettings.encryptionType = EasySave.EncryptionType.None;
|
||||
unencryptedSettings.compressionType = EasySave.CompressionType.None;
|
||||
|
||||
if (typeof(T) == typeof(object))
|
||||
return (T)EasySave.Deserialize(es3Data.type, es3Data.bytes, unencryptedSettings);
|
||||
return EasySave.Deserialize<T>(es3Data.bytes, unencryptedSettings);
|
||||
}
|
||||
|
||||
/// <summary>Loads the value from this EasySaveFile 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
|
||||
{
|
||||
EasySaveData es3Data;
|
||||
|
||||
if (!cache.TryGetValue(key, out es3Data))
|
||||
throw new KeyNotFoundException("Key \"" + key + "\" was not found in this EasySaveFile. Use Load<T>(key, defaultValue) if you want to return a default value if the key does not exist.");
|
||||
|
||||
var unencryptedSettings = (EasySaveSettings)this.settings.Clone();
|
||||
unencryptedSettings.encryptionType = EasySave.EncryptionType.None;
|
||||
unencryptedSettings.compressionType = EasySave.CompressionType.None;
|
||||
|
||||
if (typeof(T) == typeof(object))
|
||||
EasySave.DeserializeInto(es3Data.type, es3Data.bytes, obj, unencryptedSettings);
|
||||
else
|
||||
EasySave.DeserializeInto(es3Data.bytes, obj, unencryptedSettings);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Load Raw Methods
|
||||
|
||||
/// <summary>Loads the EasySaveFile as a raw, unencrypted, uncompressed byte array.</summary>
|
||||
public byte[] LoadRawBytes()
|
||||
{
|
||||
var newSettings = (EasySaveSettings)settings.Clone();
|
||||
if (!newSettings.postprocessRawCachedData)
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
internal static void Store(EasySaveSettings settings = null)
|
||||
{
|
||||
newSettings.encryptionType = EasySave.EncryptionType.None;
|
||||
newSettings.compressionType = EasySave.CompressionType.None;
|
||||
}
|
||||
return GetBytes(newSettings);
|
||||
}
|
||||
|
||||
/// <summary>Loads the EasySaveFile as a raw, unencrypted, uncompressed string, using the encoding defined in the EasySaveFile'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(EasySaveSettings 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 = (EasySaveSettings)settings.Clone();
|
||||
memorySettings.location = EasySave.Location.InternalMS;
|
||||
// Ensure we return unencrypted bytes.
|
||||
if (!memorySettings.postprocessRawCachedData)
|
||||
if (settings == null)
|
||||
settings = new EasySaveSettings(EasySave.Location.File);
|
||||
// If we're still using cached settings, set it to the default location.
|
||||
else if (settings.location == EasySave.Location.Cache)
|
||||
{
|
||||
memorySettings.encryptionType = EasySave.EncryptionType.None;
|
||||
memorySettings.compressionType = EasySave.CompressionType.None;
|
||||
settings = (EasySaveSettings)settings.Clone();
|
||||
// If the default settings are also set to cache, assume EasySave.Location.File. Otherwise, set it to the default location.
|
||||
settings.location = EasySaveSettings.defaultSettings.location == EasySave.Location.Cache ? EasySave.Location.File : EasySaveSettings.defaultSettings.location;
|
||||
}
|
||||
|
||||
using (var baseWriter = EasySaveWriter.Create(EasySaveStream.CreateStream(ms, memorySettings, EasySaveFileMode.Write), memorySettings, true, false))
|
||||
EasySaveFile 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(EasySaveSettings settings)
|
||||
{
|
||||
cachedFiles.Remove(settings.path);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
internal static void CopyCachedFile(EasySaveSettings oldSettings, EasySaveSettings newSettings)
|
||||
{
|
||||
EasySaveFile 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, (EasySaveFile)cachedFile.MemberwiseClone());
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
internal static void DeleteKey(string key, EasySaveSettings settings)
|
||||
{
|
||||
EasySaveFile cachedFile;
|
||||
if (cachedFiles.TryGetValue(settings.path, out cachedFile))
|
||||
cachedFile.DeleteKey(key);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
internal static bool KeyExists(string key, EasySaveSettings settings)
|
||||
{
|
||||
EasySaveFile 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(EasySaveSettings settings)
|
||||
{
|
||||
return cachedFiles.ContainsKey(settings.path);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
internal static string[] GetKeys(EasySaveSettings settings)
|
||||
{
|
||||
EasySaveFile 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(EasySaveSettings settings)
|
||||
{
|
||||
EasySaveFile cachedFile;
|
||||
if (!cachedFiles.TryGetValue(settings.path, out cachedFile))
|
||||
return new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
|
||||
return cachedFile.timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Internal
|
||||
{
|
||||
public struct EasySaveData
|
||||
{
|
||||
public EasySaveType type;
|
||||
public byte[] bytes;
|
||||
|
||||
public EasySaveData(Type type, byte[] bytes)
|
||||
{
|
||||
foreach (var kvp in cache)
|
||||
baseWriter.Write(kvp.Key, kvp.Value.type.type, kvp.Value.bytes);
|
||||
baseWriter.Save(false);
|
||||
this.type = type == null ? null : EasySaveTypeMgr.GetOrCreateEasySaveType(type);
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Other EasySave Methods
|
||||
|
||||
/// <summary>Deletes a key from this EasySaveFile.</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 EasySaveFile.</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)
|
||||
{
|
||||
EasySaveData es3data;
|
||||
if (!cache.TryGetValue(key, out es3data))
|
||||
throw new KeyNotFoundException("Key \"" + key + "\" was not found in this EasySaveFile. 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 EasySaveFile GetOrCreateCachedFile(EasySaveSettings settings)
|
||||
{
|
||||
EasySaveFile cachedFile;
|
||||
if (!cachedFiles.TryGetValue(settings.path, out cachedFile))
|
||||
{
|
||||
cachedFile = new EasySaveFile(settings, false);
|
||||
cachedFiles.Add(settings.path, cachedFile);
|
||||
cachedFile.syncWithFile = true; // This ensures that the file won't be merged, which would prevent deleted keys from being deleted.
|
||||
}
|
||||
// Settings might refer to the same file, but might have changed.
|
||||
// To account for this, we update the settings of the EasySaveFile each time we access it.
|
||||
cachedFile.settings = settings;
|
||||
return cachedFile;
|
||||
}
|
||||
|
||||
internal static void CacheFile(EasySaveSettings settings)
|
||||
{
|
||||
// If we're still using cached settings, set it to the default location.
|
||||
if (settings.location == EasySave.Location.Cache)
|
||||
{
|
||||
settings = (EasySaveSettings)settings.Clone();
|
||||
// If the default settings are also set to cache, assume EasySave.Location.File. Otherwise, set it to the default location.
|
||||
settings.location = EasySaveSettings.defaultSettings.location == EasySave.Location.Cache ? EasySave.Location.File : EasySaveSettings.defaultSettings.location;
|
||||
}
|
||||
|
||||
if (!EasySave.FileExists(settings))
|
||||
return;
|
||||
|
||||
// Disable compression and encryption when loading the raw bytes, and the EasySaveFile constructor will expect encrypted/compressed bytes.
|
||||
var loadSettings = (EasySaveSettings)settings.Clone();
|
||||
loadSettings.compressionType = EasySave.CompressionType.None;
|
||||
loadSettings.encryptionType = EasySave.EncryptionType.None;
|
||||
|
||||
cachedFiles[settings.path] = new EasySaveFile(EasySave.LoadRawBytes(loadSettings), settings);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
internal static void Store(EasySaveSettings settings = null)
|
||||
{
|
||||
if (settings == null)
|
||||
settings = new EasySaveSettings(EasySave.Location.File);
|
||||
// If we're still using cached settings, set it to the default location.
|
||||
else if (settings.location == EasySave.Location.Cache)
|
||||
{
|
||||
settings = (EasySaveSettings)settings.Clone();
|
||||
// If the default settings are also set to cache, assume EasySave.Location.File. Otherwise, set it to the default location.
|
||||
settings.location = EasySaveSettings.defaultSettings.location == EasySave.Location.Cache ? EasySave.Location.File : EasySaveSettings.defaultSettings.location;
|
||||
}
|
||||
|
||||
EasySaveFile 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(EasySaveSettings settings)
|
||||
{
|
||||
cachedFiles.Remove(settings.path);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
internal static void CopyCachedFile(EasySaveSettings oldSettings, EasySaveSettings newSettings)
|
||||
{
|
||||
EasySaveFile 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, (EasySaveFile)cachedFile.MemberwiseClone());
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
internal static void DeleteKey(string key, EasySaveSettings settings)
|
||||
{
|
||||
EasySaveFile cachedFile;
|
||||
if (cachedFiles.TryGetValue(settings.path, out cachedFile))
|
||||
cachedFile.DeleteKey(key);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
internal static bool KeyExists(string key, EasySaveSettings settings)
|
||||
{
|
||||
EasySaveFile 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(EasySaveSettings settings)
|
||||
{
|
||||
return cachedFiles.ContainsKey(settings.path);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
internal static string[] GetKeys(EasySaveSettings settings)
|
||||
{
|
||||
EasySaveFile 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(EasySaveSettings settings)
|
||||
{
|
||||
EasySaveFile cachedFile;
|
||||
if (!cachedFiles.TryGetValue(settings.path, out cachedFile))
|
||||
return new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
|
||||
return cachedFile.timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Convention.EasySave.Internal
|
||||
{
|
||||
public struct EasySaveData
|
||||
{
|
||||
public EasySaveType type;
|
||||
public byte[] bytes;
|
||||
|
||||
public EasySaveData(Type type, byte[] bytes)
|
||||
{
|
||||
this.type = type == null ? null : EasySaveTypeMgr.GetOrCreateEasySaveType(type);
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
public EasySaveData(EasySaveType type, byte[] bytes)
|
||||
{
|
||||
this.type = type;
|
||||
this.bytes = bytes;
|
||||
public EasySaveData(EasySaveType type, byte[] bytes)
|
||||
{
|
||||
this.type = type;
|
||||
this.bytes = bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -52,7 +52,7 @@ namespace Convention.EasySave.Internal
|
||||
// This obviously won't work if exceptions are disabled.
|
||||
try
|
||||
{
|
||||
if (assemblyNames.Contains(assembly.GetName().Name))
|
||||
//if (assemblyNames.Contains(assembly.GetName().Name))
|
||||
assemblyList.Add(assembly);
|
||||
}
|
||||
catch { }
|
||||
|
@@ -3,299 +3,302 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Convention.EasySave.Internal;
|
||||
|
||||
public class EasySaveSpreadsheet
|
||||
namespace Convention.EasySave
|
||||
{
|
||||
private int cols = 0;
|
||||
private int rows = 0;
|
||||
private Dictionary<Index, string> cells = new Dictionary<Index, string>();
|
||||
|
||||
private const string QUOTE = "\"";
|
||||
private const char QUOTE_CHAR = '"';
|
||||
private const char COMMA_CHAR = ',';
|
||||
private const char NEWLINE_CHAR = '\n';
|
||||
private const string ESCAPED_QUOTE = "\"\"";
|
||||
private static char[] CHARS_TO_ESCAPE = { ',', '"', '\n', ' ' };
|
||||
|
||||
public int ColumnCount
|
||||
public class EasySaveSpreadsheet
|
||||
{
|
||||
get{ return cols; }
|
||||
}
|
||||
private int cols = 0;
|
||||
private int rows = 0;
|
||||
private Dictionary<Index, string> cells = new Dictionary<Index, string>();
|
||||
|
||||
public int RowCount
|
||||
{
|
||||
get{ return rows; }
|
||||
}
|
||||
private const string QUOTE = "\"";
|
||||
private const char QUOTE_CHAR = '"';
|
||||
private const char COMMA_CHAR = ',';
|
||||
private const char NEWLINE_CHAR = '\n';
|
||||
private const string ESCAPED_QUOTE = "\"\"";
|
||||
private static char[] CHARS_TO_ESCAPE = { ',', '"', '\n', ' ' };
|
||||
|
||||
public int GetColumnLength(int col)
|
||||
{
|
||||
if (col >= cols)
|
||||
return 0;
|
||||
|
||||
int maxRow = -1;
|
||||
|
||||
foreach(var index in cells.Keys)
|
||||
if (index.col == col && index.row > maxRow)
|
||||
maxRow = index.row;
|
||||
|
||||
return maxRow+1;
|
||||
}
|
||||
|
||||
public int GetRowLength(int row)
|
||||
{
|
||||
if (row >= rows)
|
||||
return 0;
|
||||
|
||||
int maxCol = -1;
|
||||
|
||||
foreach (var index in cells.Keys)
|
||||
if (index.row == row && index.col > maxCol)
|
||||
maxCol = index.col;
|
||||
|
||||
return maxCol + 1;
|
||||
}
|
||||
|
||||
public void SetCell(int col, int row, object value)
|
||||
{
|
||||
var type = value.GetType();
|
||||
|
||||
// If we're writing a string, add it without formatting.
|
||||
if (type == typeof(string))
|
||||
{
|
||||
SetCellString(col, row, (string)value);
|
||||
return;
|
||||
}
|
||||
|
||||
var settings = new EasySaveSettings();
|
||||
if (EasySaveReflection.IsPrimitive(type))
|
||||
SetCellString(col, row, value.ToString());
|
||||
else
|
||||
SetCellString(col, row, settings.encoding.GetString(EasySave.Serialize(value, EasySaveTypeMgr.GetOrCreateEasySaveType(type))));
|
||||
|
||||
// Expand the spreadsheet if necessary.
|
||||
if (col >= cols)
|
||||
cols = (col + 1);
|
||||
if (row >= rows)
|
||||
rows = (row + 1);
|
||||
}
|
||||
|
||||
private void SetCellString(int col, int row, string value)
|
||||
{
|
||||
cells [new Index (col, row)] = value;
|
||||
|
||||
// Expand the spreadsheet if necessary.
|
||||
if(col >= cols)
|
||||
cols = (col+1);
|
||||
if (row >= rows)
|
||||
rows = (row + 1);
|
||||
}
|
||||
|
||||
|
||||
// Don't create non-generic version of this. Generic parameter is necessary as no type data is stored in the CSV file.
|
||||
public T GetCell<T>(int col, int row)
|
||||
{
|
||||
var val = GetCell(typeof(T), col, row);
|
||||
|
||||
if (val == null)
|
||||
return default(T);
|
||||
return (T)val;
|
||||
}
|
||||
|
||||
public object GetCell(System.Type type, int col, int row)
|
||||
{
|
||||
string value;
|
||||
|
||||
if (col >= cols || row >= rows)
|
||||
throw new System.IndexOutOfRangeException("Cell (" + col + ", " + row + ") is out of bounds of spreadsheet (" + cols + ", " + rows + ").");
|
||||
|
||||
if (!cells.TryGetValue(new Index(col, row), out value) || value == null)
|
||||
return null;
|
||||
|
||||
// If we're loading a string, simply return the string value.
|
||||
if (type == typeof(string))
|
||||
{
|
||||
var str = (object)value;
|
||||
return str;
|
||||
}
|
||||
|
||||
var settings = new EasySaveSettings();
|
||||
return EasySave.Deserialize(EasySaveTypeMgr.GetOrCreateEasySaveType(type, true), settings.encoding.GetBytes(value), settings);
|
||||
}
|
||||
|
||||
public void Load(string filePath)
|
||||
{
|
||||
Load(new EasySaveSettings (filePath));
|
||||
}
|
||||
|
||||
public void Load(string filePath, EasySaveSettings settings)
|
||||
{
|
||||
Load(new EasySaveSettings (filePath, settings));
|
||||
}
|
||||
|
||||
public void Load(EasySaveSettings settings)
|
||||
{
|
||||
Load(EasySaveStream.CreateStream(settings, EasySaveFileMode.Read), settings);
|
||||
}
|
||||
|
||||
public void LoadRaw(string str)
|
||||
{
|
||||
Load(new MemoryStream (((new EasySaveSettings ()).encoding).GetBytes(str)), new EasySaveSettings());
|
||||
}
|
||||
|
||||
public void LoadRaw(string str, EasySaveSettings settings)
|
||||
{
|
||||
Load(new MemoryStream ((settings.encoding).GetBytes(str)), settings);
|
||||
}
|
||||
|
||||
private void Load(Stream stream, EasySaveSettings settings)
|
||||
{
|
||||
using (var reader = new StreamReader(stream))
|
||||
public int ColumnCount
|
||||
{
|
||||
int c_int;
|
||||
char c;
|
||||
string value = "";
|
||||
int col = 0;
|
||||
int row = 0;
|
||||
get { return cols; }
|
||||
}
|
||||
|
||||
// Read until the end of the stream.
|
||||
while(true)
|
||||
public int RowCount
|
||||
{
|
||||
get { return rows; }
|
||||
}
|
||||
|
||||
public int GetColumnLength(int col)
|
||||
{
|
||||
if (col >= cols)
|
||||
return 0;
|
||||
|
||||
int maxRow = -1;
|
||||
|
||||
foreach (var index in cells.Keys)
|
||||
if (index.col == col && index.row > maxRow)
|
||||
maxRow = index.row;
|
||||
|
||||
return maxRow + 1;
|
||||
}
|
||||
|
||||
public int GetRowLength(int row)
|
||||
{
|
||||
if (row >= rows)
|
||||
return 0;
|
||||
|
||||
int maxCol = -1;
|
||||
|
||||
foreach (var index in cells.Keys)
|
||||
if (index.row == row && index.col > maxCol)
|
||||
maxCol = index.col;
|
||||
|
||||
return maxCol + 1;
|
||||
}
|
||||
|
||||
public void SetCell(int col, int row, object value)
|
||||
{
|
||||
var type = value.GetType();
|
||||
|
||||
// If we're writing a string, add it without formatting.
|
||||
if (type == typeof(string))
|
||||
{
|
||||
c_int = reader.Read();
|
||||
c = (char)c_int;
|
||||
if(c == QUOTE_CHAR)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
c = (char)reader.Read();
|
||||
SetCellString(col, row, (string)value);
|
||||
return;
|
||||
}
|
||||
|
||||
if(c == QUOTE_CHAR)
|
||||
{
|
||||
// If this quote isn't escaped by another, it is the last quote, so we should stop parsing this value.
|
||||
if(((char)reader.Peek()) != QUOTE_CHAR)
|
||||
break;
|
||||
else
|
||||
c = (char)reader.Read();
|
||||
}
|
||||
value += c;
|
||||
}
|
||||
}
|
||||
// If this is the end of a column, row, or the stream, add the value to the spreadsheet.
|
||||
else if(c == COMMA_CHAR || c == NEWLINE_CHAR || c_int == -1)
|
||||
var settings = new EasySaveSettings();
|
||||
if (EasySaveReflection.IsPrimitive(type))
|
||||
SetCellString(col, row, value.ToString());
|
||||
else
|
||||
SetCellString(col, row, settings.encoding.GetString(EasySave.Serialize(value, EasySaveTypeMgr.GetOrCreateEasySaveType(type))));
|
||||
|
||||
// Expand the spreadsheet if necessary.
|
||||
if (col >= cols)
|
||||
cols = (col + 1);
|
||||
if (row >= rows)
|
||||
rows = (row + 1);
|
||||
}
|
||||
|
||||
private void SetCellString(int col, int row, string value)
|
||||
{
|
||||
cells[new Index(col, row)] = value;
|
||||
|
||||
// Expand the spreadsheet if necessary.
|
||||
if (col >= cols)
|
||||
cols = (col + 1);
|
||||
if (row >= rows)
|
||||
rows = (row + 1);
|
||||
}
|
||||
|
||||
|
||||
// Don't create non-generic version of this. Generic parameter is necessary as no type data is stored in the CSV file.
|
||||
public T GetCell<T>(int col, int row)
|
||||
{
|
||||
var val = GetCell(typeof(T), col, row);
|
||||
|
||||
if (val == null)
|
||||
return default(T);
|
||||
return (T)val;
|
||||
}
|
||||
|
||||
public object GetCell(System.Type type, int col, int row)
|
||||
{
|
||||
string value;
|
||||
|
||||
if (col >= cols || row >= rows)
|
||||
throw new System.IndexOutOfRangeException("Cell (" + col + ", " + row + ") is out of bounds of spreadsheet (" + cols + ", " + rows + ").");
|
||||
|
||||
if (!cells.TryGetValue(new Index(col, row), out value) || value == null)
|
||||
return null;
|
||||
|
||||
// If we're loading a string, simply return the string value.
|
||||
if (type == typeof(string))
|
||||
{
|
||||
var str = (object)value;
|
||||
return str;
|
||||
}
|
||||
|
||||
var settings = new EasySaveSettings();
|
||||
return EasySave.Deserialize(EasySaveTypeMgr.GetOrCreateEasySaveType(type, true), settings.encoding.GetBytes(value), settings);
|
||||
}
|
||||
|
||||
public void Load(string filePath)
|
||||
{
|
||||
Load(new EasySaveSettings(filePath));
|
||||
}
|
||||
|
||||
public void Load(string filePath, EasySaveSettings settings)
|
||||
{
|
||||
Load(new EasySaveSettings(filePath, settings));
|
||||
}
|
||||
|
||||
public void Load(EasySaveSettings settings)
|
||||
{
|
||||
Load(EasySaveStream.CreateStream(settings, EasySaveFileMode.Read), settings);
|
||||
}
|
||||
|
||||
public void LoadRaw(string str)
|
||||
{
|
||||
Load(new MemoryStream(((new EasySaveSettings()).encoding).GetBytes(str)), new EasySaveSettings());
|
||||
}
|
||||
|
||||
public void LoadRaw(string str, EasySaveSettings settings)
|
||||
{
|
||||
Load(new MemoryStream((settings.encoding).GetBytes(str)), settings);
|
||||
}
|
||||
|
||||
private void Load(Stream stream, EasySaveSettings settings)
|
||||
{
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
int c_int;
|
||||
char c;
|
||||
string value = "";
|
||||
int col = 0;
|
||||
int row = 0;
|
||||
|
||||
// Read until the end of the stream.
|
||||
while (true)
|
||||
{
|
||||
SetCell(col, row, value);
|
||||
value = "";
|
||||
if(c == COMMA_CHAR)
|
||||
col++;
|
||||
else if(c == NEWLINE_CHAR)
|
||||
c_int = reader.Read();
|
||||
c = (char)c_int;
|
||||
if (c == QUOTE_CHAR)
|
||||
{
|
||||
col = 0;
|
||||
row++;
|
||||
while (true)
|
||||
{
|
||||
c = (char)reader.Read();
|
||||
|
||||
if (c == QUOTE_CHAR)
|
||||
{
|
||||
// If this quote isn't escaped by another, it is the last quote, so we should stop parsing this value.
|
||||
if (((char)reader.Peek()) != QUOTE_CHAR)
|
||||
break;
|
||||
else
|
||||
c = (char)reader.Read();
|
||||
}
|
||||
value += c;
|
||||
}
|
||||
}
|
||||
// If this is the end of a column, row, or the stream, add the value to the spreadsheet.
|
||||
else if (c == COMMA_CHAR || c == NEWLINE_CHAR || c_int == -1)
|
||||
{
|
||||
SetCell(col, row, value);
|
||||
value = "";
|
||||
if (c == COMMA_CHAR)
|
||||
col++;
|
||||
else if (c == NEWLINE_CHAR)
|
||||
{
|
||||
col = 0;
|
||||
row++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
value += c;
|
||||
}
|
||||
else
|
||||
value += c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Save(string filePath)
|
||||
{
|
||||
Save(new EasySaveSettings (filePath), false);
|
||||
}
|
||||
|
||||
public void Save(string filePath, EasySaveSettings settings)
|
||||
{
|
||||
Save(new EasySaveSettings (filePath, settings), false);
|
||||
}
|
||||
|
||||
public void Save(EasySaveSettings settings)
|
||||
{
|
||||
Save(settings, false);
|
||||
}
|
||||
|
||||
public void Save(string filePath, bool append)
|
||||
{
|
||||
Save(new EasySaveSettings (filePath), append);
|
||||
}
|
||||
|
||||
public void Save(string filePath, EasySaveSettings settings, bool append)
|
||||
{
|
||||
Save(new EasySaveSettings (filePath, settings), append);
|
||||
}
|
||||
|
||||
public void Save(EasySaveSettings settings, bool append)
|
||||
{
|
||||
using (var writer = new StreamWriter(EasySaveStream.CreateStream(settings, append ? EasySaveFileMode.Append : EasySaveFileMode.Write)))
|
||||
public void Save(string filePath)
|
||||
{
|
||||
// If data already exists and we're appending, we need to prepend a newline.
|
||||
if(append && EasySave.FileExists(settings))
|
||||
writer.Write(NEWLINE_CHAR);
|
||||
Save(new EasySaveSettings(filePath), false);
|
||||
}
|
||||
|
||||
var array = ToArray();
|
||||
for(int row = 0; row < rows; row++)
|
||||
public void Save(string filePath, EasySaveSettings settings)
|
||||
{
|
||||
Save(new EasySaveSettings(filePath, settings), false);
|
||||
}
|
||||
|
||||
public void Save(EasySaveSettings settings)
|
||||
{
|
||||
Save(settings, false);
|
||||
}
|
||||
|
||||
public void Save(string filePath, bool append)
|
||||
{
|
||||
Save(new EasySaveSettings(filePath), append);
|
||||
}
|
||||
|
||||
public void Save(string filePath, EasySaveSettings settings, bool append)
|
||||
{
|
||||
Save(new EasySaveSettings(filePath, settings), append);
|
||||
}
|
||||
|
||||
public void Save(EasySaveSettings settings, bool append)
|
||||
{
|
||||
using (var writer = new StreamWriter(EasySaveStream.CreateStream(settings, append ? EasySaveFileMode.Append : EasySaveFileMode.Write)))
|
||||
{
|
||||
if(row != 0)
|
||||
// If data already exists and we're appending, we need to prepend a newline.
|
||||
if (append && EasySave.FileExists(settings))
|
||||
writer.Write(NEWLINE_CHAR);
|
||||
|
||||
for(int col = 0; col < cols; col++)
|
||||
var array = ToArray();
|
||||
for (int row = 0; row < rows; row++)
|
||||
{
|
||||
if(col != 0)
|
||||
writer.Write(COMMA_CHAR);
|
||||
if (row != 0)
|
||||
writer.Write(NEWLINE_CHAR);
|
||||
|
||||
writer.Write( Escape(array [col, row]) );
|
||||
for (int col = 0; col < cols; col++)
|
||||
{
|
||||
if (col != 0)
|
||||
writer.Write(COMMA_CHAR);
|
||||
|
||||
writer.Write(Escape(array[col, row]));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!append)
|
||||
EasySaveIO.CommitBackup(settings);
|
||||
}
|
||||
if(!append)
|
||||
EasySaveIO.CommitBackup(settings);
|
||||
}
|
||||
|
||||
private static string Escape(string str, bool isAlreadyWrappedInQuotes=false)
|
||||
{
|
||||
if (str == "")
|
||||
return "\"\"";
|
||||
else if(str == null)
|
||||
return null;
|
||||
|
||||
// Now escape any other quotes.
|
||||
if(str.Contains(QUOTE))
|
||||
str = str.Replace(QUOTE, ESCAPED_QUOTE);
|
||||
|
||||
// If there's chars to escape, wrap the value in quotes.
|
||||
if(str.IndexOfAny(CHARS_TO_ESCAPE) > -1)
|
||||
str = QUOTE + str + QUOTE;
|
||||
return str;
|
||||
}
|
||||
|
||||
private static string Unescape(string str)
|
||||
{
|
||||
if(str.StartsWith(QUOTE) && str.EndsWith(QUOTE))
|
||||
private static string Escape(string str, bool isAlreadyWrappedInQuotes = false)
|
||||
{
|
||||
str = str.Substring(1, str.Length-2);
|
||||
if(str.Contains(ESCAPED_QUOTE))
|
||||
str = str.Replace(ESCAPED_QUOTE, QUOTE);
|
||||
if (str == "")
|
||||
return "\"\"";
|
||||
else if (str == null)
|
||||
return null;
|
||||
|
||||
// Now escape any other quotes.
|
||||
if (str.Contains(QUOTE))
|
||||
str = str.Replace(QUOTE, ESCAPED_QUOTE);
|
||||
|
||||
// If there's chars to escape, wrap the value in quotes.
|
||||
if (str.IndexOfAny(CHARS_TO_ESCAPE) > -1)
|
||||
str = QUOTE + str + QUOTE;
|
||||
return str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
private string[,] ToArray()
|
||||
{
|
||||
var array = new string[cols, rows];
|
||||
foreach (var cell in cells)
|
||||
array [cell.Key.col, cell.Key.row] = cell.Value;
|
||||
return array;
|
||||
}
|
||||
|
||||
protected struct Index
|
||||
{
|
||||
public int col;
|
||||
public int row;
|
||||
|
||||
public Index(int col, int row)
|
||||
private static string Unescape(string str)
|
||||
{
|
||||
this.col = col;
|
||||
this.row = row;
|
||||
if (str.StartsWith(QUOTE) && str.EndsWith(QUOTE))
|
||||
{
|
||||
str = str.Substring(1, str.Length - 2);
|
||||
if (str.Contains(ESCAPED_QUOTE))
|
||||
str = str.Replace(ESCAPED_QUOTE, QUOTE);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
private string[,] ToArray()
|
||||
{
|
||||
var array = new string[cols, rows];
|
||||
foreach (var cell in cells)
|
||||
array[cell.Key.col, cell.Key.row] = cell.Value;
|
||||
return array;
|
||||
}
|
||||
|
||||
protected struct Index
|
||||
{
|
||||
public int col;
|
||||
public int row;
|
||||
|
||||
public Index(int col, int row)
|
||||
{
|
||||
this.col = col;
|
||||
this.row = row;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -6,448 +6,451 @@ using System.ComponentModel;
|
||||
using Convention.EasySave.Types;
|
||||
using Convention.EasySave.Internal;
|
||||
|
||||
public abstract class EasySaveReader : System.IDisposable
|
||||
namespace Convention.EasySave
|
||||
{
|
||||
/// <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)
|
||||
public abstract class EasySaveReader : System.IDisposable
|
||||
{
|
||||
this.settings = settings;
|
||||
}
|
||||
/// <summary>The settings used to create this reader.</summary>
|
||||
public EasySaveSettings 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
|
||||
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)
|
||||
{
|
||||
return new EasySaveReaderPropertyEnumerator (this);
|
||||
}
|
||||
}
|
||||
if (key == null)
|
||||
throw new ArgumentNullException("Key cannot be NULL when loading data.");
|
||||
|
||||
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)
|
||||
string currentKey;
|
||||
while ((currentKey = ReadPropertyName()) != key)
|
||||
{
|
||||
// Allows us to repeat a property name or insert one of our own.
|
||||
if(reader.overridePropertiesName != null)
|
||||
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)
|
||||
{
|
||||
string tempName = reader.overridePropertiesName;
|
||||
reader.overridePropertiesName = null;
|
||||
yield return tempName;
|
||||
}
|
||||
else
|
||||
{
|
||||
if((propertyName = reader.ReadPropertyName()) == null)
|
||||
yield break;
|
||||
yield return propertyName;
|
||||
// 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)
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public class EasySaveReaderRawEnumerator
|
||||
{
|
||||
this.reader = reader;
|
||||
}
|
||||
public EasySaveReader reader;
|
||||
|
||||
public IEnumerator GetEnumerator()
|
||||
{
|
||||
while(true)
|
||||
public EasySaveReaderRawEnumerator(EasySaveReader reader)
|
||||
{
|
||||
string key = reader.ReadPropertyName();
|
||||
if(key == null)
|
||||
yield break;
|
||||
this.reader = reader;
|
||||
}
|
||||
|
||||
Type type = reader.ReadTypeFromHeader<object>();
|
||||
public IEnumerator GetEnumerator()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
string key = reader.ReadPropertyName();
|
||||
if (key == null)
|
||||
yield break;
|
||||
|
||||
byte[] bytes = reader.ReadElement();
|
||||
Type type = reader.ReadTypeFromHeader<object>();
|
||||
|
||||
reader.ReadKeySuffix();
|
||||
byte[] bytes = reader.ReadElement();
|
||||
|
||||
if(type != null)
|
||||
yield return new KeyValuePair<string,EasySaveData>(key, new EasySaveData(type, bytes));
|
||||
reader.ReadKeySuffix();
|
||||
|
||||
if (type != null)
|
||||
yield return new KeyValuePair<string, EasySaveData>(key, new EasySaveData(type, bytes));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,18 +1,23 @@
|
||||
public class EasySaveDefaults
|
||||
using Convention.EasySave;
|
||||
|
||||
namespace Convention.EasySave
|
||||
{
|
||||
public EasySaveSerializableSettings settings = new EasySaveSerializableSettings();
|
||||
public class EasySaveDefaults
|
||||
{
|
||||
public EasySaveSettings settings = new EasySaveSerializableSettings();
|
||||
|
||||
public bool addMgrToSceneAutomatically = false;
|
||||
public bool autoUpdateReferences = true;
|
||||
public bool addAllPrefabsToManager = true;
|
||||
public int collectDependenciesDepth = 4;
|
||||
public int collectDependenciesTimeout = 10;
|
||||
public bool updateReferencesWhenSceneChanges = true;
|
||||
public bool updateReferencesWhenSceneIsSaved = true;
|
||||
public bool updateReferencesWhenSceneIsOpened = true;
|
||||
public string[] referenceFolders = new string[0];
|
||||
public bool addMgrToSceneAutomatically = false;
|
||||
public bool autoUpdateReferences = true;
|
||||
public bool addAllPrefabsToManager = true;
|
||||
public int collectDependenciesDepth = 4;
|
||||
public int collectDependenciesTimeout = 10;
|
||||
public bool updateReferencesWhenSceneChanges = true;
|
||||
public bool updateReferencesWhenSceneIsSaved = true;
|
||||
public bool updateReferencesWhenSceneIsOpened = true;
|
||||
public string[] referenceFolders = new string[0];
|
||||
|
||||
public bool logDebugInfo = false;
|
||||
public bool logWarnings = true;
|
||||
public bool logErrors = true;
|
||||
}
|
||||
public bool logDebugInfo = false;
|
||||
public bool logWarnings = true;
|
||||
public bool logErrors = true;
|
||||
}
|
||||
}
|
||||
|
@@ -1,267 +1,217 @@
|
||||
using Convention.EasySave.Internal;
|
||||
|
||||
public class EasySaveSettings : System.ICloneable
|
||||
namespace Convention.EasySave
|
||||
{
|
||||
|
||||
#region Default settings
|
||||
private static EasySaveSettings _defaults = null;
|
||||
private static EasySaveDefaults _defaultSettingsScriptableObject;
|
||||
private const string defaultSettingsPath = "EasySave/EasySaveDefaults";
|
||||
|
||||
public static EasySaveDefaults defaultSettingsScriptableObject
|
||||
public class EasySaveSettings : System.ICloneable
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_defaultSettingsScriptableObject == null)
|
||||
{
|
||||
_defaultSettingsScriptableObject = Resources.Load<EasySaveDefaults>(defaultSettingsPath);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
#region Default settings
|
||||
private static EasySaveSettings _defaults = null;
|
||||
private static EasySaveDefaults _defaultSettingsScriptableObject;
|
||||
private const string defaultSettingsPath = "EasySave/EasySaveDefaults";
|
||||
|
||||
public static EasySaveDefaults defaultSettingsScriptableObject
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_defaultSettingsScriptableObject == null)
|
||||
{
|
||||
_defaultSettingsScriptableObject = ScriptableObject.CreateInstance<ES3Defaults>();
|
||||
|
||||
// If this is the version being submitted to the Asset Store, don't include ES3Defaults.
|
||||
if (Application.productName.Contains("EasySave Release"))
|
||||
{
|
||||
Debug.Log("This has been identified as a release build as the title contains 'EasySave Release', so ES3Defaults will not be created.");
|
||||
return _defaultSettingsScriptableObject;
|
||||
}
|
||||
|
||||
// Convert the old settings to the new settings if necessary.
|
||||
var oldSettings = GetOldSettings();
|
||||
if (oldSettings != null)
|
||||
{
|
||||
oldSettings.CopyInto(_defaultSettingsScriptableObject.settings);
|
||||
// Only enable warning logs by default for new installs as this may look like unexpected behaviour to some.
|
||||
_defaultSettingsScriptableObject.logWarnings = false;
|
||||
RemoveOldSettings();
|
||||
}
|
||||
|
||||
CreateDefaultSettingsFolder();
|
||||
AssetDatabase.CreateAsset(_defaultSettingsScriptableObject, PathToDefaultSettings());
|
||||
AssetDatabase.SaveAssets();
|
||||
_defaultSettingsScriptableObject = new();
|
||||
}
|
||||
#endif
|
||||
return _defaultSettingsScriptableObject;
|
||||
}
|
||||
return _defaultSettingsScriptableObject;
|
||||
}
|
||||
}
|
||||
|
||||
public static EasySaveSettings defaultSettings
|
||||
{
|
||||
get
|
||||
public static EasySaveSettings defaultSettings
|
||||
{
|
||||
if(_defaults == null)
|
||||
get
|
||||
{
|
||||
if(defaultSettingsScriptableObject != null)
|
||||
_defaults = defaultSettingsScriptableObject.settings;
|
||||
}
|
||||
return _defaults;
|
||||
}
|
||||
}
|
||||
|
||||
private static EasySaveSettings _unencryptedUncompressedSettings = null;
|
||||
internal static EasySaveSettings unencryptedUncompressedSettings
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_unencryptedUncompressedSettings == null)
|
||||
_unencryptedUncompressedSettings = new EasySaveSettings(EasySave.EncryptionType.None, EasySave.CompressionType.None);
|
||||
return _unencryptedUncompressedSettings;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
|
||||
private static readonly string[] resourcesExtensions = new string[]{".txt", ".htm", ".html", ".xml", ".bytes", ".json", ".csv", ".yaml", ".fnt" };
|
||||
|
||||
[SerializeField]
|
||||
private EasySave.Location _location;
|
||||
/// <summary>The location where we wish to store data. As it's not possible to save/load from File in WebGL, if the default location is File it will use PlayerPrefs instead.</summary>
|
||||
public EasySave.Location location
|
||||
{
|
||||
get
|
||||
{
|
||||
if(_location == EasySave.Location.File && (Application.platform == RuntimePlatform.WebGLPlayer || Application.platform == RuntimePlatform.tvOS))
|
||||
return EasySave.Location.PlayerPrefs;
|
||||
return _location;
|
||||
}
|
||||
set{ _location = value; }
|
||||
}
|
||||
|
||||
/// <summary>The path associated with this EasySaveSettings object, if any.</summary>
|
||||
public string path = "SaveFile.es3";
|
||||
/// <summary>The type of encryption to use when encrypting data, if any.</summary>
|
||||
public EasySave.EncryptionType encryptionType = EasySave.EncryptionType.None;
|
||||
/// <summary>The type of encryption to use when encrypting data, if any.</summary>
|
||||
public EasySave.CompressionType compressionType = EasySave.CompressionType.None;
|
||||
/// <summary>The password to use when encrypting data.</summary>
|
||||
public string encryptionPassword = "password";
|
||||
/// <summary>The default directory in which to store files, and the location which relative paths should be relative to.</summary>
|
||||
public EasySave.Directory directory = EasySave.Directory.PersistentDataPath;
|
||||
/// <summary>What format to use when serialising and deserialising data.</summary>
|
||||
public EasySave.Format format = EasySave.Format.JSON;
|
||||
/// <summary>Whether we want to pretty print JSON.</summary>
|
||||
public bool prettyPrint = true;
|
||||
/// <summary>Any stream buffers will be set to this length in bytes.</summary>
|
||||
public int bufferSize = 2048;
|
||||
/// <summary>The text encoding to use for text-based format. Note that changing this may invalidate previous save data.</summary>
|
||||
public System.Text.Encoding encoding = System.Text.Encoding.UTF8;
|
||||
// <summary>Whether we should serialise children when serialising a GameObject.</summary>
|
||||
public bool saveChildren = true;
|
||||
// <summary>Whether we should apply encryption and/or compression to raw cached data if they're specified in the cached data's settings.</summary>
|
||||
public bool postprocessRawCachedData = false;
|
||||
|
||||
/// <summary>Whether we should check that the data we are loading from a file matches the method we are using to load it.</summary>
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public bool typeChecking = true;
|
||||
|
||||
/// <summary>Enabling this ensures that only serialisable fields are serialised. Otherwise, possibly unsafe fields and properties will be serialised.</summary>
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public bool safeReflection = true;
|
||||
/// <summary>Whether UnityEngine.Object members should be stored by value, reference or both.</summary>
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public EasySave.ReferenceMode memberReferenceMode = EasySave.ReferenceMode.ByRef;
|
||||
/// <summary>Whether the main save methods should save UnityEngine.Objects by value, reference, or both.</summary>
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public EasySave.ReferenceMode referenceMode = EasySave.ReferenceMode.ByRefAndValue;
|
||||
|
||||
/// <summary>How many levels of hierarchy Easy Save will serialise. This is used to protect against cyclic references.</summary>
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public int serializationDepthLimit = 64;
|
||||
|
||||
/// <summary>The names of the Assemblies we should try to load our Convention.EasySave.Types from.</summary>
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public string[] assemblyNames = new string[] { "Assembly-CSharp-firstpass", "Assembly-CSharp"};
|
||||
|
||||
/// <summary>Gets the full, absolute path which this EasySaveSettings object identifies.</summary>
|
||||
public string FullPath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (path == null)
|
||||
throw new System.NullReferenceException("The 'path' field of this EasySaveSettings is null, indicating that it was not possible to load the default settings from Resources. Please check that the EasySave Default Settings.prefab exists in Assets/Plugins/Resources/EasySave/");
|
||||
|
||||
if(IsAbsolute(path))
|
||||
return path;
|
||||
|
||||
if(location == EasySave.Location.File)
|
||||
{
|
||||
if(directory == EasySave.Directory.PersistentDataPath)
|
||||
return EasySaveIO.persistentDataPath + "/" + path;
|
||||
if(directory == EasySave.Directory.DataPath)
|
||||
return Application.dataPath + "/" + path;
|
||||
throw new System.NotImplementedException("File directory \""+directory+"\" has not been implemented.");
|
||||
}
|
||||
if(location == EasySave.Location.Resources)
|
||||
{
|
||||
// Check that it has valid extension
|
||||
var extension = System.IO.Path.GetExtension(path);
|
||||
bool hasValidExtension = false;
|
||||
foreach (var ext in resourcesExtensions)
|
||||
if (_defaults == null)
|
||||
{
|
||||
if (extension == ext)
|
||||
{
|
||||
hasValidExtension = true;
|
||||
break;
|
||||
}
|
||||
if (defaultSettingsScriptableObject != null)
|
||||
_defaults = defaultSettingsScriptableObject.settings;
|
||||
}
|
||||
|
||||
if(!hasValidExtension)
|
||||
throw new System.ArgumentException("Extension of file in Resources must be .json, .bytes, .txt, .csv, .htm, .html, .xml, .yaml or .fnt, but path given was \"" + path + "\"");
|
||||
|
||||
// Remove extension
|
||||
string resourcesPath = path.Replace(extension, "");
|
||||
return resourcesPath;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>Creates a new EasySaveSettings object with the given path.</summary>
|
||||
/// <param name="path">The path associated with this EasySaveSettings object.</param>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public EasySaveSettings(string path = null, EasySaveSettings settings = null) : this(true)
|
||||
{
|
||||
// if there are settings to merge, merge them.
|
||||
if (settings != null)
|
||||
settings.CopyInto(this);
|
||||
|
||||
if (path != null)
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/// <summary>Creates a new EasySaveSettings object with the given path.</summary>
|
||||
/// <param name="path">The path associated with this EasySaveSettings object.</param>
|
||||
/// <param name="enums">Accepts an EasySave.EncryptionType, EasySave.CompressionType, EasySave.Location, EasySave.Directory or EasySave.ReferenceMode.</param>
|
||||
public EasySaveSettings(string path, params System.Enum[] enums) : this(enums)
|
||||
{
|
||||
if (path != null)
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Creates a new EasySaveSettings object with the given path.</summary>
|
||||
/// <param name="path">The path associated with this EasySaveSettings object.</param>
|
||||
/// <param name="enums">Accepts an EasySave.EncryptionType, EasySave.CompressionType, EasySave.Location, EasySave.Directory or EasySave.ReferenceMode.</param>
|
||||
public EasySaveSettings(params System.Enum[] enums) : this(true)
|
||||
{
|
||||
foreach (var setting in enums)
|
||||
{
|
||||
if (setting is EasySave.EncryptionType)
|
||||
this.encryptionType = (EasySave.EncryptionType)setting;
|
||||
else if (setting is EasySave.Location)
|
||||
this.location = (EasySave.Location)setting;
|
||||
else if (setting is EasySave.CompressionType)
|
||||
this.compressionType = (EasySave.CompressionType)setting;
|
||||
else if (setting is EasySave.ReferenceMode)
|
||||
this.referenceMode = (EasySave.ReferenceMode)setting;
|
||||
else if (setting is EasySave.Format)
|
||||
this.format = (EasySave.Format)setting;
|
||||
else if (setting is EasySave.Directory)
|
||||
this.directory = (EasySave.Directory)setting;
|
||||
return _defaults;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Creates a new EasySaveSettings object with the given encryption settings.</summary>
|
||||
/// <param name="encryptionType">The type of encryption to use, if any.</param>
|
||||
/// <param name="encryptionPassword">The password to use when encrypting data.</param>
|
||||
public EasySaveSettings(EasySave.EncryptionType encryptionType, string encryptionPassword) : this(true)
|
||||
{
|
||||
this.encryptionType = encryptionType;
|
||||
this.encryptionPassword = encryptionPassword;
|
||||
}
|
||||
private static EasySaveSettings _unencryptedUncompressedSettings = null;
|
||||
internal static EasySaveSettings unencryptedUncompressedSettings
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_unencryptedUncompressedSettings == null)
|
||||
_unencryptedUncompressedSettings = new EasySaveSettings(EasySave.EncryptionType.None, EasySave.CompressionType.None);
|
||||
return _unencryptedUncompressedSettings;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Creates a new EasySaveSettings object with the given path and encryption settings.</summary>
|
||||
/// <param name="path">The path associated with this EasySaveSettings object.</param>
|
||||
/// <param name="encryptionType">The type of encryption to use, if any.</param>
|
||||
/// <param name="encryptionPassword">The password to use when encrypting data.</param>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public EasySaveSettings(string path, EasySave.EncryptionType encryptionType, string encryptionPassword, EasySaveSettings settings = null) : this(path, settings)
|
||||
{
|
||||
this.encryptionType = encryptionType;
|
||||
this.encryptionPassword = encryptionPassword;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/* Base constructor which allows us to bypass defaults so it can be called by Editor serialization */
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public EasySaveSettings(bool applyDefaults)
|
||||
{
|
||||
if (applyDefaults)
|
||||
if (defaultSettings != null)
|
||||
_defaults.CopyInto(this);
|
||||
}
|
||||
#region Fields
|
||||
|
||||
#endregion
|
||||
private static readonly string[] resourcesExtensions = new string[] { ".txt", ".htm", ".html", ".xml", ".bytes", ".json", ".csv", ".yaml", ".fnt" };
|
||||
|
||||
#region Editor methods
|
||||
private EasySave.Location _location;
|
||||
/// <summary>The location where we wish to store data. As it's not possible to save/load from File in WebGL, if the default location is File it will use PlayerPrefs instead.</summary>
|
||||
public EasySave.Location location
|
||||
{
|
||||
get
|
||||
{
|
||||
return _location;
|
||||
}
|
||||
set { _location = value; }
|
||||
}
|
||||
|
||||
/// <summary>The path associated with this EasySaveSettings object, if any.</summary>
|
||||
public string path = "SaveFile.es3";
|
||||
/// <summary>The type of encryption to use when encrypting data, if any.</summary>
|
||||
public EasySave.EncryptionType encryptionType = EasySave.EncryptionType.None;
|
||||
/// <summary>The type of encryption to use when encrypting data, if any.</summary>
|
||||
public EasySave.CompressionType compressionType = EasySave.CompressionType.None;
|
||||
/// <summary>The password to use when encrypting data.</summary>
|
||||
public string encryptionPassword = "password";
|
||||
/// <summary>The default directory in which to store files, and the location which relative paths should be relative to.</summary>
|
||||
public EasySave.Directory directory = EasySave.Directory.PersistentDataPath;
|
||||
/// <summary>What format to use when serialising and deserialising data.</summary>
|
||||
public EasySave.Format format = EasySave.Format.JSON;
|
||||
/// <summary>Whether we want to pretty print JSON.</summary>
|
||||
public bool prettyPrint = true;
|
||||
/// <summary>Any stream buffers will be set to this length in bytes.</summary>
|
||||
public int bufferSize = 2048;
|
||||
/// <summary>The text encoding to use for text-based format. Note that changing this may invalidate previous save data.</summary>
|
||||
public System.Text.Encoding encoding = System.Text.Encoding.UTF8;
|
||||
// <summary>Whether we should serialise children when serialising a GameObject.</summary>
|
||||
public bool saveChildren = true;
|
||||
// <summary>Whether we should apply encryption and/or compression to raw cached data if they're specified in the cached data's settings.</summary>
|
||||
public bool postprocessRawCachedData = false;
|
||||
|
||||
/// <summary>Whether we should check that the data we are loading from a file matches the method we are using to load it.</summary>
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public bool typeChecking = true;
|
||||
|
||||
/// <summary>Enabling this ensures that only serialisable fields are serialised. Otherwise, possibly unsafe fields and properties will be serialised.</summary>
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public bool safeReflection = true;
|
||||
/// <summary>Whether UnityEngine.Object members should be stored by value, reference or both.</summary>
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public EasySave.ReferenceMode memberReferenceMode = EasySave.ReferenceMode.ByRef;
|
||||
/// <summary>Whether the main save methods should save UnityEngine.Objects by value, reference, or both.</summary>
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public EasySave.ReferenceMode referenceMode = EasySave.ReferenceMode.ByRefAndValue;
|
||||
|
||||
/// <summary>How many levels of hierarchy Easy Save will serialise. This is used to protect against cyclic references.</summary>
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public int serializationDepthLimit = 64;
|
||||
|
||||
/// <summary>The names of the Assemblies we should try to load our Convention.EasySave.Types from.</summary>
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public string[] assemblyNames = new string[] { "Assembly-CSharp-firstpass", "Assembly-CSharp" };
|
||||
|
||||
/// <summary>Gets the full, absolute path which this EasySaveSettings object identifies.</summary>
|
||||
public string FullPath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (path == null)
|
||||
throw new System.NullReferenceException("The 'path' field of this EasySaveSettings is null, indicating that it was not possible to load the default settings from Resources. Please check that the EasySave Default Settings.prefab exists in Assets/Plugins/Resources/EasySave/");
|
||||
|
||||
if (IsAbsolute(path))
|
||||
return path;
|
||||
|
||||
if (location == EasySave.Location.File)
|
||||
{
|
||||
if (directory == EasySave.Directory.PersistentDataPath)
|
||||
return EasySaveIO.persistentDataPath + "/" + path;
|
||||
if (directory == EasySave.Directory.DataPath)
|
||||
return PlatformIndicator.DataPath + "/" + path;
|
||||
throw new System.NotImplementedException("File directory \"" + directory + "\" has not been implemented.");
|
||||
}
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>Creates a new EasySaveSettings object with the given path.</summary>
|
||||
/// <param name="path">The path associated with this EasySaveSettings object.</param>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public EasySaveSettings(string path = null, EasySaveSettings settings = null) : this(true)
|
||||
{
|
||||
// if there are settings to merge, merge them.
|
||||
if (settings != null)
|
||||
settings.CopyInto(this);
|
||||
|
||||
if (path != null)
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/// <summary>Creates a new EasySaveSettings object with the given path.</summary>
|
||||
/// <param name="path">The path associated with this EasySaveSettings object.</param>
|
||||
/// <param name="enums">Accepts an EasySave.EncryptionType, EasySave.CompressionType, EasySave.Location, EasySave.Directory or EasySave.ReferenceMode.</param>
|
||||
public EasySaveSettings(string path, params System.Enum[] enums) : this(enums)
|
||||
{
|
||||
if (path != null)
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Creates a new EasySaveSettings object with the given path.</summary>
|
||||
/// <param name="path">The path associated with this EasySaveSettings object.</param>
|
||||
/// <param name="enums">Accepts an EasySave.EncryptionType, EasySave.CompressionType, EasySave.Location, EasySave.Directory or EasySave.ReferenceMode.</param>
|
||||
public EasySaveSettings(params System.Enum[] enums) : this(true)
|
||||
{
|
||||
foreach (var setting in enums)
|
||||
{
|
||||
if (setting is EasySave.EncryptionType)
|
||||
this.encryptionType = (EasySave.EncryptionType)setting;
|
||||
else if (setting is EasySave.Location)
|
||||
this.location = (EasySave.Location)setting;
|
||||
else if (setting is EasySave.CompressionType)
|
||||
this.compressionType = (EasySave.CompressionType)setting;
|
||||
else if (setting is EasySave.ReferenceMode)
|
||||
this.referenceMode = (EasySave.ReferenceMode)setting;
|
||||
else if (setting is EasySave.Format)
|
||||
this.format = (EasySave.Format)setting;
|
||||
else if (setting is EasySave.Directory)
|
||||
this.directory = (EasySave.Directory)setting;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Creates a new EasySaveSettings object with the given encryption settings.</summary>
|
||||
/// <param name="encryptionType">The type of encryption to use, if any.</param>
|
||||
/// <param name="encryptionPassword">The password to use when encrypting data.</param>
|
||||
public EasySaveSettings(EasySave.EncryptionType encryptionType, string encryptionPassword) : this(true)
|
||||
{
|
||||
this.encryptionType = encryptionType;
|
||||
this.encryptionPassword = encryptionPassword;
|
||||
}
|
||||
|
||||
/// <summary>Creates a new EasySaveSettings object with the given path and encryption settings.</summary>
|
||||
/// <param name="path">The path associated with this EasySaveSettings object.</param>
|
||||
/// <param name="encryptionType">The type of encryption to use, if any.</param>
|
||||
/// <param name="encryptionPassword">The password to use when encrypting data.</param>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public EasySaveSettings(string path, EasySave.EncryptionType encryptionType, string encryptionPassword, EasySaveSettings settings = null) : this(path, settings)
|
||||
{
|
||||
this.encryptionType = encryptionType;
|
||||
this.encryptionPassword = encryptionPassword;
|
||||
}
|
||||
|
||||
/* Base constructor which allows us to bypass defaults so it can be called by Editor serialization */
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public EasySaveSettings(bool applyDefaults)
|
||||
{
|
||||
if (applyDefaults)
|
||||
if (defaultSettings != null)
|
||||
_defaults.CopyInto(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Editor methods
|
||||
#if UNITY_EDITOR
|
||||
public static string pathToEasySaveFolder = null;
|
||||
|
||||
@@ -312,62 +262,63 @@ public class EasySaveSettings : System.ICloneable
|
||||
AssetDatabase.DeleteAsset(PathToDefaultSettings().Replace("ES3Defaults.asset", "EasySave Default Settings.prefab"));
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Utility methods
|
||||
#region Utility methods
|
||||
|
||||
private static bool IsAbsolute(string path)
|
||||
{
|
||||
if (path.Length > 0 && (path[0] == '/' || path[0] == '\\'))
|
||||
return true;
|
||||
if (path.Length > 1 && path[1] == ':')
|
||||
return true;
|
||||
return false;
|
||||
private static bool IsAbsolute(string path)
|
||||
{
|
||||
if (path.Length > 0 && (path[0] == '/' || path[0] == '\\'))
|
||||
return true;
|
||||
if (path.Length > 1 && path[1] == ':')
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public object Clone()
|
||||
{
|
||||
var settings = new EasySaveSettings();
|
||||
CopyInto(settings);
|
||||
return settings;
|
||||
}
|
||||
|
||||
private void CopyInto(EasySaveSettings newSettings)
|
||||
{
|
||||
newSettings._location = _location;
|
||||
newSettings.directory = directory;
|
||||
newSettings.format = format;
|
||||
newSettings.prettyPrint = prettyPrint;
|
||||
newSettings.path = path;
|
||||
newSettings.encryptionType = encryptionType;
|
||||
newSettings.encryptionPassword = encryptionPassword;
|
||||
newSettings.compressionType = compressionType;
|
||||
newSettings.bufferSize = bufferSize;
|
||||
newSettings.encoding = encoding;
|
||||
newSettings.typeChecking = typeChecking;
|
||||
newSettings.safeReflection = safeReflection;
|
||||
newSettings.referenceMode = referenceMode;
|
||||
newSettings.memberReferenceMode = memberReferenceMode;
|
||||
newSettings.assemblyNames = assemblyNames;
|
||||
newSettings.saveChildren = saveChildren;
|
||||
newSettings.serializationDepthLimit = serializationDepthLimit;
|
||||
newSettings.postprocessRawCachedData = postprocessRawCachedData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/*
|
||||
* A serializable version of the settings we can use as a field in the Editor, which doesn't automatically
|
||||
* assign defaults to itself, so we get no serialization errors.
|
||||
*/
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public object Clone()
|
||||
[System.Serializable]
|
||||
public class EasySaveSerializableSettings : EasySaveSettings
|
||||
{
|
||||
var settings = new EasySaveSettings();
|
||||
CopyInto(settings);
|
||||
return settings;
|
||||
public EasySaveSerializableSettings() : base(false) { }
|
||||
public EasySaveSerializableSettings(bool applyDefaults) : base(applyDefaults) { }
|
||||
public EasySaveSerializableSettings(string path) : base(false) { this.path = path; }
|
||||
public EasySaveSerializableSettings(string path, EasySave.Location location) : base(false) { this.location = location; }
|
||||
}
|
||||
|
||||
private void CopyInto(EasySaveSettings newSettings)
|
||||
{
|
||||
newSettings._location = _location;
|
||||
newSettings.directory = directory;
|
||||
newSettings.format = format;
|
||||
newSettings.prettyPrint = prettyPrint;
|
||||
newSettings.path = path;
|
||||
newSettings.encryptionType = encryptionType;
|
||||
newSettings.encryptionPassword = encryptionPassword;
|
||||
newSettings.compressionType = compressionType;
|
||||
newSettings.bufferSize = bufferSize;
|
||||
newSettings.encoding = encoding;
|
||||
newSettings.typeChecking = typeChecking;
|
||||
newSettings.safeReflection = safeReflection;
|
||||
newSettings.referenceMode = referenceMode;
|
||||
newSettings.memberReferenceMode = memberReferenceMode;
|
||||
newSettings.assemblyNames = assemblyNames;
|
||||
newSettings.saveChildren = saveChildren;
|
||||
newSettings.serializationDepthLimit = serializationDepthLimit;
|
||||
newSettings.postprocessRawCachedData = postprocessRawCachedData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/*
|
||||
* A serializable version of the settings we can use as a field in the Editor, which doesn't automatically
|
||||
* assign defaults to itself, so we get no serialization errors.
|
||||
*/
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
[System.Serializable]
|
||||
public class EasySaveSerializableSettings : EasySaveSettings
|
||||
{
|
||||
public EasySaveSerializableSettings() : base(false){}
|
||||
public EasySaveSerializableSettings(bool applyDefaults) : base(applyDefaults){}
|
||||
public EasySaveSerializableSettings(string path) : base(false) { this.path = path; }
|
||||
public EasySaveSerializableSettings(string path, EasySave.Location location) : base(false) { this.location = location; }
|
||||
}
|
@@ -32,7 +32,7 @@ namespace Convention.EasySave.Internal
|
||||
|
||||
return CreateStream(stream, settings, fileMode);
|
||||
}
|
||||
catch(System.Exception e)
|
||||
catch(Exception)
|
||||
{
|
||||
if (stream != null)
|
||||
stream.Dispose();
|
||||
|
@@ -60,9 +60,6 @@ namespace Convention.EasySave.Types
|
||||
{
|
||||
var collection = (IList)obj;
|
||||
|
||||
if (collection.Count == 0)
|
||||
ES3Debug.LogWarning("LoadInto/ReadInto expects a collection containing instances to load data in to, but the collection is empty.");
|
||||
|
||||
if(reader.StartReadCollection())
|
||||
throw new NullReferenceException("The Collection we are trying to load is stored as null, which is not allowed when using ReadInto methods.");
|
||||
|
||||
|
@@ -32,7 +32,7 @@ namespace Convention.EasySave.Types
|
||||
{
|
||||
var array = ReadAsArray(reader);
|
||||
|
||||
return EasySaveReflection.CreateInstance(type, new object[] { array, Allocator.Persistent });
|
||||
return EasySaveReflection.CreateInstance(type, new object[] { array/*, Allocator.Persistent*/ });
|
||||
}
|
||||
|
||||
public override object Read<T>(EasySaveReader reader)
|
||||
|
@@ -19,7 +19,6 @@ namespace Convention.EasySave.Types
|
||||
public bool isDictionary = false;
|
||||
public bool isTuple = false;
|
||||
public bool isEnum = false;
|
||||
public bool isES3TypeUnityObject = false;
|
||||
public bool isReflectedType = false;
|
||||
public bool isUnsupported = false;
|
||||
public int priority = 0;
|
||||
|
@@ -88,8 +88,6 @@ namespace Convention.EasySave.Internal
|
||||
es3Type = new EasySaveStackType(type);
|
||||
else if (genericType == typeof(HashSet<>))
|
||||
es3Type = new EasySaveHashSetType(type);
|
||||
else if (genericType == typeof(Unity.Collections.NativeArray<>))
|
||||
es3Type = new EasySaveNativeArrayType(type);
|
||||
else if (throwException)
|
||||
throw new NotSupportedException("Generic type \"" + type.ToString() + "\" is not supported by Easy Save.");
|
||||
else
|
||||
@@ -104,20 +102,8 @@ namespace Convention.EasySave.Internal
|
||||
}
|
||||
else
|
||||
{
|
||||
if (EasySaveReflection.IsAssignableFrom(typeof(Component), type))
|
||||
es3Type = new ES3ReflectedComponentType(type);
|
||||
else if (EasySaveReflection.IsValueType(type))
|
||||
es3Type = new EasySaveReflectedValueType(type);
|
||||
else if (EasySaveReflection.IsAssignableFrom(typeof(ScriptableObject), type))
|
||||
es3Type = new ES3ReflectedScriptableObjectType(type);
|
||||
else if (EasySaveReflection.IsAssignableFrom(typeof(UnityEngine.Object), type))
|
||||
es3Type = new ES3ReflectedUnityObjectType(type);
|
||||
/*else if (EasySaveReflection.HasParameterlessConstructor(type) || EasySaveReflection.IsAbstract(type) || EasySaveReflection.IsInterface(type))
|
||||
es3Type = new EasySaveReflectedObjectType(type);*/
|
||||
else if (type.Name.StartsWith("Tuple`"))
|
||||
if (type.Name.StartsWith("Tuple`"))
|
||||
es3Type = new EasySaveTupleType(type);
|
||||
/*else if (throwException)
|
||||
throw new NotSupportedException("Type of " + type + " is not supported as it does not have a parameterless constructor. Only value types, Components or ScriptableObjects are supportable without a parameterless constructor. However, you may be able to create an EasySaveType script to add support for it.");*/
|
||||
else
|
||||
es3Type = new EasySaveReflectedObjectType(type);
|
||||
}
|
||||
|
@@ -5,442 +5,437 @@ using System;
|
||||
using Convention.EasySave.Types;
|
||||
using Convention.EasySave.Internal;
|
||||
|
||||
public abstract class EasySaveWriter : IDisposable
|
||||
namespace Convention.EasySave
|
||||
{
|
||||
public EasySaveSettings settings;
|
||||
protected HashSet<string> keysToDelete = new HashSet<string>();
|
||||
|
||||
internal bool writeHeaderAndFooter = true;
|
||||
internal bool overwriteKeys = true;
|
||||
|
||||
protected int serializationDepth = 0;
|
||||
|
||||
#region ES3Writer Abstract Methods
|
||||
|
||||
internal abstract void WriteNull();
|
||||
|
||||
internal virtual void StartWriteFile()
|
||||
{
|
||||
serializationDepth++;
|
||||
}
|
||||
|
||||
internal virtual void EndWriteFile()
|
||||
{
|
||||
serializationDepth--;
|
||||
}
|
||||
|
||||
internal virtual void StartWriteObject(string name)
|
||||
{
|
||||
serializationDepth++;
|
||||
}
|
||||
|
||||
internal virtual void EndWriteObject(string name)
|
||||
{
|
||||
serializationDepth--;
|
||||
}
|
||||
|
||||
internal virtual void StartWriteProperty(string name)
|
||||
{
|
||||
if (name == null)
|
||||
throw new ArgumentNullException("Key or field name cannot be NULL when saving data.");
|
||||
}
|
||||
|
||||
internal virtual void EndWriteProperty(string name)
|
||||
{
|
||||
}
|
||||
|
||||
internal virtual void StartWriteCollection()
|
||||
{
|
||||
serializationDepth++;
|
||||
}
|
||||
|
||||
internal virtual void EndWriteCollection()
|
||||
{
|
||||
serializationDepth--;
|
||||
}
|
||||
|
||||
internal abstract void StartWriteCollectionItem(int index);
|
||||
internal abstract void EndWriteCollectionItem(int index);
|
||||
|
||||
internal abstract void StartWriteDictionary();
|
||||
internal abstract void EndWriteDictionary();
|
||||
internal abstract void StartWriteDictionaryKey(int index);
|
||||
internal abstract void EndWriteDictionaryKey(int index);
|
||||
internal abstract void StartWriteDictionaryValue(int index);
|
||||
internal abstract void EndWriteDictionaryValue(int index);
|
||||
|
||||
public abstract void Dispose();
|
||||
|
||||
#endregion
|
||||
|
||||
#region ES3Writer Interface abstract methods
|
||||
|
||||
internal abstract void WriteRawProperty(string name, byte[] bytes);
|
||||
|
||||
internal abstract void WritePrimitive(int value);
|
||||
internal abstract void WritePrimitive(float value);
|
||||
internal abstract void WritePrimitive(bool value);
|
||||
internal abstract void WritePrimitive(decimal value);
|
||||
internal abstract void WritePrimitive(double value);
|
||||
internal abstract void WritePrimitive(long value);
|
||||
internal abstract void WritePrimitive(ulong value);
|
||||
internal abstract void WritePrimitive(uint value);
|
||||
internal abstract void WritePrimitive(byte value);
|
||||
internal abstract void WritePrimitive(sbyte value);
|
||||
internal abstract void WritePrimitive(short value);
|
||||
internal abstract void WritePrimitive(ushort value);
|
||||
internal abstract void WritePrimitive(char value);
|
||||
internal abstract void WritePrimitive(string value);
|
||||
internal abstract void WritePrimitive(byte[] value);
|
||||
|
||||
#endregion
|
||||
|
||||
protected EasySaveWriter(EasySaveSettings settings, bool writeHeaderAndFooter, bool overwriteKeys)
|
||||
public abstract class EasySaveWriter : IDisposable
|
||||
{
|
||||
this.settings = settings;
|
||||
this.writeHeaderAndFooter = writeHeaderAndFooter;
|
||||
this.overwriteKeys = overwriteKeys;
|
||||
}
|
||||
public EasySaveSettings settings;
|
||||
protected HashSet<string> keysToDelete = new HashSet<string>();
|
||||
|
||||
/* User-facing methods used when writing randomly-accessible Key-Value pairs. */
|
||||
#region Write(key, value) Methods
|
||||
internal bool writeHeaderAndFooter = true;
|
||||
internal bool overwriteKeys = true;
|
||||
|
||||
internal virtual void Write(string key, Type type, byte[] value)
|
||||
{
|
||||
StartWriteProperty(key);
|
||||
StartWriteObject(key);
|
||||
WriteType(type);
|
||||
WriteRawProperty("value", value);
|
||||
EndWriteObject(key);
|
||||
EndWriteProperty(key);
|
||||
MarkKeyForDeletion(key);
|
||||
}
|
||||
protected int serializationDepth = 0;
|
||||
|
||||
/// <summary>Writes a value to the writer with the given key.</summary>
|
||||
/// <param name="key">The key which uniquely identifies this value.</param>
|
||||
/// <param name="value">The value we want to write.</param>
|
||||
public virtual void Write<T>(string key, object value)
|
||||
{
|
||||
if(typeof(T) == typeof(object))
|
||||
Write(value.GetType(), key, value);
|
||||
else
|
||||
Write(typeof(T), key, value);
|
||||
}
|
||||
#region ES3Writer Abstract Methods
|
||||
|
||||
/// <summary>Writes a value to the writer with the given key, using the given type rather than the generic parameter.</summary>
|
||||
/// <param name="key">The key which uniquely identifies this value.</param>
|
||||
/// <param name="value">The value we want to write.</param>
|
||||
/// <param name="type">The type we want to use for the header, and to retrieve an EasySaveType.</param>
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public virtual void Write(Type type, string key, object value)
|
||||
{
|
||||
StartWriteProperty(key);
|
||||
StartWriteObject(key);
|
||||
WriteType(type);
|
||||
WriteProperty("value", value, EasySaveTypeMgr.GetOrCreateEasySaveType(type), settings.referenceMode);
|
||||
EndWriteObject(key);
|
||||
EndWriteProperty(key);
|
||||
MarkKeyForDeletion(key);
|
||||
}
|
||||
internal abstract void WriteNull();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Write(value) & Write(value, EasySaveType) Methods
|
||||
|
||||
/// <summary>Writes a value to the writer. Note that this should only be called within an EasySaveType.</summary>
|
||||
/// <param name="value">The value we want to write.</param>
|
||||
/// <param name="memberReferenceMode">Whether we want to write UnityEngine.Object fields and properties by reference, by value, or both.</param>
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public virtual void Write(object value, EasySave.ReferenceMode memberReferenceMode = EasySave.ReferenceMode.ByRef)
|
||||
{
|
||||
if(value == null){ WriteNull(); return; }
|
||||
|
||||
var type = EasySaveTypeMgr.GetOrCreateEasySaveType(value.GetType());
|
||||
Write(value, type, memberReferenceMode);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public virtual void Write(object value, EasySaveType type, EasySave.ReferenceMode memberReferenceMode = EasySave.ReferenceMode.ByRef)
|
||||
{
|
||||
// Note that we have to check UnityEngine.Object types for null by casting it first, otherwise
|
||||
// it will always return false.
|
||||
if (value == null)
|
||||
{
|
||||
WriteNull();
|
||||
return;
|
||||
}
|
||||
|
||||
// Deal with System.Objects
|
||||
if (type == null || type.type == typeof(object))
|
||||
{
|
||||
var valueType = value.GetType();
|
||||
type = EasySaveTypeMgr.GetOrCreateEasySaveType(valueType);
|
||||
|
||||
if(type == null)
|
||||
throw new NotSupportedException("Types of " + valueType + " are not supported. Please see the Supported Types guide for more information: https://docs.moodkie.com/easy-save-3/es3-supported-types/");
|
||||
|
||||
if (!type.isCollection && !type.isDictionary)
|
||||
{
|
||||
StartWriteObject(null);
|
||||
WriteType(valueType);
|
||||
|
||||
type.Write(value, this);
|
||||
|
||||
EndWriteObject(null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(type == null)
|
||||
throw new ArgumentNullException("EasySaveType argument cannot be null.");
|
||||
if (type.isUnsupported)
|
||||
{
|
||||
if(type.isCollection || type.isDictionary)
|
||||
throw new NotSupportedException(type.type + " is not supported because it's element type is not supported. Please see the Supported Types guide for more information: https://docs.moodkie.com/easy-save-3/es3-supported-types/");
|
||||
else
|
||||
throw new NotSupportedException("Types of " + type.type + " are not supported. Please see the Supported Types guide for more information: https://docs.moodkie.com/easy-save-3/es3-supported-types/");
|
||||
}
|
||||
|
||||
if (type.isPrimitive || type.isEnum)
|
||||
type.Write(value, this);
|
||||
else if (type.isCollection)
|
||||
{
|
||||
StartWriteCollection();
|
||||
((ECollectionType)type).Write(value, this, memberReferenceMode);
|
||||
EndWriteCollection();
|
||||
}
|
||||
else if (type.isDictionary)
|
||||
{
|
||||
StartWriteDictionary();
|
||||
((EasySaveDictionaryType)type).Write(value, this, memberReferenceMode);
|
||||
EndWriteDictionary();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
//if (type.type == typeof(GameObject))
|
||||
// ((ES3Type_GameObject)type).saveChildren = settings.saveChildren;
|
||||
|
||||
//StartWriteObject(null);
|
||||
|
||||
//if (type.isES3TypeUnityObject)
|
||||
// ((ES3UnityObjectType)type).WriteObject(value, this, memberReferenceMode);
|
||||
//else
|
||||
// type.Write(value, this);
|
||||
//EndWriteObject(null);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/* Writes a property as a name value pair. */
|
||||
#region WriteProperty(name, value) methods
|
||||
|
||||
/// <summary>Writes a field or property to the writer. Note that this should only be called within an EasySaveType.</summary>
|
||||
/// <param name="name">The name of the field or property.</param>
|
||||
/// <param name="value">The value we want to write.</param>
|
||||
public virtual void WriteProperty(string name, object value)
|
||||
{
|
||||
WriteProperty(name, value, settings.memberReferenceMode);
|
||||
}
|
||||
|
||||
/// <summary>Writes a field or property to the writer. Note that this should only be called within an EasySaveType.</summary>
|
||||
/// <param name="name">The name of the field or property.</param>
|
||||
/// <param name="value">The value we want to write.</param>
|
||||
/// <param name="memberReferenceMode">Whether we want to write the property by reference, by value, or both.</param>
|
||||
public virtual void WriteProperty(string name, object value, EasySave.ReferenceMode memberReferenceMode)
|
||||
{
|
||||
if (SerializationDepthLimitExceeded())
|
||||
return;
|
||||
|
||||
StartWriteProperty(name); Write(value, memberReferenceMode); EndWriteProperty(name);
|
||||
}
|
||||
|
||||
/// <summary>Writes a field or property to the writer. Note that this should only be called within an EasySaveType.</summary>
|
||||
/// <param name="name">The name of the field or property.</param>
|
||||
/// <param name="value">The value we want to write.</param>
|
||||
public virtual void WriteProperty<T>(string name, object value)
|
||||
{
|
||||
WriteProperty(name, value, EasySaveTypeMgr.GetOrCreateEasySaveType(typeof(T)), settings.memberReferenceMode);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public virtual void WriteProperty(string name, object value, EasySaveType type)
|
||||
{
|
||||
WriteProperty(name, value, type, settings.memberReferenceMode);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public virtual void WriteProperty(string name, object value, EasySaveType type, EasySave.ReferenceMode memberReferenceMode)
|
||||
{
|
||||
if (SerializationDepthLimitExceeded())
|
||||
return;
|
||||
|
||||
StartWriteProperty(name);
|
||||
Write(value, type, memberReferenceMode);
|
||||
EndWriteProperty(name);
|
||||
}
|
||||
|
||||
/// <summary>Writes a private property to the writer. Note that this should only be called within an EasySaveType.</summary>
|
||||
/// <param name="name">The name of the property.</param>
|
||||
/// <param name="objectContainingProperty">The object containing the property we want to write.</param>
|
||||
public void WritePrivateProperty(string name, 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());
|
||||
WriteProperty(name, property.GetValue(objectContainingProperty), EasySaveTypeMgr.GetOrCreateEasySaveType(property.MemberType));
|
||||
}
|
||||
|
||||
/// <summary>Writes a private field to the writer. Note that this should only be called within an EasySaveType.</summary>
|
||||
/// <param name="name">The name of the field.</param>
|
||||
/// <param name="objectContainingField">The object containing the property we want to write.</param>
|
||||
public void WritePrivateField(string name, 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());
|
||||
WriteProperty(name,field.GetValue(objectContainingField), EasySaveTypeMgr.GetOrCreateEasySaveType(field.MemberType));
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public void WritePrivateProperty(string name, object objectContainingProperty, EasySaveType type)
|
||||
{
|
||||
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());
|
||||
WriteProperty(name, property.GetValue(objectContainingProperty), type);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public void WritePrivateField(string name, object objectContainingField, EasySaveType type)
|
||||
{
|
||||
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());
|
||||
WriteProperty(name,field.GetValue(objectContainingField), type);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public void WriteType(Type type)
|
||||
{
|
||||
WriteProperty(EasySaveType.typeFieldName, EasySaveReflection.GetTypeString(type));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Create methods
|
||||
|
||||
/// <summary>Creates a new EasySaveWriter.</summary>
|
||||
/// <param name="filePath">The relative or absolute path of the file we want to write to.</param>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public static EasySaveWriter Create(string filePath, EasySaveSettings settings)
|
||||
{
|
||||
return Create(new EasySaveSettings(filePath, settings));
|
||||
}
|
||||
|
||||
/// <summary>Creates a new EasySaveWriter.</summary>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public static EasySaveWriter Create(EasySaveSettings settings)
|
||||
{
|
||||
return Create(settings, true, true, false);
|
||||
}
|
||||
|
||||
// Implicit Stream Methods.
|
||||
internal static EasySaveWriter Create(EasySaveSettings settings, bool writeHeaderAndFooter, bool overwriteKeys, bool append)
|
||||
{
|
||||
var stream = EasySaveStream.CreateStream(settings, (append ? EasySaveFileMode.Append : EasySaveFileMode.Write));
|
||||
if(stream == null)
|
||||
return null;
|
||||
return Create(stream, settings, writeHeaderAndFooter, overwriteKeys);
|
||||
}
|
||||
|
||||
// Explicit Stream Methods.
|
||||
|
||||
internal static EasySaveWriter Create(Stream stream, EasySaveSettings settings, bool writeHeaderAndFooter, bool overwriteKeys)
|
||||
{
|
||||
if(stream.GetType() == typeof(MemoryStream))
|
||||
internal virtual void StartWriteFile()
|
||||
{
|
||||
settings = (EasySaveSettings)settings.Clone();
|
||||
settings.location = EasySave.Location.InternalMS;
|
||||
serializationDepth++;
|
||||
}
|
||||
|
||||
// Get the baseWriter using the given Stream.
|
||||
if(settings.format == EasySave.Format.JSON)
|
||||
return new EasySaveJSONWriter(stream, settings, writeHeaderAndFooter, overwriteKeys);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/*
|
||||
* Checks whether serialization depth limit has been exceeded
|
||||
*/
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
protected bool SerializationDepthLimitExceeded()
|
||||
{
|
||||
if (serializationDepth > settings.serializationDepthLimit)
|
||||
{
|
||||
//ES3Debug.LogWarning("Serialization depth limit of " + settings.serializationDepthLimit + " has been exceeded, indicating that there may be a circular reference.\nIf this is not a circular reference, you can increase the depth by going to Window > Easy Save 3 > Settings > Advanced Settings > Serialization Depth Limit");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Marks a key for deletion.
|
||||
* When merging files, keys marked for deletion will not be included.
|
||||
*/
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public virtual void MarkKeyForDeletion(string key)
|
||||
{
|
||||
keysToDelete.Add(key);
|
||||
}
|
||||
|
||||
/*
|
||||
* Merges the contents of the non-temporary file with this EasySaveWriter,
|
||||
* ignoring any keys which are marked for deletion.
|
||||
*/
|
||||
protected void Merge()
|
||||
{
|
||||
using(var reader = EasySaveReader.Create(settings))
|
||||
internal virtual void EndWriteFile()
|
||||
{
|
||||
if(reader == null)
|
||||
serializationDepth--;
|
||||
}
|
||||
|
||||
internal virtual void StartWriteObject(string name)
|
||||
{
|
||||
serializationDepth++;
|
||||
}
|
||||
|
||||
internal virtual void EndWriteObject(string name)
|
||||
{
|
||||
serializationDepth--;
|
||||
}
|
||||
|
||||
internal virtual void StartWriteProperty(string name)
|
||||
{
|
||||
if (name == null)
|
||||
throw new ArgumentNullException("Key or field name cannot be NULL when saving data.");
|
||||
}
|
||||
|
||||
internal virtual void EndWriteProperty(string name)
|
||||
{
|
||||
}
|
||||
|
||||
internal virtual void StartWriteCollection()
|
||||
{
|
||||
serializationDepth++;
|
||||
}
|
||||
|
||||
internal virtual void EndWriteCollection()
|
||||
{
|
||||
serializationDepth--;
|
||||
}
|
||||
|
||||
internal abstract void StartWriteCollectionItem(int index);
|
||||
internal abstract void EndWriteCollectionItem(int index);
|
||||
|
||||
internal abstract void StartWriteDictionary();
|
||||
internal abstract void EndWriteDictionary();
|
||||
internal abstract void StartWriteDictionaryKey(int index);
|
||||
internal abstract void EndWriteDictionaryKey(int index);
|
||||
internal abstract void StartWriteDictionaryValue(int index);
|
||||
internal abstract void EndWriteDictionaryValue(int index);
|
||||
|
||||
public abstract void Dispose();
|
||||
|
||||
#endregion
|
||||
|
||||
#region ES3Writer Interface abstract methods
|
||||
|
||||
internal abstract void WriteRawProperty(string name, byte[] bytes);
|
||||
|
||||
internal abstract void WritePrimitive(int value);
|
||||
internal abstract void WritePrimitive(float value);
|
||||
internal abstract void WritePrimitive(bool value);
|
||||
internal abstract void WritePrimitive(decimal value);
|
||||
internal abstract void WritePrimitive(double value);
|
||||
internal abstract void WritePrimitive(long value);
|
||||
internal abstract void WritePrimitive(ulong value);
|
||||
internal abstract void WritePrimitive(uint value);
|
||||
internal abstract void WritePrimitive(byte value);
|
||||
internal abstract void WritePrimitive(sbyte value);
|
||||
internal abstract void WritePrimitive(short value);
|
||||
internal abstract void WritePrimitive(ushort value);
|
||||
internal abstract void WritePrimitive(char value);
|
||||
internal abstract void WritePrimitive(string value);
|
||||
internal abstract void WritePrimitive(byte[] value);
|
||||
|
||||
#endregion
|
||||
|
||||
protected EasySaveWriter(EasySaveSettings settings, bool writeHeaderAndFooter, bool overwriteKeys)
|
||||
{
|
||||
this.settings = settings;
|
||||
this.writeHeaderAndFooter = writeHeaderAndFooter;
|
||||
this.overwriteKeys = overwriteKeys;
|
||||
}
|
||||
|
||||
/* User-facing methods used when writing randomly-accessible Key-Value pairs. */
|
||||
#region Write(key, value) Methods
|
||||
|
||||
internal virtual void Write(string key, Type type, byte[] value)
|
||||
{
|
||||
StartWriteProperty(key);
|
||||
StartWriteObject(key);
|
||||
WriteType(type);
|
||||
WriteRawProperty("value", value);
|
||||
EndWriteObject(key);
|
||||
EndWriteProperty(key);
|
||||
MarkKeyForDeletion(key);
|
||||
}
|
||||
|
||||
/// <summary>Writes a value to the writer with the given key.</summary>
|
||||
/// <param name="key">The key which uniquely identifies this value.</param>
|
||||
/// <param name="value">The value we want to write.</param>
|
||||
public virtual void Write<T>(string key, object value)
|
||||
{
|
||||
if (typeof(T) == typeof(object))
|
||||
Write(value.GetType(), key, value);
|
||||
else
|
||||
Write(typeof(T), key, value);
|
||||
}
|
||||
|
||||
/// <summary>Writes a value to the writer with the given key, using the given type rather than the generic parameter.</summary>
|
||||
/// <param name="key">The key which uniquely identifies this value.</param>
|
||||
/// <param name="value">The value we want to write.</param>
|
||||
/// <param name="type">The type we want to use for the header, and to retrieve an EasySaveType.</param>
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public virtual void Write(Type type, string key, object value)
|
||||
{
|
||||
StartWriteProperty(key);
|
||||
StartWriteObject(key);
|
||||
WriteType(type);
|
||||
WriteProperty("value", value, EasySaveTypeMgr.GetOrCreateEasySaveType(type), settings.referenceMode);
|
||||
EndWriteObject(key);
|
||||
EndWriteProperty(key);
|
||||
MarkKeyForDeletion(key);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Write(value) & Write(value, EasySaveType) Methods
|
||||
|
||||
/// <summary>Writes a value to the writer. Note that this should only be called within an EasySaveType.</summary>
|
||||
/// <param name="value">The value we want to write.</param>
|
||||
/// <param name="memberReferenceMode">Whether we want to write UnityEngine.Object fields and properties by reference, by value, or both.</param>
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public virtual void Write(object value, EasySave.ReferenceMode memberReferenceMode = EasySave.ReferenceMode.ByRef)
|
||||
{
|
||||
if (value == null) { WriteNull(); return; }
|
||||
|
||||
var type = EasySaveTypeMgr.GetOrCreateEasySaveType(value.GetType());
|
||||
Write(value, type, memberReferenceMode);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public virtual void Write(object value, EasySaveType type, EasySave.ReferenceMode memberReferenceMode = EasySave.ReferenceMode.ByRef)
|
||||
{
|
||||
// Note that we have to check UnityEngine.Object types for null by casting it first, otherwise
|
||||
// it will always return false.
|
||||
if (value == null)
|
||||
{
|
||||
WriteNull();
|
||||
return;
|
||||
Merge(reader);
|
||||
}
|
||||
|
||||
// Deal with System.Objects
|
||||
if (type == null || type.type == typeof(object))
|
||||
{
|
||||
var valueType = value.GetType();
|
||||
type = EasySaveTypeMgr.GetOrCreateEasySaveType(valueType);
|
||||
|
||||
if (type == null)
|
||||
throw new NotSupportedException("Types of " + valueType + " are not supported. Please see the Supported Types guide for more information: https://docs.moodkie.com/easy-save-3/es3-supported-types/");
|
||||
|
||||
if (!type.isCollection && !type.isDictionary)
|
||||
{
|
||||
StartWriteObject(null);
|
||||
WriteType(valueType);
|
||||
|
||||
type.Write(value, this);
|
||||
|
||||
EndWriteObject(null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("EasySaveType argument cannot be null.");
|
||||
if (type.isUnsupported)
|
||||
{
|
||||
if (type.isCollection || type.isDictionary)
|
||||
throw new NotSupportedException(type.type + " is not supported because it's element type is not supported. Please see the Supported Types guide for more information: https://docs.moodkie.com/easy-save-3/es3-supported-types/");
|
||||
else
|
||||
throw new NotSupportedException("Types of " + type.type + " are not supported. Please see the Supported Types guide for more information: https://docs.moodkie.com/easy-save-3/es3-supported-types/");
|
||||
}
|
||||
|
||||
if (type.isPrimitive || type.isEnum)
|
||||
type.Write(value, this);
|
||||
else if (type.isCollection)
|
||||
{
|
||||
StartWriteCollection();
|
||||
((ECollectionType)type).Write(value, this, memberReferenceMode);
|
||||
EndWriteCollection();
|
||||
}
|
||||
else if (type.isDictionary)
|
||||
{
|
||||
StartWriteDictionary();
|
||||
((EasySaveDictionaryType)type).Write(value, this, memberReferenceMode);
|
||||
EndWriteDictionary();
|
||||
}
|
||||
else
|
||||
{
|
||||
StartWriteObject(null);
|
||||
type.Write(value, this);
|
||||
EndWriteObject(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Merges the contents of the EasySaveReader with this EasySaveWriter,
|
||||
* ignoring any keys which are marked for deletion.
|
||||
*/
|
||||
protected void Merge(EasySaveReader reader)
|
||||
{
|
||||
foreach(KeyValuePair<string,EasySaveData> kvp in reader.RawEnumerator)
|
||||
if(!keysToDelete.Contains(kvp.Key) || kvp.Value.type == null) // Don't add keys whose data is of a type which no longer exists in the project.
|
||||
Write(kvp.Key, kvp.Value.type.type, kvp.Value.bytes);
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>Stores the contents of the writer and overwrites any existing keys if overwriting is enabled.</summary>
|
||||
public virtual void Save()
|
||||
{
|
||||
Save(overwriteKeys);
|
||||
}
|
||||
/* Writes a property as a name value pair. */
|
||||
#region WriteProperty(name, value) methods
|
||||
|
||||
/// <summary>Stores the contents of the writer and overwrites any existing keys if overwriting is enabled.</summary>
|
||||
/// <param name="overwriteKeys">Whether we should overwrite existing keys.</param>
|
||||
public virtual void Save(bool overwriteKeys)
|
||||
{
|
||||
if(overwriteKeys)
|
||||
Merge();
|
||||
EndWriteFile();
|
||||
Dispose();
|
||||
/// <summary>Writes a field or property to the writer. Note that this should only be called within an EasySaveType.</summary>
|
||||
/// <param name="name">The name of the field or property.</param>
|
||||
/// <param name="value">The value we want to write.</param>
|
||||
public virtual void WriteProperty(string name, object value)
|
||||
{
|
||||
WriteProperty(name, value, settings.memberReferenceMode);
|
||||
}
|
||||
|
||||
// If we're writing to a location which can become corrupted, rename the backup file to the file we want.
|
||||
// This prevents corrupt data.
|
||||
if(settings.location == EasySave.Location.File)
|
||||
EasySaveIO.CommitBackup(settings);
|
||||
/// <summary>Writes a field or property to the writer. Note that this should only be called within an EasySaveType.</summary>
|
||||
/// <param name="name">The name of the field or property.</param>
|
||||
/// <param name="value">The value we want to write.</param>
|
||||
/// <param name="memberReferenceMode">Whether we want to write the property by reference, by value, or both.</param>
|
||||
public virtual void WriteProperty(string name, object value, EasySave.ReferenceMode memberReferenceMode)
|
||||
{
|
||||
if (SerializationDepthLimitExceeded())
|
||||
return;
|
||||
|
||||
StartWriteProperty(name); Write(value, memberReferenceMode); EndWriteProperty(name);
|
||||
}
|
||||
|
||||
/// <summary>Writes a field or property to the writer. Note that this should only be called within an EasySaveType.</summary>
|
||||
/// <param name="name">The name of the field or property.</param>
|
||||
/// <param name="value">The value we want to write.</param>
|
||||
public virtual void WriteProperty<T>(string name, object value)
|
||||
{
|
||||
WriteProperty(name, value, EasySaveTypeMgr.GetOrCreateEasySaveType(typeof(T)), settings.memberReferenceMode);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public virtual void WriteProperty(string name, object value, EasySaveType type)
|
||||
{
|
||||
WriteProperty(name, value, type, settings.memberReferenceMode);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public virtual void WriteProperty(string name, object value, EasySaveType type, EasySave.ReferenceMode memberReferenceMode)
|
||||
{
|
||||
if (SerializationDepthLimitExceeded())
|
||||
return;
|
||||
|
||||
StartWriteProperty(name);
|
||||
Write(value, type, memberReferenceMode);
|
||||
EndWriteProperty(name);
|
||||
}
|
||||
|
||||
/// <summary>Writes a private property to the writer. Note that this should only be called within an EasySaveType.</summary>
|
||||
/// <param name="name">The name of the property.</param>
|
||||
/// <param name="objectContainingProperty">The object containing the property we want to write.</param>
|
||||
public void WritePrivateProperty(string name, 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());
|
||||
WriteProperty(name, property.GetValue(objectContainingProperty), EasySaveTypeMgr.GetOrCreateEasySaveType(property.MemberType));
|
||||
}
|
||||
|
||||
/// <summary>Writes a private field to the writer. Note that this should only be called within an EasySaveType.</summary>
|
||||
/// <param name="name">The name of the field.</param>
|
||||
/// <param name="objectContainingField">The object containing the property we want to write.</param>
|
||||
public void WritePrivateField(string name, 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());
|
||||
WriteProperty(name, field.GetValue(objectContainingField), EasySaveTypeMgr.GetOrCreateEasySaveType(field.MemberType));
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public void WritePrivateProperty(string name, object objectContainingProperty, EasySaveType type)
|
||||
{
|
||||
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());
|
||||
WriteProperty(name, property.GetValue(objectContainingProperty), type);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public void WritePrivateField(string name, object objectContainingField, EasySaveType type)
|
||||
{
|
||||
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());
|
||||
WriteProperty(name, field.GetValue(objectContainingField), type);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public void WriteType(Type type)
|
||||
{
|
||||
WriteProperty(EasySaveType.typeFieldName, EasySaveReflection.GetTypeString(type));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Create methods
|
||||
|
||||
/// <summary>Creates a new EasySaveWriter.</summary>
|
||||
/// <param name="filePath">The relative or absolute path of the file we want to write to.</param>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public static EasySaveWriter Create(string filePath, EasySaveSettings settings)
|
||||
{
|
||||
return Create(new EasySaveSettings(filePath, settings));
|
||||
}
|
||||
|
||||
/// <summary>Creates a new EasySaveWriter.</summary>
|
||||
/// <param name="settings">The settings we want to use to override the default settings.</param>
|
||||
public static EasySaveWriter Create(EasySaveSettings settings)
|
||||
{
|
||||
return Create(settings, true, true, false);
|
||||
}
|
||||
|
||||
// Implicit Stream Methods.
|
||||
internal static EasySaveWriter Create(EasySaveSettings settings, bool writeHeaderAndFooter, bool overwriteKeys, bool append)
|
||||
{
|
||||
var stream = EasySaveStream.CreateStream(settings, (append ? EasySaveFileMode.Append : EasySaveFileMode.Write));
|
||||
if (stream == null)
|
||||
return null;
|
||||
return Create(stream, settings, writeHeaderAndFooter, overwriteKeys);
|
||||
}
|
||||
|
||||
// Explicit Stream Methods.
|
||||
|
||||
internal static EasySaveWriter Create(Stream stream, EasySaveSettings settings, bool writeHeaderAndFooter, bool overwriteKeys)
|
||||
{
|
||||
if (stream.GetType() == typeof(MemoryStream))
|
||||
{
|
||||
settings = (EasySaveSettings)settings.Clone();
|
||||
settings.location = EasySave.Location.InternalMS;
|
||||
}
|
||||
|
||||
// Get the baseWriter using the given Stream.
|
||||
if (settings.format == EasySave.Format.JSON)
|
||||
return new EasySaveJSONWriter(stream, settings, writeHeaderAndFooter, overwriteKeys);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/*
|
||||
* Checks whether serialization depth limit has been exceeded
|
||||
*/
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
protected bool SerializationDepthLimitExceeded()
|
||||
{
|
||||
if (serializationDepth > settings.serializationDepthLimit)
|
||||
{
|
||||
//ES3Debug.LogWarning("Serialization depth limit of " + settings.serializationDepthLimit + " has been exceeded, indicating that there may be a circular reference.\nIf this is not a circular reference, you can increase the depth by going to Window > Easy Save 3 > Settings > Advanced Settings > Serialization Depth Limit");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Marks a key for deletion.
|
||||
* When merging files, keys marked for deletion will not be included.
|
||||
*/
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
public virtual void MarkKeyForDeletion(string key)
|
||||
{
|
||||
keysToDelete.Add(key);
|
||||
}
|
||||
|
||||
/*
|
||||
* Merges the contents of the non-temporary file with this EasySaveWriter,
|
||||
* ignoring any keys which are marked for deletion.
|
||||
*/
|
||||
protected void Merge()
|
||||
{
|
||||
using (var reader = EasySaveReader.Create(settings))
|
||||
{
|
||||
if (reader == null)
|
||||
return;
|
||||
Merge(reader);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Merges the contents of the EasySaveReader with this EasySaveWriter,
|
||||
* ignoring any keys which are marked for deletion.
|
||||
*/
|
||||
protected void Merge(EasySaveReader reader)
|
||||
{
|
||||
foreach (KeyValuePair<string, EasySaveData> kvp in reader.RawEnumerator)
|
||||
if (!keysToDelete.Contains(kvp.Key) || kvp.Value.type == null) // Don't add keys whose data is of a type which no longer exists in the project.
|
||||
Write(kvp.Key, kvp.Value.type.type, kvp.Value.bytes);
|
||||
}
|
||||
|
||||
/// <summary>Stores the contents of the writer and overwrites any existing keys if overwriting is enabled.</summary>
|
||||
public virtual void Save()
|
||||
{
|
||||
Save(overwriteKeys);
|
||||
}
|
||||
|
||||
/// <summary>Stores the contents of the writer and overwrites any existing keys if overwriting is enabled.</summary>
|
||||
/// <param name="overwriteKeys">Whether we should overwrite existing keys.</param>
|
||||
public virtual void Save(bool overwriteKeys)
|
||||
{
|
||||
if (overwriteKeys)
|
||||
Merge();
|
||||
EndWriteFile();
|
||||
Dispose();
|
||||
|
||||
// If we're writing to a location which can become corrupted, rename the backup file to the file we want.
|
||||
// This prevents corrupt data.
|
||||
if (settings.location == EasySave.Location.File)
|
||||
EasySaveIO.CommitBackup(settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using Convention;
|
||||
using Convention.EasySave;
|
||||
|
||||
public class Program
|
||||
{
|
||||
@@ -17,6 +19,8 @@ public class Program
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Directory.CreateDirectory(PlatformIndicator.PersistentDataPath);
|
||||
Console.WriteLine(PlatformIndicator.PersistentDataPath);
|
||||
EasySave.Save("key", new Vector2X2()
|
||||
{
|
||||
x = 10,
|
||||
|
Reference in New Issue
Block a user