using System; using System.IO; using System.IO.Compression; using System.Text; using Newtonsoft.Json; namespace Jovian.SaveSystem { /// /// Serializes data to an obfuscated binary format. /// Pipeline: JSON string → UTF-8 bytes → XOR obfuscation → DeflateStream compression. /// public sealed class BinarySaveSerializer : ISaveSerializer { private readonly byte[] keyBytes; private readonly JsonSerializerSettings serializerSettings; public BinarySaveSerializer(string obfuscationKey) { if(string.IsNullOrEmpty(obfuscationKey)) { throw new ArgumentException("Obfuscation key must not be null or empty.", nameof(obfuscationKey)); } keyBytes = Encoding.UTF8.GetBytes(obfuscationKey); serializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.None, NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }; } public byte[] Serialize(TData data) { string json = JsonConvert.SerializeObject(data, serializerSettings); byte[] jsonBytes = Encoding.UTF8.GetBytes(json); byte[] obfuscated = ApplyXor(jsonBytes); return Compress(obfuscated); } public TData Deserialize(byte[] payload) { if(payload == null || payload.Length == 0) { throw new ArgumentException("Payload is null or empty.", nameof(payload)); } byte[] decompressed = Decompress(payload); byte[] deobfuscated = ApplyXor(decompressed); string json = Encoding.UTF8.GetString(deobfuscated); return JsonConvert.DeserializeObject(json, serializerSettings); } private byte[] ApplyXor(byte[] data) { byte[] result = new byte[data.Length]; for(int i = 0; i < data.Length; i++) { result[i] = (byte)(data[i] ^ keyBytes[i % keyBytes.Length]); } return result; } private static byte[] Compress(byte[] data) { using(MemoryStream output = new MemoryStream()) { using(DeflateStream deflate = new DeflateStream(output, CompressionLevel.Fastest, leaveOpen: true)) { deflate.Write(data, 0, data.Length); } return output.ToArray(); } } private static byte[] Decompress(byte[] data) { using(MemoryStream input = new MemoryStream(data)) { using(DeflateStream deflate = new DeflateStream(input, CompressionMode.Decompress)) { using(MemoryStream output = new MemoryStream()) { deflate.CopyTo(output); return output.ToArray(); } } } } } }