private void loadHeader(MemoryStream 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();

            filesCount = 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 <FileEntry>();
            for (int i = 0; i < filesCount; i++)
            {
                FileEntry file = new FileEntry();
                file.filenameHash = stream.ReadToBuffer(16);
                file.compressedBlockSizesIndex = stream.ReadInt32();
                file.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;
            }

            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 < filesCount; 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 = new SevenZipHelper.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 < filesCount; l++)
                        {
                            if (StructuralComparisons.StructuralEqualityComparer.Equals(filesList[l].filenameHash, hash))
                            {
                                FileEntry f = filesList[l];
                                f.filenamePath = name;
                                filesList[l]   = f;
                            }
                        }
                    }
                    filenamesIndex = i;
                    break;
                }
            }
            if (filenamesIndex == -1)
            {
                throw new Exception("filenames entry not found");
            }
        }
Exemple #2
0
        public void extract(string SFARfilename, string outPath)
        {
            loadHeader(SFARfilename);

            Directory.CreateDirectory(Path.Combine(outPath, "CookedPCConsole"));
            using (FileStream outputFile = new FileStream(Path.Combine(outPath, "CookedPCConsole", "Default.sfar"), FileMode.Create, FileAccess.Write))
            {
                outputFile.WriteUInt32(SfarTag);
                outputFile.WriteUInt32(SfarVersion);
                outputFile.WriteUInt32(HeaderSize);
                outputFile.WriteUInt32(HeaderSize);
                outputFile.WriteUInt32((uint)filesList.Count);
                outputFile.WriteUInt32(HeaderSize);
                outputFile.WriteUInt32((uint)MaxBlockSize);
                outputFile.WriteUInt32(LZMATag);
            }

            for (int i = 0; i < filesCount; i++)
            {
                if (filenamesIndex == i)
                {
                    continue;
                }
                if (filesList[i].filenamePath == null)
                {
                    throw new Exception("filename missing");
                }

                if (mainWindow != null)
                {
                    mainWindow.updateStatusLabel2("File " + (i + 1) + " of " + filesList.Count() + " - " + Path.GetFileName(filesList[i].filenamePath));
                }

                int    pos      = filesList[i].filenamePath.IndexOf("\\BIOGame\\DLC\\", StringComparison.OrdinalIgnoreCase);
                string filename = filesList[i].filenamePath.Substring(pos + ("\\BIOGame\\DLC\\").Length).Replace('/', '\\');
                string dir      = Path.GetDirectoryName(outPath);
                Directory.CreateDirectory(Path.GetDirectoryName(dir + filename));
                using (FileStream outputFile = new FileStream(dir + filename, FileMode.Create, FileAccess.Write))
                {
                    sfarFile.JumpTo(filesList[i].dataOffset);
                    if (filesList[i].compressedBlockSizesIndex == -1)
                    {
                        outputFile.WriteFromStream(sfarFile, filesList[i].uncomprSize);
                    }
                    else
                    {
                        List <byte[]> uncompressedBlockBuffers = new List <byte[]>();
                        List <byte[]> compressedBlockBuffers   = new List <byte[]>();
                        List <long>   blockBytesLeft           = new List <long>();
                        long          bytesLeft = filesList[i].uncomprSize;
                        for (int j = 0; j < filesList[i].numBlocks; j++)
                        {
                            blockBytesLeft.Add(bytesLeft);
                            int compressedBlockSize   = blockSizes[filesList[i].compressedBlockSizesIndex + j];
                            int uncompressedBlockSize = (int)Math.Min(bytesLeft, maxBlockSize);
                            if (compressedBlockSize == 0)
                            {
                                compressedBlockSize = (int)maxBlockSize;
                            }
                            compressedBlockBuffers.Add(sfarFile.ReadToBuffer(compressedBlockSize));
                            uncompressedBlockBuffers.Add(null);
                            bytesLeft -= uncompressedBlockSize;
                        }

                        Parallel.For(0, filesList[i].numBlocks, j =>
                        {
                            int compressedBlockSize   = blockSizes[filesList[i].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] = new SevenZipHelper.LZMA().Decompress(compressedBlockBuffers[(int)j], (uint)uncompressedBlockSize);
                                if (uncompressedBlockBuffers[(int)j].Length == 0)
                                {
                                    throw new Exception();
                                }
                            }
                        });

                        for (int j = 0; j < filesList[i].numBlocks; j++)
                        {
                            outputFile.WriteFromBuffer(uncompressedBlockBuffers[j]);
                        }
                    }
                }
            }
            sfarFile.Close();
            sfarFile.Dispose();
            sfarFile = null;
        }
        public void extract(string SFARfilename, string outPath, bool ipc, ref int currentProgress, int totalNumber)
        {
            if (!File.Exists(SFARfilename))
            {
                throw new Exception("filename missing");
            }

            byte[] buffer = File.ReadAllBytes(SFARfilename);

            File.Delete(SFARfilename);
            using (FileStream outputFile = new FileStream(SFARfilename, FileMode.Create, FileAccess.Write))
            {
                outputFile.WriteUInt32(SfarTag);
                outputFile.WriteUInt32(SfarVersion);
                outputFile.WriteUInt32(HeaderSize);
                outputFile.WriteUInt32(HeaderSize);
                outputFile.WriteUInt32(0);
                outputFile.WriteUInt32(HeaderSize);
                outputFile.WriteUInt32((uint)MaxBlockSize);
                outputFile.WriteUInt32(LZMATag);
            }

            using (MemoryStream stream = new MemoryStream(buffer))
            {
                loadHeader(stream);

                int lastProgress = -1;
                for (int i = 0; i < filesCount; i++, currentProgress++)
                {
                    if (filenamesIndex == i)
                    {
                        continue;
                    }
                    if (filesList[i].filenamePath == null)
                    {
                        throw new Exception("filename missing");
                    }

                    if (ipc)
                    {
                        int newProgress = (100 * currentProgress) / totalNumber;
                        if (lastProgress != newProgress)
                        {
                            Console.WriteLine("[IPC]TASK_PROGRESS " + newProgress);
                            Console.Out.Flush();
                            lastProgress = newProgress;
                        }
                    }

                    int    pos      = filesList[i].filenamePath.IndexOf("\\BIOGame\\DLC\\", StringComparison.OrdinalIgnoreCase);
                    string filename = filesList[i].filenamePath.Substring(pos + ("\\BIOGame\\DLC\\").Length).Replace('/', '\\');
                    string dir      = Path.GetDirectoryName(outPath);
                    Directory.CreateDirectory(Path.GetDirectoryName(dir + filename));
                    using (FileStream outputFile = new FileStream(dir + filename, FileMode.Create, FileAccess.Write))
                    {
                        stream.JumpTo(filesList[i].dataOffset);
                        if (filesList[i].compressedBlockSizesIndex == -1)
                        {
                            outputFile.WriteFromStream(stream, filesList[i].uncomprSize);
                        }
                        else
                        {
                            List <byte[]> uncompressedBlockBuffers = new List <byte[]>();
                            List <byte[]> compressedBlockBuffers   = new List <byte[]>();
                            List <long>   blockBytesLeft           = new List <long>();
                            long          bytesLeft = filesList[i].uncomprSize;
                            for (int j = 0; j < filesList[i].numBlocks; j++)
                            {
                                blockBytesLeft.Add(bytesLeft);
                                int compressedBlockSize   = blockSizes[filesList[i].compressedBlockSizesIndex + j];
                                int uncompressedBlockSize = (int)Math.Min(bytesLeft, maxBlockSize);
                                if (compressedBlockSize == 0)
                                {
                                    compressedBlockSize = (int)maxBlockSize;
                                }
                                compressedBlockBuffers.Add(stream.ReadToBuffer(compressedBlockSize));
                                uncompressedBlockBuffers.Add(null);
                                bytesLeft -= uncompressedBlockSize;
                            }

                            Parallel.For(0, filesList[i].numBlocks, j =>
                            {
                                int compressedBlockSize   = blockSizes[filesList[i].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] = new SevenZipHelper.LZMA().Decompress(compressedBlockBuffers[(int)j], (uint)uncompressedBlockSize);
                                    if (uncompressedBlockBuffers[(int)j].Length == 0)
                                    {
                                        throw new Exception();
                                    }
                                }
                            });

                            for (int j = 0; j < filesList[i].numBlocks; j++)
                            {
                                outputFile.WriteFromBuffer(uncompressedBlockBuffers[j]);
                            }
                        }
                    }
                }
            }
        }
