public void Serialize(Stream output)
        {
            var saveGame = this.SaveGame;

            byte[] innerUncompressedBytes;
            using (var innerUncompressedData = new MemoryStream())
            {
                saveGame.Compose();
                try
                {
                    ProtoBuf.Serializer.Serialize(innerUncompressedData, saveGame);
                }
                finally
                {
                    saveGame.Decompose();
                }
                innerUncompressedData.Position = 0;
                innerUncompressedBytes = innerUncompressedData.ReadBytes((uint)innerUncompressedData.Length);
            }

            byte[] innerCompressedBytes;
            using (var innerCompressedData = new MemoryStream())
            {
                var endian = this.Endian;

                innerCompressedData.WriteValueS32(0, Endian.Big);
                innerCompressedData.WriteString("WSG");
                innerCompressedData.WriteValueU32(2, endian);
                innerCompressedData.WriteValueU32(CRC32.Hash(innerUncompressedBytes, 0, innerUncompressedBytes.Length),
                                                  endian); // crc32
                innerCompressedData.WriteValueS32(innerUncompressedBytes.Length, endian);

                var encoder = new Huffman.Encoder();
                encoder.Build(innerUncompressedBytes);
                innerCompressedData.WriteBytes(encoder.Encode(innerUncompressedBytes));

                innerCompressedData.Position = 0;
                innerCompressedData.WriteValueU32((uint)(innerCompressedData.Length - 4), Endian.Big);

                innerCompressedData.Position = 0;
                innerCompressedBytes = innerCompressedData.ReadBytes((uint)innerCompressedData.Length);
            }

            byte[] compressedBytes;

            if (innerCompressedBytes.Length <= BlockSize)
            {
                compressedBytes = new byte[innerCompressedBytes.Length +
                                           (innerCompressedBytes.Length / 16) + 64 + 3];
                var actualCompressedSize = compressedBytes.Length;

                var result = LZO.Compress(innerCompressedBytes,
                                          0,
                                          innerCompressedBytes.Length,
                                          compressedBytes,
                                          0,
                                          ref actualCompressedSize);
                if (result != LZO.ErrorCode.Success)
                {
                    throw new SaveCorruptionException(string.Format("LZO compression failure ({0})", result));
                }

                Array.Resize(ref compressedBytes, actualCompressedSize);
            }
            else
            {
                int innerCompressedOffset = 0;
                int innerCompressedSizeLeft = innerCompressedBytes.Length;

                using (var blockData = new MemoryStream())
                {
                    var blockCount = (innerCompressedSizeLeft + BlockSize) / BlockSize;
                    blockData.WriteValueS32(blockCount, Endian.Big);

                    blockData.Position = 4 + (blockCount * 8);

                    var blockInfos = new List<Tuple<uint, uint>>();
                    while (innerCompressedSizeLeft > 0)
                    {
                        var blockUncompressedSize = Math.Min(BlockSize, innerCompressedSizeLeft);

                        compressedBytes = new byte[blockUncompressedSize +
                                                   (blockUncompressedSize / 16) + 64 + 3];
                        var actualCompressedSize = compressedBytes.Length;

                        var result = LZO.Compress(innerCompressedBytes,
                                                  innerCompressedOffset,
                                                  blockUncompressedSize,
                                                  compressedBytes,
                                                  0,
                                                  ref actualCompressedSize);
                        if (result != LZO.ErrorCode.Success)
                        {
                            throw new SaveCorruptionException(string.Format("LZO compression failure ({0})", result));
                        }

                        blockData.Write(compressedBytes, 0, actualCompressedSize);
                        blockInfos.Add(new Tuple<uint, uint>((uint)actualCompressedSize, BlockSize));

                        innerCompressedOffset += blockUncompressedSize;
                        innerCompressedSizeLeft -= blockUncompressedSize;
                    }

                    blockData.Position = 4;
                    foreach (var blockInfo in blockInfos)
                    {
                        blockData.WriteValueU32(blockInfo.Item1, Endian.Big);
                        blockData.WriteValueU32(blockInfo.Item2, Endian.Big);
                    }

                    blockData.Position = 0;
                    compressedBytes = blockData.ReadBytes((uint)blockData.Length);
                }
            }

            byte[] uncompressedBytes;
            using (var uncompressedData = new MemoryStream())
            {
                uncompressedData.WriteValueS32(innerCompressedBytes.Length, Endian.Big);
                uncompressedData.WriteBytes(compressedBytes);
                uncompressedData.Position = 0;
                uncompressedBytes = uncompressedData.ReadBytes((uint)uncompressedData.Length);
            }

            byte[] computedHash;
            using (var sha1 = new System.Security.Cryptography.SHA1Managed())
            {
                computedHash = sha1.ComputeHash(uncompressedBytes);
            }

            output.WriteBytes(computedHash);
            output.WriteBytes(uncompressedBytes);
        }
