public override byte Decrypt(Xp3Entry entry, long offset, byte value) { return((byte)(value ^ entry.Hash)); }
public override void Encrypt(Xp3Entry entry, long offset, byte[] values, int pos, int count) { Decrypt(entry, offset, values, pos, count); }
public override byte Decrypt(Xp3Entry entry, long offset, byte value) { return(value); }
public override void Encrypt(Xp3Entry entry, long offset, byte[] values, int pos, int count) { return; }
public override byte Decrypt(Xp3Entry entry, long offset, byte value) { return((byte)(value ^ (entry.Hash >> (int)((uint)offset % 5)))); }
public override byte Decrypt(Xp3Entry entry, long offset, byte value) { byte key = (byte)entry.Hash; return(key != 0 && offset % key != 0 ? (byte)(value ^ key) : value); }
public override byte Decrypt(Xp3Entry entry, long offset, byte value) { return(offset < 5 ? value : (byte)(value ^ (entry.Hash >> 12))); }
public override byte Decrypt(Xp3Entry entry, long offset, byte value) { return((byte)((value ^ m_key) + 1)); }
public override byte Decrypt(Xp3Entry entry, long offset, byte value) { return((byte)(value ^ KeyTable[offset & 0xFF])); }
public virtual void Encrypt(Xp3Entry entry, long offset, byte[] values, int pos, int count) { throw new NotImplementedException(Strings.arcStrings.MsgEncNotImplemented); }
public abstract void Decrypt(Xp3Entry entry, long offset, byte[] values, int pos, int count);
public override void Encrypt(Xp3Entry entry, long offset, byte[] buffer, int pos, int count) { base.Encrypt(entry, offset, buffer, pos, count); ProcessFirstBytes(entry, offset, buffer, pos, count); }
void EncryptedFileCopy(FileStream file, Xp3Entry xp3entry, Stream output, bool compress) { if (file.Length > int.MaxValue) { throw new FileSizeException(); } using (var map = MemoryMappedFile.CreateFromFile(file, null, 0, MemoryMappedFileAccess.Read, null, HandleInheritability.None, true)) { uint unpacked_size = (uint)file.Length; xp3entry.UnpackedSize = (uint)unpacked_size; xp3entry.Size = (uint)unpacked_size; using (var view = map.CreateViewAccessor(0, unpacked_size, MemoryMappedFileAccess.Read)) { var segment = new Xp3Segment { IsCompressed = compress, Offset = output.Position, Size = unpacked_size, PackedSize = unpacked_size, }; if (compress) { output = new ZLibStream(output, CompressionMode.Compress, CompressionLevel.Level9, true); } unsafe { byte[] read_buffer = new byte[81920]; byte * ptr = view.GetPointer(0); try { var checksum = new Adler32(); bool hash_after_crypt = xp3entry.Cipher.HashAfterCrypt; if (!hash_after_crypt) { xp3entry.Hash = checksum.Update(ptr, (int)unpacked_size); } int offset = 0; int remaining = (int)unpacked_size; while (remaining > 0) { int amount = Math.Min(remaining, read_buffer.Length); remaining -= amount; Marshal.Copy((IntPtr)(ptr + offset), read_buffer, 0, amount); xp3entry.Cipher.Encrypt(xp3entry, offset, read_buffer, 0, amount); if (hash_after_crypt) { checksum.Update(read_buffer, 0, amount); } output.Write(read_buffer, 0, amount); offset += amount; } if (hash_after_crypt) { xp3entry.Hash = checksum.Value; } } finally { view.SafeMemoryMappedViewHandle.ReleasePointer(); if (compress) { var dest = (output as ZLibStream).BaseStream; output.Dispose(); segment.PackedSize = (uint)(dest.Position - segment.Offset); xp3entry.Size = segment.PackedSize; } xp3entry.Segments.Add(segment); } } } } }
public override void Create(Stream output, IEnumerable <Entry> list, ResourceOptions options, EntryCallback callback) { var xp3_options = GetOptions <Xp3Options> (options); ICrypt scheme = xp3_options.Scheme; bool compress_index = xp3_options.CompressIndex; bool compress_contents = xp3_options.CompressContents; bool retain_dirs = xp3_options.RetainDirs; bool use_encryption = !(scheme is NoCrypt); using (var writer = new BinaryWriter(output, Encoding.ASCII, true)) { writer.Write(s_xp3_header); if (2 == xp3_options.Version) { writer.Write((long)0x17); writer.Write((int)1); writer.Write((byte)0x80); writer.Write((long)0); } long index_pos_offset = writer.BaseStream.Position; writer.BaseStream.Seek(8, SeekOrigin.Current); int callback_count = 0; var used_names = new HashSet <string>(); var dir = new List <Xp3Entry>(); long current_offset = writer.BaseStream.Position; foreach (var entry in list) { if (null != callback) { callback(callback_count++, entry, arcStrings.MsgAddingFile); } string name = entry.Name; if (!retain_dirs) { name = Path.GetFileName(name); } else { name = name.Replace(@"\", "/"); } if (!used_names.Add(name)) { Trace.WriteLine("duplicate name", entry.Name); continue; } var xp3entry = new Xp3Entry { Name = name, Cipher = scheme, IsEncrypted = use_encryption && !(scheme.StartupTjsNotEncrypted && VFS.IsPathEqualsToFileName(name, "startup.tjs")) }; bool compress = compress_contents && ShouldCompressFile(entry); using (var file = File.Open(name, FileMode.Open, FileAccess.Read)) { if (!xp3entry.IsEncrypted || 0 == file.Length) { RawFileCopy(file, xp3entry, output, compress); } else { EncryptedFileCopy(file, xp3entry, output, compress); } } dir.Add(xp3entry); } long index_pos = writer.BaseStream.Position; writer.BaseStream.Position = index_pos_offset; writer.Write(index_pos); writer.BaseStream.Position = index_pos; using (var header = new BinaryWriter(new MemoryStream(dir.Count * 0x58), Encoding.Unicode)) { if (null != callback) { callback(callback_count++, null, arcStrings.MsgWritingIndex); } long dir_pos = 0; foreach (var entry in dir) { header.BaseStream.Position = dir_pos; header.Write((uint)0x656c6946); // "File" long header_size_pos = header.BaseStream.Position; header.Write((long)0); header.Write((uint)0x6f666e69); // "info" header.Write((long)(4 + 8 + 8 + 2 + entry.Name.Length * 2)); header.Write((uint)(use_encryption ? 0x80000000 : 0)); header.Write((long)entry.UnpackedSize); header.Write((long)entry.Size); header.Write((short)entry.Name.Length); foreach (char c in entry.Name) { header.Write(c); } header.Write((uint)0x6d676573); // "segm" header.Write((long)0x1c); var segment = entry.Segments.First(); header.Write((int)(segment.IsCompressed ? 1 : 0)); header.Write((long)segment.Offset); header.Write((long)segment.Size); header.Write((long)segment.PackedSize); header.Write((uint)0x726c6461); // "adlr" header.Write((long)4); header.Write((uint)entry.Hash); dir_pos = header.BaseStream.Position; long header_size = dir_pos - header_size_pos - 8; header.BaseStream.Position = header_size_pos; header.Write(header_size); } header.BaseStream.Position = 0; writer.Write(compress_index); long unpacked_dir_size = header.BaseStream.Length; if (compress_index) { if (null != callback) { callback(callback_count++, null, arcStrings.MsgCompressingIndex); } long packed_dir_size_pos = writer.BaseStream.Position; writer.Write((long)0); writer.Write(unpacked_dir_size); long dir_start = writer.BaseStream.Position; using (var zstream = new ZLibStream(writer.BaseStream, CompressionMode.Compress, CompressionLevel.Level9, true)) header.BaseStream.CopyTo(zstream); long packed_dir_size = writer.BaseStream.Position - dir_start; writer.BaseStream.Position = packed_dir_size_pos; writer.Write(packed_dir_size); } else { writer.Write(unpacked_dir_size); header.BaseStream.CopyTo(writer.BaseStream); } } } output.Seek(0, SeekOrigin.End); }
public override ArcFile TryOpen(ArcView file) { long base_offset = 0; if (0x5a4d == file.View.ReadUInt16(0)) // 'MZ' { base_offset = SkipExeHeader(file); } if (!file.View.AsciiEqual(base_offset, SignatureBytes)) { return(null); } long dir_offset = base_offset + file.View.ReadInt64(base_offset + 0x0b); if (dir_offset < 0x13 || dir_offset >= file.MaxOffset) { return(null); } if (0x80 == file.View.ReadUInt32(dir_offset)) { dir_offset = base_offset + file.View.ReadInt64(dir_offset + 9); if (dir_offset < 0x13 || dir_offset >= file.MaxOffset) { return(null); } } int header_type = file.View.ReadByte(dir_offset); if (0 != header_type && 1 != header_type) { return(null); } Stream header_stream; if (0 == header_type) // read unpacked header { long header_size = file.View.ReadInt64(dir_offset + 1); if (header_size > uint.MaxValue) { return(null); } header_stream = file.CreateStream(dir_offset + 9, (uint)header_size); } else // read packed header { long packed_size = file.View.ReadInt64(dir_offset + 1); if (packed_size > uint.MaxValue) { return(null); } long header_size = file.View.ReadInt64(dir_offset + 9); using (var input = file.CreateStream(dir_offset + 17, (uint)packed_size)) header_stream = ZLibCompressor.DeCompress(input); } var crypt_algorithm = new Lazy <ICrypt> (() => QueryCryptAlgorithm(file), false); var dir = new List <Entry>(); dir_offset = 0; using (var header = new BinaryReader(header_stream, Encoding.Unicode)) using (var filename_map = new FilenameMap()) { while (-1 != header.PeekChar()) { uint entry_signature = header.ReadUInt32(); long entry_size = header.ReadInt64(); if (entry_size < 0) { return(null); } dir_offset += 12 + entry_size; if (0x656C6946 == entry_signature) // "File" { var entry = new Xp3Entry(); while (entry_size > 0) { uint section = header.ReadUInt32(); long section_size = header.ReadInt64(); entry_size -= 12; if (section_size > entry_size) { break; } entry_size -= section_size; long next_section_pos = header.BaseStream.Position + section_size; switch (section) { case 0x6f666e69: // "info" if (entry.Size != 0 || !string.IsNullOrEmpty(entry.Name)) { goto NextEntry; // ambiguous entry, ignore } entry.IsEncrypted = 0 != header.ReadUInt32(); long file_size = header.ReadInt64(); long packed_size = header.ReadInt64(); if (file_size >= uint.MaxValue || packed_size > uint.MaxValue || packed_size > file.MaxOffset) { goto NextEntry; } entry.IsPacked = file_size != packed_size; entry.Size = (uint)packed_size; entry.UnpackedSize = (uint)file_size; if (entry.IsEncrypted || ForceEncryptionQuery) { entry.Cipher = crypt_algorithm.Value; } else { entry.Cipher = NoCryptAlgorithm; } var name = entry.Cipher.ReadName(header); if (null == name) { goto NextEntry; } if (entry.Cipher.ObfuscatedIndex && ObfuscatedPathRe.IsMatch(name)) { goto NextEntry; } if (filename_map.Count > 0) { name = filename_map.Get(entry.Hash, name); } if (name.Length > 0x100) { goto NextEntry; } entry.Name = name; entry.Type = FormatCatalog.Instance.GetTypeFromName(name); entry.IsEncrypted = !(entry.Cipher is NoCrypt) && !(entry.Cipher.StartupTjsNotEncrypted && "startup.tjs" == name); break; case 0x6d676573: // "segm" int segment_count = (int)(section_size / 0x1c); if (segment_count > 0) { for (int i = 0; i < segment_count; ++i) { bool compressed = 0 != header.ReadInt32(); long segment_offset = base_offset + header.ReadInt64(); long segment_size = header.ReadInt64(); long segment_packed_size = header.ReadInt64(); if (segment_offset > file.MaxOffset || segment_packed_size > file.MaxOffset) { goto NextEntry; } var segment = new Xp3Segment { IsCompressed = compressed, Offset = segment_offset, Size = (uint)segment_size, PackedSize = (uint)segment_packed_size }; entry.Segments.Add(segment); } entry.Offset = entry.Segments.First().Offset; } break; case 0x726c6461: // "adlr" if (4 == section_size) { entry.Hash = header.ReadUInt32(); } break; default: // unknown section break; } header.BaseStream.Position = next_section_pos; } if (!string.IsNullOrEmpty(entry.Name) && entry.Segments.Any()) { if (entry.Cipher.ObfuscatedIndex) { DeobfuscateEntry(entry); } dir.Add(entry); } } else if (entry_size > 7) { // 0x6E666E68 == entry_signature // "hnfn" // 0x6C696D73 == entry_signature // "smil" // 0x46696C65 == entry_signature // "eliF" // 0x757A7559 == entry_signature // "Yuzu" uint hash = header.ReadUInt32(); int name_size = header.ReadInt16(); if (name_size > 0) { entry_size -= 6; if (name_size * 2 <= entry_size) { var filename = new string (header.ReadChars(name_size)); filename_map.Add(hash, filename); } } } NextEntry: header.BaseStream.Position = dir_offset; } } if (0 == dir.Count) { return(null); } var arc = new ArcFile(file, this, dir); try { if (crypt_algorithm.IsValueCreated) { crypt_algorithm.Value.Init(arc); } return(arc); } catch { arc.Dispose(); throw; } }