private void AddLayoutEntry(CASResult blte) { if (Layout.ContainsKey(blte.Hash)) { Layout.Remove(blte.Hash); } // get layout string string layoutString; uint size = blte.CompressedSize - 30; if (blte.DataHash == CASContainer.BuildConfig.GetKey("root")) // root is always z { layoutString = "z"; } else if (size >= 1024 * 256) // 256K* seems to be the max { layoutString = "b:{256K*=z}"; } else if (size > 1024) { layoutString = "b:{" + (int)Math.Floor(size / 1024d) + "K*=z}"; // closest floored KB } else { layoutString = "b:{" + size + "*=z}"; // actual B size } // string index int stridx = LayoutStringTable.IndexOf(layoutString); if (stridx == -1) { stridx = LayoutStringTable.Count - 2; // ignore the 0 byte LayoutStringTable.Insert(stridx, layoutString); } // create the entry var entry = new EncodingLayout() { Size = size, Hash = blte.Hash, StringIndex = (uint)stridx }; Layout.Add(entry.Hash, entry); }
public EncodingHandler(BLTEStream blte) { if (blte.Length != long.Parse(CASContainer.BuildConfig["encoding-size"][0])) { CASContainer.Settings?.Logger.LogAndThrow(Logging.LogType.Critical, "Encoding File is corrupt."); } BinaryReader stream = new BinaryReader(blte); Header = new EncodingHeader() { Magic = stream.ReadBytes(2), Version = stream.ReadByte(), ChecksumSizeA = stream.ReadByte(), ChecksumSizeB = stream.ReadByte(), FlagsA = stream.ReadUInt16(), FlagsB = stream.ReadUInt16(), NumEntriesA = stream.ReadUInt32BE(), NumEntriesB = stream.ReadUInt32BE(), StringBlockSize = stream.ReadUInt40BE() }; // stringTableA LayoutStringTable.AddRange(Encoding.ASCII.GetString(stream.ReadBytes((int)Header.StringBlockSize)).Split('\0')); // skip header block A stream.ReadBytes((int)Header.NumEntriesA * 32); // encoding table entry block for (int i = 0; i < Header.NumEntriesA; i++) { long start = stream.BaseStream.Position; ushort keysCount; while ((keysCount = stream.ReadUInt16()) != 0) { EncodingEntry entry = new EncodingEntry() { DecompressedSize = stream.ReadUInt32BE(), Hash = new MD5Hash(stream) }; for (int ki = 0; ki < keysCount; ki++) { entry.Keys.Add(new MD5Hash(stream)); } Data.Add(entry.Hash, entry); } if (stream.BaseStream.Position % CHUNK_SIZE != 0) { stream.BaseStream.Position += CHUNK_SIZE - ((stream.BaseStream.Position - start) % CHUNK_SIZE); } } // skip header block B stream.ReadBytes((int)Header.NumEntriesB * 32); // layout table entry block for (int i = 0; i < Header.NumEntriesB; i++) { long start = stream.BaseStream.Position; MD5Hash hash; while (!(hash = new MD5Hash(stream)).IsEmpty) { var entry = new EncodingLayout() { Hash = hash, StringIndex = stream.ReadUInt32BE(), Size = stream.ReadUInt40BE() }; Layout.Add(entry.Hash, entry); } if (stream.BaseStream.Position % CHUNK_SIZE != 0) { stream.BaseStream.Position += CHUNK_SIZE - ((stream.BaseStream.Position - start) % CHUNK_SIZE); } } stream.ReadBytes((int)(stream.BaseStream.Length - stream.BaseStream.Position)); //EncodingStringTable EncodingMap = blte.EncodingMap.ToArray(); blte?.Dispose(); stream?.Dispose(); }