Пример #2
0
        public void Serialize(Stream output)
        {
            var saveGame = this.SaveGame;

            if (IsSupportedPlatform(this.Platform) == false)
            {
                throw new InvalidOperationException("unsupported platform");
            }

            var endian            = this.Platform.GetEndian();
            var compressionScheme = this.Platform.GetCompressionScheme();

            byte[] innerUncompressedBytes;
            using (var innerUncompressedData = new MemoryStream())
            {
                if (this.PlayerStats != null)
                {
                    saveGame.StatsData = this.PlayerStats.Serialize(endian);
                }

                ProtoSerializer.Serialize(innerUncompressedData, saveGame);
                innerUncompressedData.Position = 0;
                innerUncompressedBytes         = innerUncompressedData.ReadBytes((uint)innerUncompressedData.Length);
            }

            byte[] innerCompressedBytes;
            using (var innerCompressedData = new MemoryStream())
            {
                var hash = CRC32.Hash(innerUncompressedBytes, 0, innerUncompressedBytes.Length);

                innerCompressedData.WriteValueS32(0, Endian.Big);
                innerCompressedData.WriteString("WSG");
                innerCompressedData.WriteValueU32(2, endian);
                innerCompressedData.WriteValueU32(hash, endian);
                innerCompressedData.WriteValueS32(innerUncompressedBytes.Length, endian);

                var encoder = new Huffman.Encoder();
                encoder.Build(innerUncompressedBytes);
                innerCompressedData.WriteBytes(encoder.Encode(innerUncompressedBytes));

                innerCompressedData.Position = 0;
                innerCompressedData.WriteValueU32((uint)(innerCompressedData.Length - 4), Endian.Big);

                innerCompressedData.Position = 0;
                innerCompressedBytes         = innerCompressedData.ReadBytes((uint)innerCompressedData.Length);
            }

            byte[] compressedBytes;

            if (innerCompressedBytes.Length <= BlockSize)
            {
                if (compressionScheme == CompressionScheme.LZO)
                {
                    compressedBytes = new byte[innerCompressedBytes.Length +
                                               (innerCompressedBytes.Length / 16) + 64 + 3];
                    var actualCompressedSize = compressedBytes.Length;
                    var result = MiniLZO.LZO.Compress(
                        innerCompressedBytes,
                        0,
                        innerCompressedBytes.Length,
                        compressedBytes,
                        0,
                        ref actualCompressedSize,
                        new MiniLZO.CompressWorkBuffer());
                    if (result != MiniLZO.ErrorCode.Success)
                    {
                        throw new SaveCorruptionException(string.Format("LZO compression failure ({0})", result));
                    }

                    Array.Resize(ref compressedBytes, actualCompressedSize);
                }
                else if (compressionScheme == CompressionScheme.Zlib)
                {
                    using (var temp = new MemoryStream())
                    {
                        var zlib = new DeflaterOutputStream(temp);
                        zlib.WriteBytes(innerCompressedBytes);
                        zlib.Finish();
                        temp.Flush();
                        temp.Position   = 0;
                        compressedBytes = temp.ReadBytes((uint)temp.Length);
                    }
                }
                else
                {
                    throw new InvalidOperationException("unsupported compression scheme");
                }
            }
            else
            {
                if (compressionScheme == CompressionScheme.LZO)
                {
                    int innerCompressedOffset   = 0;
                    int innerCompressedSizeLeft = innerCompressedBytes.Length;

                    using (var blockData = new MemoryStream())
                    {
                        var blockCount = (innerCompressedSizeLeft + BlockSize) / BlockSize;
                        blockData.WriteValueS32(blockCount, Endian.Big);

                        blockData.Position = 4 + (blockCount * 8);

                        var blockInfos = new List <Tuple <uint, uint> >();
                        while (innerCompressedSizeLeft > 0)
                        {
                            var blockUncompressedSize = Math.Min(BlockSize, innerCompressedSizeLeft);

                            compressedBytes = new byte[blockUncompressedSize +
                                                       (blockUncompressedSize / 16) + 64 + 3];
                            var actualCompressedSize = compressedBytes.Length;
                            var result = MiniLZO.LZO.Compress(
                                innerCompressedBytes,
                                innerCompressedOffset,
                                blockUncompressedSize,
                                compressedBytes,
                                0,
                                ref actualCompressedSize,
                                new MiniLZO.CompressWorkBuffer());
                            if (result != MiniLZO.ErrorCode.Success)
                            {
                                throw new SaveCorruptionException(string.Format("LZO compression failure ({0})", result));
                            }

                            blockData.Write(compressedBytes, 0, actualCompressedSize);
                            blockInfos.Add(new Tuple <uint, uint>((uint)actualCompressedSize, BlockSize));

                            innerCompressedOffset   += blockUncompressedSize;
                            innerCompressedSizeLeft -= blockUncompressedSize;
                        }

                        blockData.Position = 4;
                        foreach (var blockInfo in blockInfos)
                        {
                            blockData.WriteValueU32(blockInfo.Item1, Endian.Big);
                            blockData.WriteValueU32(blockInfo.Item2, Endian.Big);
                        }

                        blockData.Position = 0;
                        compressedBytes    = blockData.ReadBytes((uint)blockData.Length);
                    }
                }
                else if (compressionScheme == CompressionScheme.Zlib)
                {
                    int innerCompressedOffset   = 0;
                    int innerCompressedSizeLeft = innerCompressedBytes.Length;

                    using (var blockData = new MemoryStream())
                    {
                        var blockCount = (innerCompressedSizeLeft + BlockSize) / BlockSize;
                        blockData.WriteValueS32(blockCount, Endian.Big);

                        blockData.Position = 4 + (blockCount * 8);

                        var blockInfos = new List <Tuple <uint, uint> >();
                        while (innerCompressedSizeLeft > 0)
                        {
                            var blockUncompressedSize = Math.Min(BlockSize, innerCompressedSizeLeft);

                            using (var temp = new MemoryStream())
                            {
                                var zlib = new DeflaterOutputStream(temp);
                                zlib.Write(innerCompressedBytes, innerCompressedOffset, blockUncompressedSize);
                                zlib.Finish();
                                temp.Flush();

                                temp.Position   = 0;
                                compressedBytes = temp.ReadBytes((uint)temp.Length);
                            }

                            blockData.WriteBytes(compressedBytes);
                            blockInfos.Add(new Tuple <uint, uint>((uint)compressedBytes.Length, BlockSize));

                            innerCompressedOffset   += blockUncompressedSize;
                            innerCompressedSizeLeft -= blockUncompressedSize;
                        }

                        blockData.Position = 4;
                        foreach (var blockInfo in blockInfos)
                        {
                            blockData.WriteValueU32(blockInfo.Item1, Endian.Big);
                            blockData.WriteValueU32(blockInfo.Item2, Endian.Big);
                        }

                        blockData.Position = 0;
                        compressedBytes    = blockData.ReadBytes((uint)blockData.Length);
                    }
                }
                else
                {
                    throw new InvalidOperationException("unsupported platform");
                }
            }

            byte[] uncompressedBytes;
            using (var uncompressedData = new MemoryStream())
            {
                uncompressedData.WriteValueS32(innerCompressedBytes.Length, Endian.Big);
                uncompressedData.WriteBytes(compressedBytes);
                uncompressedData.Position = 0;
                uncompressedBytes         = uncompressedData.ReadBytes((uint)uncompressedData.Length);
            }

            byte[] computedHash;
            using (var sha1 = new System.Security.Cryptography.SHA1Managed())
            {
                computedHash = sha1.ComputeHash(uncompressedBytes);
            }

            output.WriteBytes(computedHash);
            output.WriteBytes(uncompressedBytes);
        }
