Example #1
0
        /// <summary>
        /// Apply patch data from given <see cref="Stream"/> to the ROM.
        /// </summary>
        /// <param name="inStream">Input stream.</param>
        /// <returns><see cref="SHA256"/> hash of the patch.</returns>
        public static byte[] ApplyPatch(Stream inStream)
        {
            try
            {
                var aes     = Aes.Create();
                var hashAlg = new SHA256Managed();
                using (var cryptoStream = new CryptoStream(inStream, aes.CreateDecryptor(key, iv), CryptoStreamMode.Read))
                    using (var hashStream = new CryptoStream(cryptoStream, hashAlg, CryptoStreamMode.Read))
                        using (var decompressStream = new GZipStream(hashStream, CompressionMode.Decompress))
                            using (var memoryStream = new MemoryStream())
                            {
                                // Fully decompress into MemoryStream so that we can access Position to check for end of Stream.
                                decompressStream.CopyTo(memoryStream);
                                memoryStream.Seek(0, SeekOrigin.Begin);
                                using var reader = new BeBinaryReader(memoryStream);

                                // Validate patch magic.
                                var magic = reader.ReadUInt32();
                                ValidateMagic(magic);

                                Span <byte> headerBytes = stackalloc byte[PatchHeader.Size];
                                while (reader.BaseStream.Position != reader.BaseStream.Length)
                                {
                                    // Read header bytes into stack buffer to prevent allocation.
                                    reader.ReadExact(headerBytes);
                                    var header = PatchHeader.Read(headerBytes);
                                    var data   = reader.ReadBytes(header.Length);
                                    ApplyPatchEntry(header, data);
                                }
                            }
                return(hashAlg.Hash);
            }
            catch
            {
                throw new IOException("Failed to apply patch. Patch may be invalid.");
            }
        }