public Stream GetLumpStream(LumpType type) { var info = GetLumpInfo(type); if (info.UncompressedSize == 0) { return(GetSubStream(info.Offset, info.Length)); } using (var stream = GetSubStream(info.Offset, LzmaHeader.Size)) { var lzmaHeader = LzmaHeader.Read(stream); using (var compressedStream = GetSubStream(info.Offset + LzmaHeader.Size, lzmaHeader.LzmaSize)) { var uncompressedStream = new MemoryStream(info.UncompressedSize); Decoder decoder = new Decoder(); decoder.SetDecoderProperties(lzmaHeader.Properties); decoder.Code(compressedStream, uncompressedStream, lzmaHeader.LzmaSize, lzmaHeader.ActualSize, null); uncompressedStream.Seek(0, SeekOrigin.Begin); return(uncompressedStream); } } }
private int ReadLumpValues <T>(LumpType type, int srcOffset, T[] dst, int dstOffset, int count) where T : struct { var info = GetLumpInfo(type); // 0 = no compression if (info.UncompressedSize == 0) { var tSize = Marshal.SizeOf <T>(); var length = info.Length / tSize; if (srcOffset > length) { srcOffset = length; } if (srcOffset + count > length) { count = length - srcOffset; } if (count <= 0) { return(0); } using (var stream = GetLumpStream(type)) { stream.Seek(tSize * srcOffset, SeekOrigin.Begin); LumpReader <T> .ReadLumpFromStream(stream, count, dst, dstOffset); } } else { // LZMA compressed lump if (type == LumpType.GAME_LUMP) { // game lumps are compressed individually // https://developer.valvesoftware.com/wiki/Source_BSP_File_Format#Lump_compression throw new NotImplementedException(); } using (var stream = GetSubStream(info.Offset, LzmaHeader.Size)) { var lzmaHeader = LzmaHeader.Read(stream); using (var compressedStream = GetSubStream(info.Offset + LzmaHeader.Size, lzmaHeader.LzmaSize)) { using (var uncompressedStream = new MemoryStream(info.UncompressedSize)) { Decoder decoder = new Decoder(); decoder.SetDecoderProperties(lzmaHeader.Properties); decoder.Code(compressedStream, uncompressedStream, lzmaHeader.LzmaSize, lzmaHeader.ActualSize, null); var tSize = Marshal.SizeOf <T>(); var length = info.UncompressedSize / tSize; if (srcOffset > length) { srcOffset = length; } if (srcOffset + count > length) { count = length - srcOffset; } if (count <= 0) { return(0); } uncompressedStream.Seek(tSize * srcOffset, SeekOrigin.Begin); LumpReader <T> .ReadLumpFromStream(uncompressedStream, count, dst, dstOffset); if (type == LumpType.PLANES) { return(count); } } } } } return(count); }
public Stream OpenItem(string id) { EnsureLoaded(); var item = _items[id]; // Find index of current lump var keyArray = _items.Keys.ToArray(); int index = -1; for (int i = 0; i < keyArray.Length; i++) { if (keyArray[i] == id) { index = i; break; } } // https://developer.valvesoftware.com/wiki/Source_BSP_File_Format#Lump_compression // Get the actual length of the item using offset of the next item. var valueArray = _items.Values.ToArray(); var actualLength = item.FileLength; if (index != -1) { if (index < _items.Count - 1) { // The last game lump is /supposed/ to be a dummy containing nothing but the offset, // but sometimes the offset is 0 which would result in negative actualLength. if (valueArray[index + 1].FileOffset > valueArray[index].FileOffset) { actualLength = valueArray[index + 1].FileOffset - valueArray[index].FileOffset; } } } var stream = _bspFile.GetSubStream(item.FileOffset, actualLength); LzmaHeader lzmaHeader; try { lzmaHeader = LzmaHeader.Read(stream); } catch (NotSupportedException e) { stream.Seek(0, SeekOrigin.Begin); return(stream); } using (var compressedStream = _bspFile.GetSubStream(item.FileOffset + LzmaHeader.Size, lzmaHeader.LzmaSize)) { using (var uncompressedStream = new MemoryStream(( int )lzmaHeader.ActualSize)) { Decoder decoder = new Decoder(); decoder.SetDecoderProperties(lzmaHeader.Properties); decoder.Code(compressedStream, uncompressedStream, lzmaHeader.LzmaSize, lzmaHeader.ActualSize, null); stream = new MemoryStream(( int )stream.Length); uncompressedStream.Seek(0, SeekOrigin.Begin); uncompressedStream.CopyTo(stream); } } stream.Seek(0, SeekOrigin.Begin); return(stream); }