private static void WriteFileHeader(BinaryWriter writer, EArchive archive, EArchiveFileCreation file, ref long rollingKey) { long fileSizeKey = (rollingKey * MasterFileKey) ^ file.Hash, dataOffsetKey = (fileSizeKey * MasterFileKey) ^ ~(file.Hash); int uncompressedKey = (int)(fileSizeKey >> 32), compressedKey = (int)(fileSizeKey & 0xFFFFFFFF); file.SizeUncompressed ^= uncompressedKey; file.SizeCompressed ^= compressedKey; file.DataOffset ^= dataOffsetKey; rollingKey = dataOffsetKey; writer.Write(file.Hash); writer.Write(file.SizeUncompressed); writer.Write(file.SizeCompressed); writer.Write(file.Flags); writer.Write(file.DataPathOffset); writer.Write(file.DataOffset); writer.Write(file.PathOffset); writer.Write(file.LocalizeType); writer.Write(file.Locale); writer.Write(file.ChunkKey); }
private static void WriteUncompressedFile(BinaryWriter writer, EArchiveFileCreation file) { //* create a stream to read the file contents using (Stream input = File.OpenRead(file.FilePath)) { using (BinaryReader reader = new BinaryReader(input)) { while (reader.BaseStream.Position < reader.BaseStream.Length) { writer.Write(reader.ReadByte()); } } } }
private static void WriteFilePath(BinaryWriter writer, EArchiveFileCreation file) { //* store the path offset file.PathOffset = (uint)writer.BaseStream.Position; //* write the data path writer.Write(Encoding.UTF8.GetBytes(file.Path)); //* zero terminate writer.Write((byte)0x00); //* align for next one Align(writer, 8); }
private static void WriteFileDataPath(BinaryWriter writer, EArchiveFileCreation file) { //* store our data path offset file.DataPathOffset = (uint)writer.BaseStream.Position; //* write the data path if (string.IsNullOrWhiteSpace(file.DataPath)) { writer.Write(Encoding.UTF8.GetBytes("data://" + file.Path)); } else { writer.Write(Encoding.UTF8.GetBytes(file.DataPath)); } //* zero terminate writer.Write((byte)0x00); //* align for next one Align(writer, 8); }
private static void WriteCompressedFile(BinaryWriter writer, EArchive archive, EArchiveFileCreation file) { using (Stream input = File.OpenRead(file.FilePath)) { using (BinaryReader reader = new BinaryReader(input)) { int chunkSize = (int)archive.ChunkSize * 1024; file.SizeUncompressedOriginal = (int)input.Length; file.SizeUncompressed = (int)input.Length; //* get the number of chunks int chunks = (int)input.Length / chunkSize, remaining = (int)input.Length; //* if the integer division wasn't even, add a chunk if (input.Length % chunkSize != 0) { chunks++; } //* set compressed size to zero and sum as we go file.SizeCompressed = 0; if (file.ChunkKey == 0) { file.ChunkKey = (ushort)(new Random().Next(0, ushort.MaxValue)); } for (int chunk = 0; chunk < chunks; chunk++) { //* use a memory stream for chunking using (MemoryStream memory = new MemoryStream()) { int read = (remaining > chunkSize) ? chunkSize : remaining; //* store the chunk of compressed data to a memory stream memory.Write(reader.ReadBytes(read), 0, read); //* move to the start of the chunk memory.Seek(0, SeekOrigin.Begin); //* now compress it and write it to our compressed stream using (MemoryStream compressed = new MemoryStream()) { using (ZLibStream compressor = new ZLibStream(compressed, CompressionMode.Compress, CompressionLevel.Best, true)) memory.CopyTo(compressor); compressed.Seek(0, SeekOrigin.Begin); int sizeCompressed = (int)compressed.Length, sizeUncompressed = read; //* write chunk sizes if (chunk == 0) { //* for the first one we need to encrypt it long chunkKey = (MasterChunkKeyA * file.ChunkKey) + MasterChunkKeyB; int compressedKey = (int)(chunkKey >> 32); int uncompressedKey = (int)(chunkKey & 0xFFFFFFFF); sizeCompressed ^= compressedKey; sizeUncompressed ^= uncompressedKey; } writer.Write(sizeCompressed); writer.Write(sizeUncompressed); for (int position = 0; position < compressed.Length; position++) { writer.Write((byte)compressed.ReadByte()); } //* align for next chunk int alignment = Align(writer, 4); file.SizeCompressed += (int)compressed.Length + 8 + alignment; } remaining -= read; } } } } }
private static void CopyFileFromArchive(BinaryWriter writer, EArchive archive, EArchiveFileCreation file) { if (file.FilePath == file.Path) { EArchive existing = Open(file.ArchivePath); EArchiveFile old = null; foreach (EArchiveFile previous in existing.Files) { if (previous.Path == file.Path) { old = previous; break; } } if (old == null) { throw new FileNotFoundException(); } using (Stream input = File.OpenRead(file.ArchivePath)) { input.Seek(old.DataOffset, SeekOrigin.Begin); using (BinaryReader reader = new BinaryReader(input)) { for (int index = 0; index < old.SizeCompressed; index++) { writer.Write(reader.ReadByte()); } } } file.SizeCompressed = old.SizeCompressed; file.SizeUncompressed = old.SizeUncompressed; file.SizeUncompressedOriginal = old.SizeUncompressed; return; } }
private static void WriteEncryptedFile(BinaryWriter writer, EArchive archive, EArchiveFileCreation file) { Aes aes = Aes.Create(); aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.Zeros; if (file.IV == null) { aes.GenerateIV(); file.IV = aes.IV; } ICryptoTransform transform = aes.CreateEncryptor(AESKey, file.IV); using (Stream input = File.OpenRead(file.FilePath)) { using (BinaryReader inputReader = new BinaryReader(input)) { using (MemoryStream msEncrypted = new MemoryStream()) { using (CryptoStream csEncrypted = new CryptoStream(msEncrypted, transform, CryptoStreamMode.Write)) { using (BinaryWriter bwEncrypted = new BinaryWriter(csEncrypted, Encoding.Default, true)) { while (input.Position < input.Length) { bwEncrypted.Write(inputReader.ReadByte()); } } if (!csEncrypted.HasFlushedFinalBlock) { csEncrypted.FlushFinalBlock(); } msEncrypted.Seek(0, SeekOrigin.Begin); while (msEncrypted.Position < msEncrypted.Length) { writer.Write((byte)msEncrypted.ReadByte()); } } } } } int alignment = 16 - (file.SizeUncompressedOriginal % 16); if (alignment == 16) { alignment = 0; } writer.Write(file.IV); file.SizeCompressed = file.SizeUncompressedOriginal + alignment + 33; }