public override ArcFile TryOpen(ArcView file) { if (!VFS.IsPathEqualsToFileName(file.Name, "0000.bin")) { return(null); } if ((file.MaxOffset % BitmapSize) != 0) { return(null); } int count = (int)(file.MaxOffset / BitmapSize); if (!IsSaneCount(count)) { return(null); } uint offset = 0; var dir = new List <Entry> (count); for (int i = 0; i < count; ++i) { var entry = new Entry { Name = string.Format("{0:D4}.bmp", i), Type = "image", Offset = offset, Size = BitmapSize, }; dir.Add(entry); offset += BitmapSize; } return(new ArcFile(file, this, dir)); }
public override IImageDecoder OpenImage(ArcFile arc, Entry entry) { OrgMetaData info; if (VFS.IsPathEqualsToFileName(arc.File.Name, "MASK.DAT")) { info = new OrgMetaData { Width = arc.File.View.ReadUInt32(entry.Offset), Height = arc.File.View.ReadUInt32(entry.Offset + 4), BPP = 8, IsMask = true, }; } else { byte has_alpha = arc.File.View.ReadByte(entry.Offset); byte type = arc.File.View.ReadByte(entry.Offset + 1); if (has_alpha > 1 || type < 1 || type > 3) { return(base.OpenImage(arc, entry)); } info = new OrgMetaData { Width = arc.File.View.ReadUInt16(entry.Offset + 2), Height = arc.File.View.ReadUInt16(entry.Offset + 4), HasAlpha = has_alpha != 0, Method = type, BPP = 32, }; } var input = arc.File.CreateStream(entry.Offset, entry.Size); return(new OrgImageDecoder(input, info)); }
uint GetContentKey(ArcView file, List <Entry> dir, EncryptionScheme scheme) { if (null != scheme.ContentKey) { return(scheme.ContentKey.Value); } if (VFS.IsPathEqualsToFileName(file.Name, "system.arc")) { return(ReadSysenvSeed(file, dir, scheme.IndexKey)); } else { var system_arc = VFS.CombinePath(VFS.GetDirectoryName(file.Name), "system.arc"); using (var arc = VFS.OpenView(system_arc)) { var header = arc.View.ReadBytes(0, 0x30); Decrypt(header, 0, scheme.IndexKey); using (var arc_file = ReadIndex(arc, header, scheme)) { return(ReadSysenvSeed(arc, arc_file.Dir, scheme.IndexKey)); } } } }
public override ArcFile TryOpen(ArcView file) { uint key = 0x8B6A4E5F; int count = file.View.ReadInt32(4) ^ (int)key; if (!IsSaneCount(count)) { return(null); } var scheme = QueryScheme(file.Name); if (null == scheme) { return(null); } bool is_script = VFS.IsPathEqualsToFileName(file.Name, "script.dat"); using (var index = new NcIndexReader(file, count, key) { IndexPosition = 8 }) { var file_map = ReadFilenameMap(scheme); var dir = index.Read(file_map); if (null == dir) { return(null); } return(new ArcDatArchive(file, this, dir, scheme.Hash)); } }
public override ArcFile TryOpen(ArcView file) { if (!file.Name.HasExtension(".dat")) { return(null); } var cpn_name = Path.ChangeExtension(file.Name, ".cpn"); if (!VFS.FileExists(cpn_name)) { return(null); } byte key; string cpn_index; using (var cpn = VFS.OpenView(cpn_name)) { key = cpn.View.ReadByte(0); var cpn_data = cpn.View.ReadBytes(1, (uint)(cpn.MaxOffset - 1)); for (int i = 0; i < cpn_data.Length; ++i) { cpn_data[i] ^= key; } cpn_index = Encodings.cp932.GetString(cpn_data); } int idx = cpn_index.IndexOf('#', 1); if (idx <= 1) { return(null); } var data_name = cpn_index.Substring(1, idx - 1); if (!VFS.IsPathEqualsToFileName(file.Name, data_name)) { return(null); } var dir = new List <Entry>(); var match = CpnEntryRe.Match(cpn_index, idx); while (match.Success) { var name = match.Groups["name"].Value; var entry = FormatCatalog.Instance.Create <Entry> (name); entry.Offset = UInt32.Parse(match.Groups["offset"].Value); entry.Size = UInt32.Parse(match.Groups["size"].Value); if (!entry.CheckPlacement(file.MaxOffset)) { return(null); } dir.Add(entry); match = match.NextMatch(); } if (0 == dir.Count) { return(null); } return(new CpnArchive(file, this, dir, key)); }
public override ArcFile TryOpen(ArcView file) { if (!VFS.IsPathEqualsToFileName(file.Name, "gaf")) { return(null); } int count = file.View.ReadInt32(8); if (!IsSaneCount(count)) { return(null); } uint width = file.View.ReadUInt32(0); uint height = file.View.ReadUInt32(4); if (width == 0 || width > 0x4000 || height == 0 || height > 0x4000) { return(null); } uint offset = 0xC; var base_name = Path.GetFileNameWithoutExtension(file.Name); var dir = new List <Entry> (count); uint image_size = width * height; for (int i = 0; i < count; ++i) { var entry = new Entry { Name = string.Format("{0}#{1:D4}", base_name, i), Type = "image", Offset = offset, }; if (i + 1 < count) { uint unpacked = 0; while (unpacked < image_size && offset < file.MaxOffset) { unpacked += file.View.ReadByte(offset + 1); offset += 2; } } else { offset = (uint)file.MaxOffset; } entry.Size = (uint)(offset - entry.Offset); dir.Add(entry); } var info = new ImageMetaData { Width = width, Height = height, BPP = 8 }; return(new GafArchive(file, this, dir, info)); }
string XmlFindArchiveKey(XmlDocument xml, string filename) { foreach (XmlNode archive in xml.DocumentElement.SelectNodes("archive[@path and @key]")) { var attr = archive.Attributes; var path = attr["path"].Value; if (VFS.IsPathEqualsToFileName(path, filename)) { return(attr["key"].Value); } } return(null); }
public override ArcFile TryOpen(ArcView file) { int count = file.View.ReadInt32(0); if (!IsSaneCount(count) || 8 + count * MinEntryLength >= file.MaxOffset) { return(null); } uint is_compressed = file.View.ReadUInt32(4); if (is_compressed > 1) // should be either 0 or 1 { return(null); } var index_reader = new ArcIndexReader(file, count, is_compressed != 0); var scheme = index_reader.GuessScheme(8, new int[] { 0x20, 0x18 }); // additional checks to avoid dialog popup on false positives if (null == scheme && KnownSchemes.Count > 0 && file.Name.HasExtension(".arc")) { var first_entry = file.View.ReadBytes(8, 0x20); if (-1 == Array.FindIndex(first_entry, x => x != 0)) { return(null); } scheme = QueryScheme(); } if (null == scheme) { return(null); } // special case for "instdata.arc" archives if (scheme.Keyword != "inst" && VFS.IsPathEqualsToFileName(file.Name, "instdata.arc")) { scheme = new EncryptionScheme("inst", scheme.NameLength); } var dir = index_reader.ReadIndex(8, scheme); if (null == dir) { return(null); } return(new ArcFile(file, this, dir)); }
public override ArcFile TryOpen(ArcView file) { if (!VFS.IsPathEqualsToFileName(file.Name, "SCNPAC.DAT")) { return(null); } int count = file.View.ReadInt32(0); if (!IsSaneCount(count)) { return(null); } uint index_size = 4 * (uint)count; if (index_size > file.View.Reserve(4, index_size)) { return(null); } int index_offset = 4; uint next_offset = file.View.ReadUInt32(index_offset); if (next_offset < index_offset + index_size) { return(null); } var dir = new List <Entry> (count); for (int i = 0; i < count; ++i) { index_offset += 4; var entry = new Entry { Name = i.ToString("D5"), Type = "script" }; entry.Offset = next_offset; next_offset = file.View.ReadUInt32(index_offset); if (next_offset < entry.Offset || next_offset > file.MaxOffset) { return(null); } entry.Size = next_offset - (uint)entry.Offset; dir.Add(entry); } return(new ArcFile(file, this, dir)); }
public override ArcFile TryOpen(ArcView file) { if (!file.Name.HasExtension(".pb")) { return(null); } int count = file.View.ReadInt32(0); if (count <= 0 || count > 0xfff) { return(null); } var dir = new List <Entry> (count); int index_offset = 0x10; bool is_voice = VFS.IsPathEqualsToFileName(file.Name, "voice.pb"); int data_offset = index_offset + 8 * count; for (int i = 0; i < count; ++i) { uint offset = file.View.ReadUInt32(index_offset); Entry entry; if (!is_voice) { entry = new Entry { Name = i.ToString("D4"), Type = "audio", Offset = offset } } ; else { entry = new Entry { Name = string.Format("{0:D4}.pb", i), Type = "archive", Offset = offset } }; entry.Size = file.View.ReadUInt32(index_offset + 4); if (offset < data_offset || !entry.CheckPlacement(file.MaxOffset)) { return(null); } dir.Add(entry); index_offset += 8; } return(new ArcFile(file, this, dir)); } }
static public RioReader Create(ArcView file) { if (CRioArchive.RioSignature == file.View.ReadUInt32(0)) { return(new RioReader(file)); } if (file.Name.HasExtension(".ici")) { return(null); } var ici_name = file.Name + ".ici"; if (!VFS.FileExists(ici_name)) { ici_name = Path.ChangeExtension(file.Name, ".ici"); if (!VFS.FileExists(ici_name)) { return(null); } } byte[] ici_data; using (var ici = VFS.OpenBinaryStream(ici_name)) ici_data = ReadIci(ici, IciKey); CObjectArcMan arc_man; using (var ici = new BinMemoryStream(ici_data)) { var rio = new CRioArchive(ici); arc_man = rio.DeserializeRoot() as CObjectArcMan; if (null == arc_man) { return(null); } } var arc_object = arc_man.ArcList.FirstOrDefault(); if (null == arc_object || !VFS.IsPathEqualsToFileName(file.Name, arc_object.RioName)) { return(null); } return(new RioReader(arc_man, file)); }
public override ArcFile TryOpen(ArcView file) { // enforce extension to avoid false positives if (!file.Name.HasExtension(".awf")) { return(null); } int count = file.View.ReadInt32(0); if (!IsSaneCount(count)) { return(null); } uint index_offset = 4; uint index_size = (uint)count * 0x34; if (index_size > file.View.Reserve(index_offset, index_size)) { return(null); } // rather loose criterion, haven't found anything better yet. bool is_mp3 = VFS.IsPathEqualsToFileName(file.Name, "voice.awf"); var dir = new List <Entry> (count); for (int i = 0; i < count; ++i) { var name = file.View.ReadString(index_offset, 0x20); if (is_mp3) { name = Path.ChangeExtension(name, "mp3"); } var entry = FormatCatalog.Instance.Create <Entry> (name); entry.Offset = file.View.ReadUInt32(index_offset + 0x20); entry.Size = file.View.ReadUInt32(index_offset + 0x24); if (!entry.CheckPlacement(file.MaxOffset)) { return(null); } dir.Add(entry); index_offset += 0x34; } return(new ArcFile(file, this, dir)); }
public override ArcFile TryOpen(ArcView file) { if (!file.View.AsciiEqual(0, "BinaryCombineData")) { return(null); } var bcl_name = Path.ChangeExtension(file.Name, "bcl"); using (var bcl = VFS.OpenStream(bcl_name)) using (var index = new StreamReader(bcl, Encodings.cp932)) { if (index.ReadLine() != "[BinaryCombineData]") { return(null); } var filename = index.ReadLine(); if (!VFS.IsPathEqualsToFileName(file.Name, filename)) { return(null); } index.ReadLine(); var dir = new List <Entry>(); while ((filename = index.ReadLine()) != null) { if (!filename.StartsWith("[") || !filename.EndsWith("]")) { return(null); } filename = filename.Substring(1, filename.Length - 2); var offset = index.ReadLine(); var size = index.ReadLine(); index.ReadLine(); var entry = Create <Entry> (filename); entry.Offset = UInt32.Parse(offset); entry.Size = UInt32.Parse(size); if (!entry.CheckPlacement(file.MaxOffset)) { return(null); } dir.Add(entry); } return(new ArcFile(file, this, dir)); } }
public override ArcFile TryOpen(ArcView file) { if (!VFS.IsPathEqualsToFileName(file.Name, "data.dsm") || (file.View.ReadUInt32(0) & 0xFFFFFF) != 0xBFBBEF) // UTF-8 BOM { return(null); } var dir = new List <Entry> { new Entry { Name = "data.txt", Type = "script", Offset = 0, Size = (uint)file.MaxOffset / 4 * 3, } }; return(new ArcFile(file, this, dir)); }
public override IImageDecoder OpenImage(ArcFile arc, Entry entry) { var aent = entry as AssetEntry; if (null == aent || aent.AssetObject.TypeName != "Texture2D") { return(base.OpenImage(arc, entry)); } var uarc = (UnityBundle)arc; var obj = aent.AssetObject; var bundles = new BundleStream(uarc.File, uarc.Segments); var input = new StreamRegion(bundles, obj.Offset, obj.Size); var reader = new AssetReader(input, entry.Name); reader.SetupReaders(obj.Asset); Texture2D tex = null; var type = obj.Type; if (type != null && type.Children.Any(t => t.Type == "StreamingInfo")) { var fields = obj.Deserialize(reader); tex = new Texture2D(); tex.Import(fields); var info = fields["m_StreamData"] as StreamingInfo; if (info != null) { var bundle = uarc.Bundles.FirstOrDefault(b => VFS.IsPathEqualsToFileName(info.Path, b.Name)); if (bundle != null) { tex.m_DataLength = (int)info.Size; input = new StreamRegion(bundles, bundle.Offset + info.Offset, info.Size); reader = new AssetReader(input, entry.Name); } } } if (null == tex) { tex = new Texture2D(); tex.Load(reader); } return(new Texture2DDecoder(tex, reader)); }
void DetectFileTypes(List <Entry> dir, ArcView file) { bool is_mask = VFS.IsPathEqualsToFileName(file.Name, "MASK.DAT"); var buffer = new byte[0x11]; foreach (var entry in dir) { file.View.Read(entry.Offset, buffer, 0, 0x11); if (buffer.AsciiEqual(0xD, "OggS")) { entry.ChangeType(OggAudio.Instance); entry.Offset += 0xD; entry.Size -= 0xD; } else if (is_mask || buffer[0] <= 1 && buffer[1] > 0 && buffer[1] <= 3) { entry.Type = "image"; } } }
public override ArcFile TryOpen(ArcView file) { if (!VFS.IsPathEqualsToFileName(file.Name, "CG") || file.MaxOffset <= DefaultDataOffset) { return(null); } uint index_pos = 0; var dir = new List <Entry>(); while (index_pos < DefaultDataOffset) { if (file.View.ReadByte(index_pos) == 0) { break; } var name = file.View.ReadString(index_pos, 0x20); if (string.IsNullOrWhiteSpace(name)) { return(null); } var entry = Create <CgEntry> (name); entry.Offset = file.View.ReadUInt32(index_pos + 0x20) + DefaultDataOffset; entry.Size = file.View.ReadUInt32(index_pos + 0x2C); if (!entry.CheckPlacement(file.MaxOffset)) { return(null); } entry.Info = new ImageMetaData { Width = file.View.ReadUInt32(index_pos + 0x24), Height = file.View.ReadUInt32(index_pos + 0x28), BPP = 8, }; dir.Add(entry); index_pos += 0x30; } if (0 == dir.Count) { return(null); } return(new ArcFile(file, this, dir)); }
public override ArcFile TryOpen(ArcView file) { if (file.MaxOffset > uint.MaxValue || !VFS.IsPathEqualsToFileName(file.Name, "ArchPac.dat")) { return(null); } foreach (var scheme in KnownSchemes.Values.Where(s => s.IndexOffset < file.MaxOffset).OrderBy(s => s.IndexOffset)) { var dir = ReadIndex(file, scheme.IndexOffset, file.MaxOffset); if (dir != null) { if (scheme.EventMap != null) { return(new SeraphArchive(file, this, dir, scheme)); } else { return(new ArcFile(file, this, dir)); } } } var scnpac_name = VFS.ChangeFileName(file.Name, "ScnPac.dat"); if (!VFS.FileExists(scnpac_name)) { return(null); } using (var scnpac = VFS.OpenView(scnpac_name)) { uint first_offset = scnpac.View.ReadUInt32(4); uint index_offset = scnpac.View.ReadUInt32(first_offset - 4); var dir = ReadIndex(scnpac, index_offset, file.MaxOffset); if (dir != null) { return(new ArcFile(file, this, dir)); } } return(null); }
public override ArcFile TryOpen(ArcView file) { uint key = 0x8B6A4E5F; int count = file.View.ReadInt32(4) ^ (int)key; if (!IsSaneCount(count)) { return(null); } var scheme = QueryScheme(file.Name); if (null == scheme) { return(null); } bool is_script = VFS.IsPathEqualsToFileName(file.Name, "script.dat"); var dir = new List <Entry> (count); using (var input = file.CreateStream(8, (uint)count * 0x15)) { foreach (var entry in ReadIndex(input, count, scheme, key)) { if (!entry.CheckPlacement(file.MaxOffset)) { return(null); } if (is_script) { entry.Hash ^= scheme.Hash; } dir.Add(entry); } } return(new ArcFile(file, this, dir)); }
public override ArcFile TryOpen(ArcView file) { if (!file.Name.HasExtension(".dat") || VFS.IsPathEqualsToFileName(file.Name, "00000000.dat")) { return(null); } var index_name = VFS.ChangeFileName(file.Name, "00000000.dat"); if (!VFS.FileExists(index_name)) { return(null); } var arc_name = Path.GetFileName(file.Name); using (var index = VFS.OpenView(index_name)) { var dir = ReadIndex(index, arc_name, file.MaxOffset); if (null == dir) { return(null); } return(new ArcFile(file, this, dir)); } }
public override ArcFile TryOpen(ArcView file) { if (file.MaxOffset > uint.MaxValue || !VFS.IsPathEqualsToFileName(file.Name, "ArchPac.dat")) { return(null); } foreach (var scheme in KnownSchemes.Values.Where(s => s.IndexOffset < file.MaxOffset)) { var dir = ReadIndex(file, scheme); if (dir != null) { if (scheme.EventMap != null) { return(new SeraphArchive(file, this, dir, scheme)); } else { return(new ArcFile(file, this, dir)); } } } return(null); }
ArchiveKey FindArchiveKey(string arc_name) { // look for "start.ps3" in the same directory as an archive var start_name = VFS.ChangeFileName(arc_name, "start.ps3"); if (!VFS.FileExists(start_name)) { return(null); } byte[] start_data; using (var start = VFS.OpenView(start_name)) { if (!start.View.AsciiEqual(0, "PS2A")) { return(null); } start_data = start.View.ReadBytes(0, (uint)start.MaxOffset); } arc_name = Path.GetFileName(arc_name); start_data = UnpackPs2(start_data); int table_count = start_data.ToInt32(0x10); int strings_offset = 0x30 + table_count * 4 + start_data.ToInt32(0x14); int strings_size = start_data.ToInt32(0x1C); if (strings_offset < 0x30 || strings_offset + strings_size > start_data.Length) { return(null); } // search strings table for archive name int string_pos = strings_offset; int strings_end = strings_offset + strings_size; int arc_id = -1; while (string_pos < strings_end) { int end_pos = Array.IndexOf <byte> (start_data, 0, string_pos); if (-1 == end_pos) { end_pos = strings_offset + strings_size; } if (end_pos != string_pos) { var text = Encodings.cp932.GetString(start_data, string_pos, end_pos - string_pos); if (VFS.IsPathEqualsToFileName(text, arc_name)) { arc_id = string_pos - strings_offset; break; } } string_pos = end_pos + 1; } if (-1 == arc_id) { return(null); } // search bytecode for a reference to archive name found above var id_bytes = new byte[4]; LittleEndian.Pack(arc_id, id_bytes, 0); for (int data_pos = 0x30 + table_count * 4; data_pos + 4 <= strings_offset; ++data_pos) { if (start_data[data_pos + 0] == id_bytes[0] && start_data[data_pos + 1] == id_bytes[1] && start_data[data_pos + 2] == id_bytes[2] && start_data[data_pos + 3] == id_bytes[3]) { if (start_data[data_pos - 0x33] == 2 && start_data[data_pos - 0x32] == 0 && start_data[data_pos - 0x31] == 1) { return(new ArchiveKey { IndexDirKey = start_data.ToUInt32(data_pos - 0x0C), IndexEntryKey = start_data.ToUInt32(data_pos - 0x18), EntryDataKey1 = start_data.ToUInt32(data_pos - 0x24), EntryDataKey2 = start_data.ToUInt32(data_pos - 0x30), }); } } } return(null); }
public override ArcFile TryOpen(ArcView file) { if (file.MaxOffset > uint.MaxValue || !VFS.IsPathEqualsToFileName(file.Name, "ARCHPAC.DAT")) { return(null); } int file_count = file.View.ReadInt16(0); if (!IsSaneCount(file_count)) { return(null); } uint index_pos = 2; var size_table = new uint[file_count]; for (int i = 0; i < file_count; ++i) { size_table[i] = file.View.ReadUInt32(index_pos); index_pos += 4; } var section_table = new SortedDictionary <int, uint>(); uint min_offset = (uint)file.MaxOffset; while (index_pos + 6 <= min_offset) { uint offset = file.View.ReadUInt32(index_pos); int index = file.View.ReadInt16(index_pos + 4); if (index < 0 || index > file_count || offset > file.MaxOffset) { return(null); } if (offset < min_offset) { min_offset = offset; } section_table[index] = offset; index_pos += 6; } var dir = new List <Entry> (file_count); int section_num = 0; foreach (var section in section_table) { int i = section.Key; uint base_offset = section.Value; do { uint size = size_table[i]; var entry = new PackedEntry { Name = string.Format("{0}-{1:D6}", section_num, i), Offset = base_offset, Size = size, }; if (!entry.CheckPlacement(file.MaxOffset)) { return(null); } if (section_num < DefaultSections.Length && DefaultSections[section_num] != null) { entry.Type = DefaultSections[section_num]; } if ("script" == entry.Type) { entry.IsPacked = true; } dir.Add(entry); base_offset += size; ++i; }while (i < file_count && !section_table.ContainsKey(i)); ++section_num; } return(new ArcFile(file, this, dir)); }
public override ArcFile TryOpen(ArcView file) { int count = file.View.ReadInt32(4); if (!IsSaneCount(count) || VFS.IsPathEqualsToFileName(file.Name, "00.mpk")) { return(null); } var list_name = VFS.ChangeFileName(file.Name, "00.mpk"); List <string> filelist; if (VFS.FileExists(list_name)) { using (var s = VFS.OpenStream(list_name)) using (var xs = new XoredStream(s, 0xA)) using (var reader = new StreamReader(xs, Encodings.cp932)) { filelist = new List <string> (count); string filename; while ((filename = reader.ReadLine()) != null) { filelist.Add(filename); } } } else { var base_name = Path.GetFileNameWithoutExtension(file.Name); filelist = Enumerable.Range(0, count).Select(x => string.Format("{0}#{1:D4}", base_name, x)).ToList(); } bool has_sizes = file.View.ReadByte(3) != 'P'; uint index_offset = 8; uint record_size = has_sizes ? 8u : 4u; var dir = new List <Entry> (count); for (int i = 0; i < count; ++i) { var entry = FormatCatalog.Instance.Create <Entry> (filelist[i]); entry.Offset = file.View.ReadUInt32(index_offset); if (has_sizes) { entry.Size = file.View.ReadUInt32(index_offset + 4); if (!entry.CheckPlacement(file.MaxOffset)) { return(null); } } else if (entry.Offset > file.MaxOffset) { return(null); } dir.Add(entry); index_offset += record_size; } if (!has_sizes) { for (int i = 1; i < count; ++i) { dir[i - 1].Size = (uint)(dir[i].Offset - dir[i - 1].Offset); } dir[dir.Count - 1].Size = (uint)(file.MaxOffset - dir[dir.Count - 1].Offset); } return(new ArcFile(file, this, dir)); }
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) { if (!VFS.IsPathEqualsToFileName(file.Name, "AVGDatas.pck")) { return(null); } int seed = Binary.BigEndian(file.View.ReadInt32(file.MaxOffset - 104)); var header = file.View.ReadBytes(file.MaxOffset - 100, 100); var rnd = new RandomGenerator(); rnd.Init(seed); rnd.Decrypt(header, 0, header.Length); uint checksum = (uint)(header[1] | header[2] << 8 | header[0] << 16 | header[3] << 24) ^ 0xDEFD32D3; uint length = BigEndian.ToUInt32(header, 24); if (checksum != length) { return(null); } uint idx_pos = BigEndian.ToUInt32(header, 28); uint idx_size = Binary.BigEndian(file.View.ReadUInt32(idx_pos)); uint index_size; var index = ReadChunk(file, 8, idx_pos + 4, out index_size); if (index_size >= 0x80000000) { index_size &= 0x7FFFFFFF; var unpacked = new byte[idx_size]; LzssUnpack(index, index.Length, unpacked); index = unpacked; } using (var input = new BinMemoryStream(index)) { var dir = new List <Entry>(); int dir_count = 0; while (input.PeekByte() != -1) { input.ReadInt32(); input.ReadInt32(); input.ReadInt32(); int count = Binary.BigEndian(input.ReadInt32()); var dir_name = dir_count.ToString("X4"); for (int i = 0; i < count; ++i) { var name = input.ReadCString(0x28); name = Path.Combine(dir_name, name); var entry = Create <PckEntry> (name); entry.Offset = Binary.BigEndian(input.ReadUInt32()); entry.Size = Binary.BigEndian(input.ReadUInt32()); entry.IsEncrypted = input.ReadInt32() != 0; entry.UnpackedSize = input.ReadUInt32(); entry.IsPacked = entry.Size != entry.UnpackedSize; if (!entry.CheckPlacement(file.MaxOffset)) { return(null); } dir.Add(entry); } ++dir_count; } return(new ArcFile(file, this, dir)); } }
public override ArcFile TryOpen(ArcView file) { int count = file.View.ReadInt32(0); if (!IsSaneCount(count) || 8 + count * MinEntryLength >= file.MaxOffset) { return(null); } uint is_compressed = file.View.ReadUInt32(4); if (is_compressed > 1) // should be either 0 or 1 { return(null); } var scheme = GuessScheme(file, count); // additional filename extension check avoids dialog popup on false positives if (null == scheme && KnownSchemes.Count > 0 && file.Name.HasExtension(".arc")) { scheme = QueryScheme(); } if (null == scheme) { return(null); } // special case for "instdata.arc" archives if (scheme.Keyword != "inst" && VFS.IsPathEqualsToFileName(file.Name, "instdata.arc")) { scheme = new EncryptionScheme("inst", scheme.NameLength); } int index_size = count * (scheme.NameLength + 12); var index = new byte[index_size]; if (index_size != file.View.Read(8, index, 0, (uint)index_size)) { return(null); } DecryptIndex(index, scheme.Keyword); uint data_offset = LittleEndian.ToUInt32(index, scheme.NameLength + 8); if (data_offset != 8 + index_size) { return(null); } int index_offset = 0; var dir = new List <Entry> (count); for (int i = 0; i < count; ++i) { var name = Binary.GetCString(index, index_offset, scheme.NameLength); index_offset += scheme.NameLength; var entry = FormatCatalog.Instance.Create <PackedEntry> (name); entry.UnpackedSize = LittleEndian.ToUInt32(index, index_offset); entry.Size = LittleEndian.ToUInt32(index, index_offset + 4); entry.Offset = LittleEndian.ToUInt32(index, index_offset + 8); entry.IsPacked = is_compressed != 0; if (0 != entry.Size) { if (entry.Offset < data_offset || !entry.CheckPlacement(file.MaxOffset)) { return(null); } } dir.Add(entry); index_offset += 12; } return(new ArcFile(file, this, dir)); }
public override ArcFile TryOpen(ArcView file) { uint file_size = file.View.ReadUInt32(4); if (file_size != file.MaxOffset) { return(null); } int count = file.View.ReadInt32(8); if (count <= 0 || count > 0xfffff) { return(null); } int dir_level = file.View.ReadByte(0x0d); int dir_entries = file.View.ReadUInt16(0x0e); uint index_offset = 0x10; uint index_size = (uint)(count * 0x18 + dir_entries * 8); if (index_size > file.View.Reserve(index_offset, index_size)) { return(null); } List <DirEntry> folders = null; if (0 != dir_entries && 2 == dir_level) { folders = new List <DirEntry> (dir_entries); uint dir_offset = index_offset + (uint)count * 0x18; for (int i = 0; i < dir_entries; ++i) { folders.Add(new DirEntry { Name = file.View.ReadString(dir_offset, 4), Index = file.View.ReadInt32(dir_offset + 4) }); dir_offset += 8; } } bool is_mask_arc = VFS.IsPathEqualsToFileName(file.Name, "mask.arc"); var dir = new List <Entry> (count); int next_folder = null == folders ? count : folders[0].Index; int folder = 0; string current_folder = ""; for (int i = 0; i < count; ++i) { while (i >= next_folder && folder < folders.Count) { current_folder = folders[folder++].Name; if (folders.Count == folder) { next_folder = count; } else { next_folder = folders[folder].Index; } } string name = file.View.ReadString(index_offset, 0x10); if (0 == name.Length) { return(null); } var offset = file.View.ReadUInt32(index_offset + 0x10); var entry = new AutoEntry(Path.Combine(current_folder, name), () => { if (is_mask_arc) { return(s_MskFormat.Value); } uint signature = file.View.ReadUInt32(offset); switch (signature & 0xFFFF) { case 0x4D43: return(s_CmFormat.Value); case 0x4D41: return(s_AmFormat.Value); case 0x4D42: return(ImageFormat.Bmp); default: return(AutoEntry.DetectFileType(signature)); } }); entry.Offset = offset; entry.Size = file.View.ReadUInt32(index_offset + 0x14); if (!entry.CheckPlacement(file.MaxOffset)) { return(null); } dir.Add(entry); index_offset += 0x18; } return(new ArcFile(file, this, dir)); }