protected override FileIndexEntry3D[] ReadEntries() { if (!File.Exists(IndexPath) || !File.Exists(DataPath)) { return(new FileIndexEntry3D[0]); } var entries = new List <FileIndexEntry3D>(); var length = (int)((new FileInfo(IndexPath).Length / 3) / 4); using (var index = new FileStream(IndexPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { var bin = new BinaryReader(index); var count = (int)(index.Length / 12); for (var i = 0; i < count && i < length; ++i) { var entry = new FileIndexEntry3D(bin.ReadInt32(), bin.ReadInt32(), bin.ReadInt32()); entries.Add(entry); } for (var i = count; i < length; ++i) { var entry = new FileIndexEntry3D(-1, -1, -1); entries.Add(entry); } } var patches = VerData.Patches; for (var i = 0; i < patches.Length; ++i) { var patch = patches[i]; if (patch.file == patchFile && patch.index >= 0 && patch.index < entries.Count) { var entry = entries.ElementAt(patch.index); entry.Lookup = patch.lookup; entry.Length = patch.length | (1 << 31); entry.Extra = patch.extra; } } return(entries.ToArray()); }
protected override FileIndexEntry3D[] ReadEntries() { var length = Length; var dataPath = DataPath; var entries = new FileIndexEntry3D[length]; // In the mul file index, we read everything sequentially, and -1 is applied to invalid lookups. // UOP does not do this, so we need to do it ourselves. for (var i = 0; i < entries.Length; i++) { entries[i].Lookup = -1; } using (var index = new FileStream(dataPath, FileMode.Open, FileAccess.Read, FileShare.Read)) { var fi = new FileInfo(dataPath); var uopPattern = Path.GetFileNameWithoutExtension(fi.Name).ToLowerInvariant(); using (var br = new BinaryReader(index)) { br.BaseStream.Seek(0, SeekOrigin.Begin); if (br.ReadInt32() != UOP_MAGIC_NUMBER) { throw new ArgumentException("Bad UOP file."); } br.ReadInt64(); // version + signature var nextBlock = br.ReadInt64(); br.ReadInt32(); // block capacity var count = br.ReadInt32(); var hashes = new Dictionary <ulong, int>(); for (var i = 0; i < length; i++) { var entryName = string.Format("build/{0}/{1:D8}{2}", uopPattern, i, _extension); var hash = CreateHash(entryName); if (!hashes.ContainsKey(hash)) { hashes.Add(hash, i); } } br.BaseStream.Seek(nextBlock, SeekOrigin.Begin); do { var filesCount = br.ReadInt32(); nextBlock = br.ReadInt64(); for (var i = 0; i < filesCount; i++) { var offset = br.ReadInt64(); var headerLength = br.ReadInt32(); var compressedLength = br.ReadInt32(); var decompressedLength = br.ReadInt32(); var hash = br.ReadUInt64(); br.ReadUInt32(); var flag = br.ReadInt16(); var entryLength = flag == 1 ? compressedLength : decompressedLength; if (offset == 0) { continue; } int idx; if (hashes.TryGetValue(hash, out idx)) { if (idx < 0 || idx > entries.Length) { throw new IndexOutOfRangeException("hashes dictionary and files collection have different count of entries!"); } entries[idx].Lookup = (int)(offset + headerLength); entries[idx].Length = entryLength; if (_hasExtra) { var curPos = br.BaseStream.Position; br.BaseStream.Seek(offset + headerLength, SeekOrigin.Begin); var extra = br.ReadBytes(8); var extra1 = (ushort)((extra[3] << 24) | (extra[2] << 16) | (extra[1] << 8) | extra[0]); var extra2 = (ushort)((extra[7] << 24) | (extra[6] << 16) | (extra[5] << 8) | extra[4]); entries[idx].Lookup += 8; entries[idx].Extra = extra1 << 16 | extra2; br.BaseStream.Seek(curPos, SeekOrigin.Begin); } } } } while (br.BaseStream.Seek(nextBlock, SeekOrigin.Begin) != 0); } } return(entries); }