Stream OpenLstIndex(ArcView file, string dat_name, HibikiDatScheme scheme) { var lst_name = Path.ChangeExtension(file.Name, ".lst"); if (VFS.FileExists(lst_name)) { return(VFS.OpenStream(lst_name)); } else if ("init.dat" == dat_name) { return(file.CreateStream()); } // try to open 'init.dat' archive in the same directory var init_dat = VFS.CombinePath(VFS.GetDirectoryName(file.Name), "init.dat"); if (!VFS.FileExists(init_dat)) { return(file.CreateStream()); } try { using (var init = VFS.OpenView(init_dat)) using (var init_arc = TryOpenWithScheme(init, ReadCount(init), scheme)) { lst_name = Path.GetFileName(lst_name); var lst_entry = init_arc.Dir.First(e => e.Name == lst_name); return(init_arc.OpenEntry(lst_entry)); } } catch { return(file.CreateStream()); } }
ArcFile TryOpenWithScheme(ArcView file, int count, HibikiDatScheme scheme) { var dat_name = Path.GetFileName(file.Name).ToLowerInvariant(); IList <HibikiTocRecord> toc_table = null; if (scheme.ArcMap != null && scheme.ArcMap.TryGetValue(dat_name, out toc_table)) { if (toc_table.Count != count) { toc_table = null; } } using (var input = OpenLstIndex(file, dat_name, scheme)) using (var dec = new XoredStream(input, 0x80)) using (var index = new BinaryReader(dec)) { const int name_length = 0x100; int data_offset = 2 + (name_length + 10) * count; index.BaseStream.Position = 2; Func <int, Entry> read_entry; if (null == toc_table) { var name_buf = new byte[name_length]; read_entry = i => { if (name_length != index.Read(name_buf, 0, name_length)) { return(null); } var name = Binary.GetCString(name_buf, 0); var entry = FormatCatalog.Instance.Create <Entry> (name); index.ReadUInt16(); entry.Size = index.ReadUInt32(); entry.Offset = index.ReadUInt32(); return(entry); }; } else { read_entry = i => { index.BaseStream.Seek(name_length + 6, SeekOrigin.Current); index.ReadUInt32(); // throws in case of EOF var toc_entry = toc_table[i]; var entry = FormatCatalog.Instance.Create <Entry> (toc_entry.Name); entry.Offset = toc_entry.Offset; entry.Size = toc_entry.Size; return(entry); }; } var dir = new List <Entry> (count); for (int i = 0; i < count; ++i) { var entry = read_entry(i); if (null == entry || string.IsNullOrWhiteSpace(entry.Name) || entry.Offset < data_offset || entry.Size > file.MaxOffset) { return(null); } dir.Add(entry); } return(new HibikiArchive(file, this, dir, scheme.ContentKey)); } }