Esempio n. 1
0
        public void ExtractEntry(DLCEntry entry, Stream input, Stream output)
        {
            input.JumpTo(entry.dataOffset);
            if (entry.compressedBlockSizesIndex == -1)
            {
                output.WriteFromStream(input, entry.uncomprSize);
            }
            else
            {
                var  uncompressedBlockBuffers = new List <byte[]>();
                var  compressedBlockBuffers   = new List <byte[]>();
                var  blockBytesLeft           = new List <long>();
                long bytesLeft = entry.uncomprSize;
                for (int j = 0; j < entry.numBlocks; j++)
                {
                    blockBytesLeft.Add(bytesLeft);
                    int compressedBlockSize   = blockSizes[entry.compressedBlockSizesIndex + j];
                    int uncompressedBlockSize = (int)Math.Min(bytesLeft, maxBlockSize);
                    if (compressedBlockSize == 0)
                    {
                        compressedBlockSize = (int)maxBlockSize;
                    }
                    compressedBlockBuffers.Add(input.ReadToBuffer(compressedBlockSize));
                    uncompressedBlockBuffers.Add(null);
                    bytesLeft -= uncompressedBlockSize;
                }

                Parallel.For(0, entry.numBlocks, j =>
                {
                    int compressedBlockSize   = blockSizes[entry.compressedBlockSizesIndex + (int)j];
                    int uncompressedBlockSize = (int)Math.Min(blockBytesLeft[(int)j], maxBlockSize);
                    if (compressedBlockSize == 0 || compressedBlockSize == blockBytesLeft[(int)j])
                    {
                        uncompressedBlockBuffers[(int)j] = compressedBlockBuffers[(int)j];
                    }
                    else
                    {
                        uncompressedBlockBuffers[(int)j] = LZMA.Decompress(compressedBlockBuffers[(int)j], (uint)uncompressedBlockSize);
                        if (uncompressedBlockBuffers[(int)j].Length == 0)
                        {
                            throw new Exception();
                        }
                    }
                });

                for (int j = 0; j < entry.numBlocks; j++)
                {
                    output.WriteFromBuffer(uncompressedBlockBuffers[j]);
                }
            }
        }
Esempio n. 2
0
        private void LoadHeader(Stream stream)
        {
            uint tag = stream.ReadUInt32();

            if (tag != SfarTag)
            {
                throw new Exception("Wrong SFAR tag");
            }
            uint sfarVersion = stream.ReadUInt32();

            if (sfarVersion != SfarVersion)
            {
                throw new Exception("Wrong SFAR version");
            }

            uint dataOffset    = stream.ReadUInt32();
            uint entriesOffset = stream.ReadUInt32();

            TotalFilesInDLC = stream.ReadUInt32();
            uint sizesArrayOffset = stream.ReadUInt32();

            maxBlockSize = stream.ReadUInt32();
            uint compressionTag = stream.ReadUInt32();

            if (compressionTag != LZMATag)
            {
                throw new Exception("Not LZMA compression for SFAR file");
            }

            uint numBlockSizes = 0;

            stream.JumpTo(entriesOffset);
            filesList = new List <DLCEntry>();
            for (int i = 0; i < TotalFilesInDLC; i++)
            {
                DLCEntry file = new DLCEntry
                {
                    filenameHash = stream.ReadToBuffer(16),
                    compressedBlockSizesIndex = stream.ReadInt32(),
                    uncomprSize = stream.ReadUInt32()
                };
                file.uncomprSize |= (long)stream.ReadByte() << 32;
                file.dataOffset   = stream.ReadUInt32();
                file.dataOffset  |= (long)stream.ReadByte() << 32;
                file.numBlocks    = (uint)((file.uncomprSize + maxBlockSize - 1) / maxBlockSize);
                filesList.Add(file);
                numBlockSizes    += file.numBlocks;
                UncompressedSize += file.uncomprSize;
            }

            stream.JumpTo(sizesArrayOffset);
            blockSizes = new List <ushort>();
            for (int i = 0; i < numBlockSizes; i++)
            {
                blockSizes.Add(stream.ReadUInt16());
            }

            filenamesIndex = -1;
            for (int i = 0; i < TotalFilesInDLC; i++)
            {
                if (StructuralComparisons.StructuralEqualityComparer.Equals(filesList[i].filenameHash, FileListHash))
                {
                    stream.JumpTo(filesList[i].dataOffset);
                    int    compressedBlockSize = blockSizes[filesList[i].compressedBlockSizesIndex];
                    byte[] inBuf  = stream.ReadToBuffer(compressedBlockSize);
                    byte[] outBuf = LZMA.Decompress(inBuf, (uint)filesList[i].uncomprSize);
                    if (outBuf.Length == 0)
                    {
                        throw new Exception();
                    }
                    StreamReader filenamesStream = new StreamReader(new MemoryStream(outBuf));
                    while (filenamesStream.EndOfStream == false)
                    {
                        string name = filenamesStream.ReadLine();
                        byte[] hash = MD5.Create().ComputeHash(Encoding.ASCII.GetBytes(name.ToLowerInvariant()));
                        for (int l = 0; l < TotalFilesInDLC; l++)
                        {
                            if (StructuralComparisons.StructuralEqualityComparer.Equals(filesList[l].filenameHash, hash))
                            {
                                DLCEntry f = filesList[l];
                                f.filenamePath = name.Replace('/', '\\');
                                filesList[l]   = f;
                            }
                        }
                    }
                    filenamesIndex = i;
                    break;
                }
            }
        }