Exemple #4
0
        public byte[] unpackFileEntry(string filename)
        {
            if (sfarFile == null)
            {
                throw new Exception();
            }

            string name = filename.Replace('\\', '/');

            byte[] fileHash = MD5.Create().ComputeHash(Encoding.ASCII.GetBytes(name.ToLowerInvariant()));
            int    index    = filesList.FindIndex(s => StructuralComparisons.StructuralEqualityComparer.Equals(s.filenameHash, fileHash));

            if (index == -1)
            {
                throw new Exception();
            }
            using (MemoryStream outputFile = new MemoryStream())
            {
                sfarFile.JumpTo(filesList[index].dataOffset);
                if (filesList[index].compressedBlockSizesIndex == -1)
                {
                    outputFile.WriteFromStream(sfarFile, filesList[index].uncomprSize);
                }
                else
                {
                    List <byte[]> uncompressedBlockBuffers = new List <byte[]>();
                    List <byte[]> compressedBlockBuffers   = new List <byte[]>();
                    List <long>   blockBytesLeft           = new List <long>();
                    long          bytesLeft = filesList[index].uncomprSize;
                    for (int j = 0; j < filesList[index].numBlocks; j++)
                    {
                        blockBytesLeft.Add(bytesLeft);
                        int compressedBlockSize   = blockSizes[filesList[index].compressedBlockSizesIndex + j];
                        int uncompressedBlockSize = (int)Math.Min(bytesLeft, maxBlockSize);
                        if (compressedBlockSize == 0)
                        {
                            compressedBlockSize = (int)maxBlockSize;
                        }
                        compressedBlockBuffers.Add(sfarFile.ReadToBuffer(compressedBlockSize));
                        uncompressedBlockBuffers.Add(null);
                        bytesLeft -= uncompressedBlockSize;
                    }

                    Parallel.For(0, filesList[index].numBlocks, j =>
                    {
                        int compressedBlockSize   = blockSizes[filesList[index].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] = new SevenZipHelper.LZMA().Decompress(compressedBlockBuffers[(int)j], (uint)uncompressedBlockSize);
                            if (uncompressedBlockBuffers[(int)j].Length == 0)
                            {
                                throw new Exception();
                            }
                        }
                    });

                    for (int j = 0; j < filesList[index].numBlocks; j++)
                    {
                        outputFile.WriteFromBuffer(uncompressedBlockBuffers[j]);
                    }
                }
                return(outputFile.ToArray());
            }
        }