public FileIndex( string uopFile, int length, string uopEntryExtension, int idxLength, bool hasExtra) { Index = new Entry3D[length]; MulPath = Core.FindDataFile(uopFile); /* UOP files support code, written by Wyatt (c) www.ruosi.org * idxLength variable was added for compatibility with legacy code for art (see art.cs) * At the moment the only UOP file having entries with extra field is gumpartlegacy.uop, * and it's two dwords in the beginning of the entry. * It's possible that UOP can include some entries with unknown hash: not really unknown for me, but * not useful for reading legacy entries. That's why i removed unknown hash exception throwing from this code */ if (MulPath != null && MulPath.EndsWith(".uop")) { using (FileStream index = new FileStream(MulPath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) { Stream = new FileStream(MulPath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); FileInfo fi = new FileInfo(MulPath); string uopPattern = fi.Name.Replace(fi.Extension, "").ToLowerInvariant(); using (BinaryReader br = new BinaryReader(Stream)) { br.BaseStream.Seek(0, SeekOrigin.Begin); if (br.ReadInt32() != 0x50594D) { return; } br.ReadInt64(); // version + signature long nextBlock = br.ReadInt64(); br.ReadInt32(); // block capacity int count = br.ReadInt32(); if (idxLength > 0) { IdxLength = idxLength * 12; } Dictionary <ulong, int> hashes = new Dictionary <ulong, int>(); for (int i = 0; i < length; i++) { string entryName = string.Format("build/{0}/{1:D8}{2}", uopPattern, i, uopEntryExtension); ulong hash = UOPHash.HashLittle2(entryName); if (!hashes.ContainsKey(hash)) { hashes.Add(hash, i); } } br.BaseStream.Seek(nextBlock, SeekOrigin.Begin); do { int filesCount = br.ReadInt32(); nextBlock = br.ReadInt64(); for (int i = 0; i < filesCount; i++) { long offset = br.ReadInt64(); int headerLength = br.ReadInt32(); int compressedLength = br.ReadInt32(); int decompressedLength = br.ReadInt32(); ulong hash = br.ReadUInt64(); br.ReadUInt32(); // Adler32 short flag = br.ReadInt16(); int entryLength = flag == 1 ? compressedLength : decompressedLength; if (offset == 0) { continue; } if (hashes.TryGetValue(hash, out int idx)) { if (idx < 0 || idx > Index.Length) { return; } Index[idx].lookup = (int)(offset + headerLength); Index[idx].length = entryLength; if (hasExtra) { long curPos = br.BaseStream.Position; br.BaseStream.Seek(offset + headerLength, SeekOrigin.Begin); byte[] extra = br.ReadBytes(8); ushort extra1 = (ushort)((extra[3] << 24) | (extra[2] << 16) | (extra[1] << 8) | extra[0]); ushort extra2 = (ushort)((extra[7] << 24) | (extra[6] << 16) | (extra[5] << 8) | extra[4]); Index[idx].lookup += 8; Index[idx].extra = extra1 << 16 | extra2; br.BaseStream.Seek(curPos, SeekOrigin.Begin); } } } }while (br.BaseStream.Seek(nextBlock, SeekOrigin.Begin) != 0); } } } }
public FileIndex(string uopFile, int entryCount, string entryExt, bool extended) : this(entryCount) { do { _IdxPath = _BinPath = Core.FindDataFile(uopFile); try { if (_BinPath != null) { try { File = new FileInfo(_BinPath); } catch { File = null; } _BinLoaded = File?.Exists ?? false; } } catch { } try { if (File != null) { using (var stream = new FileStream(File.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (var reader = new BinaryReader(stream)) { if (reader.ReadInt32() == 0x50594D) { reader.ReadInt64(); // version + signature var nextBlock = reader.ReadInt64(); reader.ReadInt32(); // block capacity reader.ReadInt32(); // block count var hashes = new Dictionary <ulong, int>(); var root = $"build/{Path.GetFileNameWithoutExtension(_IdxPath).ToLowerInvariant()}"; for (var i = 0; i < entryCount; i++) { hashes[UOPHash.HashLittle2($"{root}/{i:D8}{entryExt}")] = i; } stream.Seek(nextBlock, SeekOrigin.Begin); do { var filesCount = reader.ReadInt32(); nextBlock = reader.ReadInt64(); for (var i = 0; i < filesCount; i++) { var offset = reader.ReadInt64(); var headerLength = reader.ReadInt32(); var compressedLength = reader.ReadInt32(); var decompressedLength = reader.ReadInt32(); var hash = reader.ReadUInt64(); reader.ReadUInt32(); // Adler32 var flag = reader.ReadInt16(); var entryLength = flag == 1 ? compressedLength : decompressedLength; if (offset == 0 || !hashes.TryGetValue(hash, out var idx)) { continue; } if (idx < 0 || idx > Index.Length) { continue; } Index[idx].Offset = (int)(offset + headerLength); Index[idx].Size = entryLength; if (!extended) { continue; } var curPos = stream.Position; stream.Seek(offset + headerLength, SeekOrigin.Begin); var extra = reader.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]); Index[idx].Offset += 8; Index[idx].Data = extra1 << 16 | extra2; stream.Seek(curPos, SeekOrigin.Begin); } }while (stream.Seek(nextBlock, SeekOrigin.Begin) != 0); _IdxLoaded = true; } } } } catch { } }while (CheckRetry()); }
public static void UOPLoad(string path) { var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); var streamReader = new BinaryReader(stream); // Head Information Start if (streamReader.ReadInt32() != 0x0050594D) // Not a UOP Files { return; } if (streamReader.ReadInt32() > 5) // Bad Version { return; } // Multi ID List Array Start var chunkIds = new Dictionary <ulong, int>(); var chunkIds2 = new Dictionary <ulong, int>(); UOPHash.BuildChunkIDs(ref chunkIds, ref chunkIds2); // Multi ID List Array End streamReader.ReadUInt32(); // format timestamp? 0xFD23EC43 var startAddress = streamReader.ReadInt64(); var blockSize = streamReader.ReadInt32(); // files in each block var totalSize = streamReader.ReadInt32(); // Total File Count stream.Seek(startAddress, SeekOrigin.Begin); // Head Information End long nextBlock; do { var blockFileCount = streamReader.ReadInt32(); nextBlock = streamReader.ReadInt64(); var index = 0; do { var offset = streamReader.ReadInt64(); var headerSize = streamReader.ReadInt32(); // header length var compressedSize = streamReader.ReadInt32(); // compressed size var decompressedSize = streamReader.ReadInt32(); // decompressed size var filehash = streamReader.ReadUInt64(); // filename hash (HashLittle2) var datablockhash = streamReader.ReadUInt32(); // data hash (Adler32) var flag = streamReader.ReadInt16(); // compression method (0 = none, 1 = zlib) index++; if (offset == 0 || decompressedSize == 0 || filehash == 0x126D1E99DDEDEE0A) // Exclude housing.bin { continue; } // Multi ID Search Start var chunkID = -1; if (!chunkIds.TryGetValue(filehash, out chunkID)) { if (chunkIds2.TryGetValue(filehash, out var tmpChunkID)) { chunkID = tmpChunkID; } } // Multi ID Search End var positionpoint = stream.Position; // save current position // Decompress Data Start stream.Seek(offset + headerSize, SeekOrigin.Begin); var sourceData = new byte[compressedSize]; if (stream.Read(sourceData, 0, compressedSize) != compressedSize) { continue; } byte[] data; if (flag == 1) { var destData = new byte[decompressedSize]; /*ZLibError error = */ Compression.Compressor.Decompress(destData, ref decompressedSize, sourceData, compressedSize); data = destData; } else { data = sourceData; } // End Decompress Data var tileList = new List <MultiTileEntry>(); using (var fs = new MemoryStream(data)) { using (var reader = new BinaryReader(fs)) { var a = reader.ReadUInt32(); var count = reader.ReadUInt32(); for (uint i = 0; i < count; i++) { var ItemId = reader.ReadUInt16(); var x = reader.ReadInt16(); var y = reader.ReadInt16(); var z = reader.ReadInt16(); var flagint = reader.ReadUInt16(); TileFlag flagg; switch (flagint) { default: case 0: flagg = TileFlag.Background; break; case 1: flagg = TileFlag.None; break; case 257: flagg = TileFlag.Generic; break; } var clilocsCount = reader.ReadUInt32(); if (clilocsCount != 0) { fs.Seek(fs.Position + (clilocsCount * 4), SeekOrigin.Begin); // binary block bypass } tileList.Add(new MultiTileEntry(ItemId, x, y, z, flagg)); } reader.Close(); } } Components[chunkID] = new MultiComponentList(tileList); stream.Seek(positionpoint, SeekOrigin.Begin); // back to position }while (index < blockFileCount); }while (stream.Seek(nextBlock, SeekOrigin.Begin) != 0); chunkIds.Clear(); chunkIds2.Clear(); }
public FileIndex(string uopFile, int length, string uopEntryExtension, int idxLength, bool hasExtra) { Index = new Entry3D[length]; _Path = Core.FindDataFile(uopFile); if (_Path != null && _Path.EndsWith(".uop")) { using (var index = new FileStream(_Path, FileMode.Open, FileAccess.Read, FileShare.Read)) { Stream = new FileStream(_Path, FileMode.Open, FileAccess.Read, FileShare.Read); var fi = new FileInfo(_Path); var uopPattern = fi.Name.Replace(fi.Extension, "").ToLowerInvariant(); using (var br = new BinaryReader(Stream)) { br.BaseStream.Seek(0, SeekOrigin.Begin); if (br.ReadInt32() != 0x50594D) { return; } br.ReadInt64(); // version + signature var nextBlock = br.ReadInt64(); br.ReadInt32(); // block capacity var count = br.ReadInt32(); if (idxLength > 0) { IdxLength = idxLength * 12; } var hashes = new Dictionary <ulong, int>(); for (var i = 0; i < length; i++) { var entryName = System.String.Format("build/{0}/{1:D8}{2}", uopPattern, i, uopEntryExtension); var hash = UOPHash.HashLittle2(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; } if (hashes.TryGetValue(hash, out var idx)) { if (idx < 0 || idx > Index.Length) { return; } Index[idx].lookup = (int)(offset + headerLength); Index[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]); Index[idx].lookup += 8; Index[idx].extra = extra1 << 16 | extra2; br.BaseStream.Seek(curPos, SeekOrigin.Begin); } } } }while (br.BaseStream.Seek(nextBlock, SeekOrigin.Begin) != 0); } } } }