private void DecryptEntry(byte[] data, uint key1, uint key2, DpkEntry entry) { for (uint i = 0; i < data.Length; ++i) { data[i] ^= (byte)(key1 + (key1 >> 8)); data[i] -= (byte)entry.Hash; key1 += key2; } }
public override ArcFile TryOpen(ArcView file) { var header = new byte[8]; if (8 != file.View.Read(8, header, 0, 8)) { return(null); } byte last = header[7]; for (int i = 0; i < 8; i++) { header[i] ^= (byte)(i - 8); } int data_offset = LittleEndian.ToInt32(header, 0); if (data_offset <= 16 || data_offset >= file.MaxOffset) { return(null); } int index_length = data_offset - 16; var index = new byte[index_length]; if (index_length != file.View.Read(16, index, 0, (uint)index_length)) { return(null); } DecryptIndex(index, 16, index_length, last); int count = LittleEndian.ToInt32(index, 0); if (count <= 0 || count > 0xfffff) { return(null); } var options = Query <DpkOptions> (arcStrings.ArcEncryptedNotice); var name_bytes = new byte[0x20]; var dir = new List <Entry> (count); int base_offset = 4 + count * 4; for (int i = 0; i < count; ++i) { var index_offset = base_offset + LittleEndian.ToInt32(index, 4 + i * 4); int name_begin = index_offset + 0x0c; int name_end = Array.IndexOf(index, (byte)0, name_begin); if (-1 == name_end) { name_end = index.Length; } if (name_end == name_begin) { continue; } if ('z' == index[name_end - 1]) { --name_end; // strip 'z' from file extensions } int name_length = name_end - name_begin; var name = Encodings.cp932.GetString(index, name_begin, name_length); if (name_length > name_bytes.Length) { name_bytes = new byte[name_length]; } // shift-jis characters sequence may contain '\\' that is not a path delimiter string name_base = Path.GetFileName(name); name_length = Encodings.cp932.GetBytes(name_base, 0, name_base.Length, name_bytes, 0); uint size = LittleEndian.ToUInt32(index, index_offset + 4); var entry = new DpkEntry { Name = name, Type = FormatCatalog.Instance.GetTypeFromName(name), Hash = GetNameHash(name_bytes, 0, name_length, options.Key1, options.Key2, size), Offset = data_offset + LittleEndian.ToUInt32(index, index_offset), Size = size, }; if (!entry.CheckPlacement(file.MaxOffset)) { return(null); } dir.Add(entry); } if (0 == dir.Count) { return(null); } return(new DpkArchive(file, this, dir, options)); }