public MemoryStream SaveToStream() { MemoryStream stream = null; string json = m_saveData.ToJSON(); //Compress the data using LZF compression byte[] compressed = null; using (MemoryStream compMemStream = new MemoryStream()) { using (StreamWriter writer = new StreamWriter(compMemStream, Encoding.UTF8)) { writer.Write(json); writer.Close(); compressed = CLZF2.Compress(compMemStream.ToArray()); } } if (compressed != null) { byte[] encrypted = AESEncryptor.Encrypt(m_cryptoKey, m_cryptoIV, compressed); if (encrypted != null) { stream = new MemoryStream(); //Write version and headers! byte[] version = SaveUtilities.SerializeVersion(HeaderVersion); stream.Write(version, 0, version.Length); byte[] header = SaveUtilities.SerializeHeader(m_modifiedTime, m_deviceName, SaveUtilities.CalculateMD5Hash(encrypted), encrypted.Length); stream.Write(header, 0, header.Length); //Write encrypted and compressed data to stream stream.Write(encrypted, 0, encrypted.Length); } } return(stream); }
private bool IsValidFile(Stream stream, ref byte[] contentBytes) { bool valid = false; string md5Hash = null; int headerLength = 0; int contentLength = 0; bool validHeader = SaveUtilities.DeserializeHeader(stream, ref headerLength, ref m_modifiedTime, ref m_deviceName, ref md5Hash, ref contentLength); if (validHeader) { contentBytes = new byte[contentLength]; int contentRead = stream.Read(contentBytes, 0, contentLength); if (contentRead == contentLength) { string contentHash = SaveUtilities.CalculateMD5Hash(contentBytes); if (md5Hash == contentHash) { valid = true; } else { Debug.LogError(string.Format("SaveData :: MD5 Checksum Failed (Got {0} expected {1})", md5Hash, contentHash)); } } else { Debug.LogError(string.Format("SaveData :: Content length different to expected (Got {0} expected {1})", contentRead, contentLength)); } } else { Debug.LogError("SaveData :: Invalid header detected!"); } return(valid); }
private LoadState LoadSave(User user, out SaveData loadedData) { m_savingEnabled = false; string saveID = !string.IsNullOrEmpty(user.saveID) ? user.saveID : LocalSaveID; SaveData save = new SaveData(saveID); Func <LoadState> loadSave = null; loadSave = delegate() { LoadState loadResult = save.Load(); switch (loadResult) { case LoadState.NotFound: if (save.Key != LocalSaveID) { Debug.Log("SaveGameManager (LoadSave) :: Haven't found save for saveID - " + saveID + " attempting to load local.sav instead!"); //If the save isn't found and we aren't trying to load a local save already then try to load a local save instead save = new SaveData(LocalSaveID); loadResult = loadSave(); if (loadResult == LoadState.OK) { Debug.Log("SaveGameManager (LoadSave) :: Found local.sav! Converting to user save"); save.UpdateSavePathAndKey(SaveUtilities.GetSavePath(saveID), saveID); SaveState state = save.Save(); //Note: possible save duplication exploit if (state == SaveState.OK) { //Delete old local.sav when done! string localSavePath = SaveUtilities.GetSavePath(LocalSaveID); try { if (File.Exists(localSavePath)) { File.Delete(localSavePath); } // Fix for HSW-5647 - delete the backup file as well as otherwise in some cases user can get a corrupted popup string backupPath = localSavePath + ".backup"; if (File.Exists(backupPath)) { File.Delete(backupPath); } } catch (Exception e) { Debug.LogWarning("SaveGameManager (LoadSave) :: Unable to delete " + localSavePath + " - " + e.Message); } } } } break; } return(loadResult); }; LoadState result = loadSave(); Action loadSystems = delegate() { if (result == LoadState.OK) { result = LoadSystems(save); if (result == LoadState.OK) { m_savingEnabled = true; } } }; //Check for valid results and enable saving if we are in a valid state! switch (result) { case LoadState.OK: //Now need to check game systems can load it! bool upgraded = false; result = UpgradeSystems(save, out upgraded); save.Version = m_version; //TODO only save on upgrade if (result == LoadState.OK && upgraded) { SaveToDisk(); } loadSystems(); break; case LoadState.NotFound: Debug.Log("SaveGameManager (LoadSave) :: No save found! Creating new save!"); //Create a new save result = LoadState.OK; loadSystems(); save.Version = m_version; if (result == LoadState.OK) { save.Save(); } break; default: loadSystems(); m_savingEnabled = false; break; } loadedData = save; return(result); }
public SaveData(string key) : this(SaveUtilities.GetSavePath(key), key) { }
public LoadState LoadFromStream(Stream stream) { LoadState state = LoadState.Corrupted; try { byte[] decompressed = null; byte[] contentBytes = null; bool versionOkay = false; //Check version first int headerVersion = SaveUtilities.DeserializeVersion(stream); if (headerVersion == -1) { state = LoadState.Corrupted; } else if (headerVersion < HeaderVersion) { stream = UpgradeFile(stream); if (stream != null) { versionOkay = true; } else { state = LoadState.Corrupted; } } else if (headerVersion > HeaderVersion) { state = LoadState.VersionMismatch; } else { versionOkay = true; } if (versionOkay) { if (IsValidFile(stream, ref contentBytes)) { byte[] decrypted = AESEncryptor.Decrypt(m_cryptoKey, m_cryptoIV, contentBytes); if (decrypted != null) { decompressed = CLZF2.Decompress(decrypted); } else { Debug.LogError("SaveData :: Decryption failed!"); state = LoadState.Corrupted; } } else { Debug.LogError("SaveData :: File Corrupted!"); state = LoadState.Corrupted; } } if (decompressed != null) { using (MemoryStream jsonMemoryStream = new MemoryStream(decompressed)) { using (StreamReader reader = new StreamReader(jsonMemoryStream)) { if (m_saveData.FromJSON(reader)) { state = LoadState.OK; } else { Debug.LogWarning("Trying to load invalid JSON file at path: " + m_savePath); state = LoadState.Corrupted; } } } } } catch (Exception e) { //TODO determine exception types and see if any are recoverable! Debug.LogWarning("Exception when parsing file from stream"); Debug.LogWarning(e); } return(state); }
public LoadState Load() { LoadState state = LoadState.NotFound; string savePath = null; if (File.Exists(m_savePath)) { savePath = m_savePath; } else if (File.Exists(m_saveTempPath)) { savePath = m_saveTempPath; } else if (File.Exists(m_saveBackupPath)) { savePath = m_saveBackupPath; } if (savePath != null) { try { using (MemoryStream ms = SaveUtilities.GetUnpaddedSaveData(savePath)) { state = LoadFromStream(ms); } } catch (UnauthorizedAccessException e) { Debug.LogError("Permissions error when loading file at path: " + savePath); Debug.LogException(e); state = LoadState.PermissionError; } catch (FileNotFoundException) { Debug.LogWarning("No save file found at path: " + savePath); } catch (Exception e) { Debug.LogError("Exception when loading file at path: " + savePath); Debug.LogException(e); state = LoadState.Corrupted; } } else { Debug.LogWarning("No save file found at path: " + savePath); } //If we can't load from disk try player prefs! Player prefs will be set if we detected an issue when saving! if (state != LoadState.OK) { string playerPrefKey = "Save." + m_key + ".sav"; string prefSaveString = PlayerPrefs.GetString(playerPrefKey); if (!string.IsNullOrEmpty(prefSaveString)) { try { using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(prefSaveString))) { state = LoadFromStream(ms); } } catch (Exception e) { Debug.LogWarning("Unable to parse save data in PlayerPrefs"); Debug.LogWarning(e); } } } return(state); }