Пример #1
0
            public static LzmaHeader Read(Stream stream)
            {
                var header = new LzmaHeader();

                byte[] buffer = new byte[5];

                stream.Read(buffer, 0, 4);
                header.Identifier = BitConverter.ToUInt32(buffer, 0);

                if (header.Identifier != LZMA_ID)
                {
                    throw new NotSupportedException($"Unrecognized identifier {header.Identifier}");
                }

                stream.Read(buffer, 0, 4);
                header.ActualSize = BitConverter.ToUInt32(buffer, 0);

                stream.Read(buffer, 0, 4);
                header.LzmaSize = BitConverter.ToUInt32(buffer, 0);

                stream.Read(buffer, 0, 5);
                header.Properties = buffer;

                return(header);
            }
Пример #2
0
        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);
                }
            }
        }
Пример #3
0
        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);
        }
Пример #4
0
            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);
            }