protected override FileIndexEntry[] ReadEntries() { var entries = new List <FileIndexEntry>(); var length = (int)((new FileInfo(_indexPath).Length / 3) / 4); using (var index = new FileStream(_indexPath, FileMode.Open, FileAccess.Read, FileShare.Read)) { var bin = new BinaryReader(index); var count = (int)(index.Length / 12); for (var i = 0; i < count && i < length; ++i) { var entry = new FileIndexEntry { Lookup = bin.ReadInt32(), Length = bin.ReadInt32(), Extra = bin.ReadInt32() }; entries.Add(entry); } for (var i = count; i < length; ++i) { var entry = new FileIndexEntry { Lookup = -1, Length = -1, Extra = -1 }; entries.Add(entry); } } return(entries.ToArray()); }
protected override FileIndexEntry[] ReadEntries() { var length = Length; var dataPath = DataPath; var entries = new FileIndexEntry[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(); // Adler32 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); }