Пример #3
0
        public void Serialize(Stream output)
        {
            var saveGame = this.SaveGame;

            byte[] innerUncompressedBytes;
            using (var innerUncompressedData = new MemoryStream())
            {
                saveGame.Compose();
                try
                {
                    ProtoBuf.Serializer.Serialize(innerUncompressedData, saveGame);
                }
                finally
                {
                    saveGame.Decompose();
                }
                innerUncompressedData.Position = 0;
                innerUncompressedBytes         = innerUncompressedData.ReadBytes((uint)innerUncompressedData.Length);
            }

            byte[] innerCompressedBytes;
            using (var innerCompressedData = new MemoryStream())
            {
                var endian = this.Endian;

                innerCompressedData.WriteValueS32(0, Endian.Big);
                innerCompressedData.WriteString("WSG");
                innerCompressedData.WriteValueU32(2, endian);
                innerCompressedData.WriteValueU32(CRC32.Hash(innerUncompressedBytes, 0, innerUncompressedBytes.Length),
                                                  endian); // crc32
                innerCompressedData.WriteValueS32(innerUncompressedBytes.Length, endian);

                var encoder = new Huffman.Encoder();
                encoder.Build(innerUncompressedBytes);
                innerCompressedData.WriteBytes(encoder.Encode(innerUncompressedBytes));

                innerCompressedData.Position = 0;
                innerCompressedData.WriteValueU32((uint)(innerCompressedData.Length - 4), Endian.Big);

                innerCompressedData.Position = 0;
                innerCompressedBytes         = innerCompressedData.ReadBytes((uint)innerCompressedData.Length);
            }

            byte[] compressedBytes;

            if (innerCompressedBytes.Length <= BlockSize)
            {
                compressedBytes = new byte[innerCompressedBytes.Length +
                                           (innerCompressedBytes.Length / 16) + 64 + 3];
                var actualCompressedSize = compressedBytes.Length;

                var result = LZO.Compress(innerCompressedBytes,
                                          0,
                                          innerCompressedBytes.Length,
                                          compressedBytes,
                                          0,
                                          ref actualCompressedSize);
                if (result != LZO.ErrorCode.Success)
                {
                    throw new SaveCorruptionException(string.Format("LZO compression failure ({0})", result));
                }

                Array.Resize(ref compressedBytes, actualCompressedSize);
            }
            else
            {
                int innerCompressedOffset   = 0;
                int innerCompressedSizeLeft = innerCompressedBytes.Length;

                using (var blockData = new MemoryStream())
                {
                    var blockCount = (innerCompressedSizeLeft + BlockSize) / BlockSize;
                    blockData.WriteValueS32(blockCount, Endian.Big);

                    blockData.Position = 4 + (blockCount * 8);

                    var blockInfos = new List <Tuple <uint, uint> >();
                    while (innerCompressedSizeLeft > 0)
                    {
                        var blockUncompressedSize = Math.Min(BlockSize, innerCompressedSizeLeft);

                        compressedBytes = new byte[blockUncompressedSize +
                                                   (blockUncompressedSize / 16) + 64 + 3];
                        var actualCompressedSize = compressedBytes.Length;

                        var result = LZO.Compress(innerCompressedBytes,
                                                  innerCompressedOffset,
                                                  blockUncompressedSize,
                                                  compressedBytes,
                                                  0,
                                                  ref actualCompressedSize);
                        if (result != LZO.ErrorCode.Success)
                        {
                            throw new SaveCorruptionException(string.Format("LZO compression failure ({0})", result));
                        }

                        blockData.Write(compressedBytes, 0, actualCompressedSize);
                        blockInfos.Add(new Tuple <uint, uint>((uint)actualCompressedSize, BlockSize));

                        innerCompressedOffset   += blockUncompressedSize;
                        innerCompressedSizeLeft -= blockUncompressedSize;
                    }

                    blockData.Position = 4;
                    foreach (var blockInfo in blockInfos)
                    {
                        blockData.WriteValueU32(blockInfo.Item1, Endian.Big);
                        blockData.WriteValueU32(blockInfo.Item2, Endian.Big);
                    }

                    blockData.Position = 0;
                    compressedBytes    = blockData.ReadBytes((uint)blockData.Length);
                }
            }

            byte[] uncompressedBytes;
            using (var uncompressedData = new MemoryStream())
            {
                uncompressedData.WriteValueS32(innerCompressedBytes.Length, Endian.Big);
                uncompressedData.WriteBytes(compressedBytes);
                uncompressedData.Position = 0;
                uncompressedBytes         = uncompressedData.ReadBytes((uint)uncompressedData.Length);
            }

            byte[] computedHash;
            using (var sha1 = new System.Security.Cryptography.SHA1Managed())
            {
                computedHash = sha1.ComputeHash(uncompressedBytes);
            }

            output.WriteBytes(computedHash);
            output.WriteBytes(uncompressedBytes);
        }