public override Stream OpenEntry(ArcFile arc, Entry entry) { var g2ent = entry as G2Entry; if (null == g2ent) { return(base.OpenEntry(arc, entry)); } int entry_size = (int)g2ent.Size; int offset = 0; var decoders = new G2Scheme[4]; for (int i = 0; i < 4 && offset < entry_size; ++i) { decoders[i] = G2MetaScheme.CreateInstance(g2ent.Keys[i]); if (null != decoders[i]) { offset += EntryChunkSize; } } var output = new byte[entry_size]; var input = new byte[EntryChunkSize]; int current_decoder = 0; offset = 0; while (offset < entry_size) { int current_chunk_size = Math.Min(EntryChunkSize, entry_size - offset); if (null != decoders[current_decoder]) { arc.File.View.Read(g2ent.Offset + offset, input, 0, (uint)current_chunk_size); decoders[current_decoder].Decrypt(input, 0, output, offset, current_chunk_size); } else { arc.File.View.Read(g2ent.Offset + offset, output, offset, (uint)current_chunk_size); } current_decoder = (current_decoder + 1) & 3; offset += current_chunk_size; } return(new MemoryStream(output)); }
public override ArcFile TryOpen(ArcView file) { var header = file.View.ReadBytes(0, 0x5C); if (header.Length != 0x5C) { return(null); } header = HeaderEncryption.Decrypt(header); if (!Binary.AsciiEqual(header, "GLibArchiveData2.") || header[0x12] != 0) { return(null); } int version = header[0x11] - '0'; if (version != 0 && version != 1) { return(null); } uint index_offset = LittleEndian.ToUInt32(header, 0x54); uint index_size = LittleEndian.ToUInt32(header, 0x58); byte[][] encrypted_index = new byte[2][]; encrypted_index[0] = file.View.ReadBytes(index_offset, index_size); if (encrypted_index[0].Length != index_size) { return(null); } encrypted_index[1] = new byte[index_size]; uint[] keys = { LittleEndian.ToUInt32(header, 0x44), LittleEndian.ToUInt32(header, 0x34), LittleEndian.ToUInt32(header, 0x24), LittleEndian.ToUInt32(header, 0x14), }; int i = 0; foreach (var key in keys) { var decoder = G2MetaScheme.CreateInstance(key); decoder.Decrypt(encrypted_index[i], encrypted_index[i ^ 1]); i ^= 1; } byte[] index = encrypted_index[i]; if (!Binary.AsciiEqual(index, "CDBD")) { return(null); } int count = LittleEndian.ToInt32(index, 4); int current_offset = 0x10; int info_base = current_offset + LittleEndian.ToInt32(index, 8); int names_base = current_offset + count * 0x18; var dir = new List <Entry> (count); for (i = 0; i < count; ++i) { int name_offset = names_base + LittleEndian.ToInt32(index, current_offset); int parent_dir = LittleEndian.ToInt32(index, current_offset + 8); int attr = LittleEndian.ToInt32(index, current_offset + 0xC); var name = Binary.GetCString(index, name_offset, info_base - name_offset); if (parent_dir != -1) { name = Path.Combine(dir[parent_dir].Name, name); } var entry = new G2Entry { Name = name }; if (0x100 == attr) { int info_offset = info_base + LittleEndian.ToInt32(index, current_offset + 0x10); entry.Size = LittleEndian.ToUInt32(index, info_offset + 8); entry.Offset = LittleEndian.ToUInt32(index, info_offset + 0xC); entry.Type = FormatCatalog.Instance.GetTypeFromName(name); for (int j = 0; j < 4; ++j) { info_offset += 0x10; entry.Keys[j] = LittleEndian.ToUInt32(index, info_offset); } } dir.Add(entry); current_offset += 0x18; } return(new ArcFile(file, this, dir.Where(e => e.Offset != -1).ToList())); }