public override ArcFile TryOpen(ArcView file) { if (!file.View.AsciiEqual(4, "PACK")) { return(null); } uint init_key = file.View.ReadUInt32(0xC); var xdec = new NekoXCode(init_key); uint seed = file.View.ReadUInt32(0x10); var buffer = file.View.ReadBytes(0x14, 8); xdec.Decrypt(seed, buffer, 0, 8); uint index_size = LittleEndian.ToUInt32(buffer, 0); if (index_size < 0x14 || index_size != LittleEndian.ToUInt32(buffer, 4)) { return(null); } var index = new byte[(index_size + 7u) & ~7u]; if (file.View.Read(0x1C, index, 0, index_size) < index_size) { return(null); } xdec.Decrypt(seed, index, 0, index.Length); using (var reader = new IndexReader(file, xdec, index, (int)index_size)) { var dir = reader.Parse(0x1C + index.Length); if (null == dir) { return(null); } reader.DetectTypes(dir, entry => { uint key = file.View.ReadUInt32(entry.Offset); file.View.Read(entry.Offset + 12, buffer, 0, 8); xdec.Decrypt(key, buffer, 0, 8); return(LittleEndian.ToUInt32(buffer, 0)); }); return(new NekoArchive(file, this, dir, xdec)); } }
void DetectTypes(ArcView file, List <Entry> dir, NekoXCode dec) { byte[] buffer = new byte[8]; foreach (var entry in dir.Where(e => string.IsNullOrEmpty(e.Type))) { if (entry.Name.EndsWith(".txt", StringComparison.InvariantCultureIgnoreCase)) { entry.Type = "script"; continue; } uint key = file.View.ReadUInt32(entry.Offset); file.View.Read(entry.Offset + 12, buffer, 0, 8); dec.Decrypt(key, buffer, 0, 8); uint signature = LittleEndian.ToUInt32(buffer, 0); var res = AutoEntry.DetectFileType(signature); string ext = ""; if (res != null) { ext = res.Extensions.FirstOrDefault(); entry.Type = res.Type; } else if (0x474e4d8a == signature) { ext = "mng"; } else if (entry.Name.StartsWith("script/")) { entry.Type = "script"; } if (!string.IsNullOrEmpty(ext)) { entry.Name = Path.ChangeExtension(entry.Name, ext); } } }
void DetectTypes(ArcView file, List<Entry> dir, NekoXCode dec) { byte[] buffer = new byte[8]; foreach (var entry in dir.Where (e => string.IsNullOrEmpty (e.Type))) { if (entry.Name.EndsWith (".txt", StringComparison.InvariantCultureIgnoreCase)) { entry.Type = "script"; continue; } uint key = file.View.ReadUInt32 (entry.Offset); file.View.Read (entry.Offset+12, buffer, 0, 8); dec.Decrypt (key, buffer, 0, 8); uint signature = LittleEndian.ToUInt32 (buffer, 0); var res = AutoEntry.DetectFileType (signature); string ext = ""; if (res != null) { ext = res.Extensions.FirstOrDefault(); entry.Type = res.Type; } else if (0x474e4d8a == signature) ext = "mng"; else if (entry.Name.StartsWith ("script/")) entry.Type = "script"; if (!string.IsNullOrEmpty (ext)) entry.Name = Path.ChangeExtension (entry.Name, ext); } }
public override ArcFile TryOpen(ArcView file) { if (!file.View.AsciiEqual(4, "PACK")) { return(null); } uint init_key = file.View.ReadUInt32(0xC); var xdec = new NekoXCode(init_key); uint key = file.View.ReadUInt32(0x10); var buffer = file.View.ReadBytes(0x14, 8); xdec.Decrypt(key, buffer, 0, 8); uint index_size = LittleEndian.ToUInt32(buffer, 0); if (index_size != LittleEndian.ToUInt32(buffer, 4)) { return(null); } var index = new byte[(index_size + 7u) & ~7u]; if (file.View.Read(0x1C, index, 0, index_size) < index_size) { return(null); } xdec.Decrypt(key, index, 0, index.Length); var names_map = GetNamesMap(init_key, KnownDirNames); var files_map = GetNamesMap(init_key, KnownFileNames.Value); int index_pos = 0; var dir = new List <Entry>(); long current_offset = 0x1C + index.Length; while (index_pos < (int)index_size) { uint dir_hash = LittleEndian.ToUInt32(index, index_pos); int count = LittleEndian.ToInt32(index, index_pos + 4); if (count != LittleEndian.ToInt32(index, index_pos + 8)) { break; } index_pos += 12; string dir_name; if (!names_map.TryGetValue(dir_hash, out dir_name)) { dir_name = dir_hash.ToString("X8"); } dir.Capacity = dir.Count + count; for (int i = 0; i < count; ++i) { uint name_hash = LittleEndian.ToUInt32(index, index_pos); uint size = LittleEndian.ToUInt32(index, index_pos + 4); string file_name; string type = ""; if (!files_map.TryGetValue(name_hash, out file_name)) { file_name = name_hash.ToString("X8"); } else { type = FormatCatalog.Instance.GetTypeFromName(file_name); } var entry = new Entry { Name = string.Format("{0}/{1}", dir_name, file_name), Type = type, Offset = current_offset, Size = size, }; if (!entry.CheckPlacement(file.MaxOffset)) { return(null); } dir.Add(entry); index_pos += 8; current_offset += entry.Size; } } if (0 == dir.Count) { return(null); } DetectTypes(file, dir, xdec); return(new NekoArchive(file, this, dir, xdec)); }
public override ArcFile TryOpen(ArcView file) { if (!file.View.AsciiEqual (4, "PACK")) return null; uint init_key = file.View.ReadUInt32 (0xC); var xdec = new NekoXCode (init_key); uint key = file.View.ReadUInt32 (0x10); var buffer = file.View.ReadBytes (0x14, 8); xdec.Decrypt (key, buffer, 0, 8); uint index_size = LittleEndian.ToUInt32 (buffer, 0); if (index_size != LittleEndian.ToUInt32 (buffer, 4)) return null; var index = new byte[(index_size + 7u) & ~7u]; if (file.View.Read (0x1C, index, 0, index_size) < index_size) return null; xdec.Decrypt (key, index, 0, index.Length); var names_map = GetNamesMap (init_key, KnownDirNames); var files_map = GetNamesMap (init_key, KnownFileNames.Value); int index_pos = 0; var dir = new List<Entry>(); long current_offset = 0x1C + index.Length; while (index_pos < (int)index_size) { uint dir_hash = LittleEndian.ToUInt32 (index, index_pos); int count = LittleEndian.ToInt32 (index, index_pos+4); if (count != LittleEndian.ToInt32 (index, index_pos+8)) break; index_pos += 12; string dir_name; if (!names_map.TryGetValue (dir_hash, out dir_name)) dir_name = dir_hash.ToString ("X8"); dir.Capacity = dir.Count + count; for (int i = 0; i < count; ++i) { uint name_hash = LittleEndian.ToUInt32 (index, index_pos); uint size = LittleEndian.ToUInt32 (index, index_pos+4); string file_name; string type = ""; if (!files_map.TryGetValue(name_hash, out file_name)) file_name = name_hash.ToString("X8"); else type = FormatCatalog.Instance.GetTypeFromName (file_name); var entry = new Entry { Name = string.Format ("{0}/{1}", dir_name, file_name), Type = type, Offset = current_offset, Size = size, }; if (!entry.CheckPlacement (file.MaxOffset)) return null; dir.Add (entry); index_pos += 8; current_offset += entry.Size; } } if (0 == dir.Count) return null; DetectTypes (file, dir, xdec); return new NekoArchive (file, this, dir, xdec); }