Ejemplo n.º 1
0
        public void extractFile(string selectedFileName, string outputName)
        {
            sfarFile selectedFile = fileList.First(entry => entry.fileName == selectedFileName);

            using (FileStream input = File.OpenRead(fileName), output = File.Create(outputName))
            {
                DecompressEntry(selectedFile, input, output);
            }
        }
Ejemplo n.º 2
0
        private void getStructure(Stream input)
        {
            var magic = input.ReadValueU32(Endian.Little);

            if (magic != sfarHeader && // SFAR
                magic.Swap() != sfarHeader)
            {
                throw new FormatException("Not a valid sfar file.");
            }
            var endian = magic == sfarHeader ? Endian.Little : Endian.Big;

            var version = input.ReadValueU32(endian);

            if (version != 0x00010000)
            {
                throw new FormatException("Not supported version.");
            }

            dataOffset = input.ReadValueU32(endian);
            uint minDataOffset = dataOffset;

            entryOffset = input.ReadValueU32(endian);
            var fileTableCount = numOfFiles = input.ReadValueU32(endian);

            blockTableOffset       = input.ReadValueU32(endian);
            MaximumBlockSize       = input.ReadValueU32(endian);
            this.CompressionScheme = input.ReadValueEnum <CompressionScheme>(endian);

            if (entryOffset != 0x20)
            {
                throw new FormatException();
            }

            if (MaximumBlockSize != 0x010000)
            {
                throw new FormatException();
            }

            if (this.CompressionScheme != CompressionScheme.None &&
                this.CompressionScheme != CompressionScheme.Lzma &&
                this.CompressionScheme != CompressionScheme.Lzx)
            {
                throw new FormatException();
            }

            input.Seek(entryOffset, SeekOrigin.Begin);
            for (uint i = 0; i < fileTableCount; i++)
            {
                sfarFile entry = new sfarFile();
                entry.entryOffset       = input.Position;
                entry.nameHash          = input.ReadFileNameHash();
                entry.blockSizeIndex    = input.ReadValueS32(endian);
                entry.uncompressedSize  = input.ReadValueU32(endian);
                entry.uncompressedSize |= ((long)input.ReadValueU8()) << 32;
                totalUncSize           += entry.uncompressedSize;

                if (entry.blockSizeIndex == -1)
                {
                    entry.dataOffset     = new long[1];
                    entry.dataOffset[0]  = input.ReadValueU32(endian);
                    entry.dataOffset[0] |= ((long)input.ReadValueU8()) << 32;
                    totalComprSize      += entry.uncompressedSize;
                }
                else
                {
                    int numBlocks = (int)Math.Ceiling(entry.uncompressedSize / (double)MaximumBlockSize);
                    entry.dataOffset     = new long[numBlocks];
                    entry.blockSizeArray = new ushort[numBlocks];
                    entry.dataOffset[0]  = input.ReadValueU32(endian);
                    entry.dataOffset[0] |= ((long)input.ReadValueU8()) << 32;

                    long lastPosition = input.Position;
                    input.Seek(getBlockOffset(entry.blockSizeIndex, entryOffset, fileTableCount), 0);
                    entry.blockSizeArray[0] = input.ReadValueU16();

                    for (int j = 1; j < numBlocks; j++)
                    {
                        entry.blockSizeArray[j] = input.ReadValueU16();
                        entry.dataOffset[j]     = entry.dataOffset[j - 1] + entry.blockSizeArray[j];
                        totalComprSize         += entry.blockSizeArray[j];
                    }
                    input.Seek(lastPosition, 0);
                }
                fileList.Add(entry);
            }// end of foreach
        }
Ejemplo n.º 3
0
        public void DecompressEntry(sfarFile entry, Stream input, Stream output)
        {
#endif
            int count = 0;

            byte[] inputBlock;
            byte[] outputBlock = new byte[MaximumBlockSize];

            var left = entry.uncompressedSize;

            input.Seek(entry.dataOffset[0], SeekOrigin.Begin);

            if (entry.blockSizeIndex == -1)
            {
                output.WriteFromStream(input, entry.uncompressedSize);
            }
            else
            {
                while (left > 0)
                {
                    uint compressedBlockSize = entry.blockSizeArray[count];
                    if (compressedBlockSize == 0)
                    {
                        compressedBlockSize = MaximumBlockSize;
                    }

                    if (CompressionScheme == CompressionScheme.None)
                    {
                        output.WriteFromStream(input, compressedBlockSize);
                        left -= compressedBlockSize;
                    }
                    else if (CompressionScheme == CompressionScheme.Lzma)
                    {
                        if (compressedBlockSize == MaximumBlockSize ||
                            compressedBlockSize == left)
                        {
                            output.WriteFromStream(input, compressedBlockSize);
                            left -= compressedBlockSize;
                        }
                        else
                        {
                            var uncompressedBlockSize = (uint)Math.Min(left, MaximumBlockSize);

                            if (compressedBlockSize < 5)
                            {
                                throw new InvalidOperationException();
                            }

                            inputBlock = new byte[compressedBlockSize];

                            //var properties = input.ReadBytes(5);
                            //compressedBlockSize -= 5;

                            if (input.Read(inputBlock, 0, (int)compressedBlockSize)
                                != compressedBlockSize)
                            {
                                throw new EndOfStreamException();
                            }

                            uint actualUncompressedBlockSize = uncompressedBlockSize;
                            uint actualCompressedBlockSize   = compressedBlockSize;

                            /*var error = LZMA.Decompress(
                             *  outputBlock,
                             *  ref actualUncompressedBlockSize,
                             *  inputBlock,
                             *  ref actualCompressedBlockSize,
                             *  properties,
                             *  (uint)properties.Length);
                             *
                             * if (error != LZMA.ErrorCode.Ok ||
                             *  uncompressedBlockSize != actualUncompressedBlockSize ||
                             *  compressedBlockSize != actualCompressedBlockSize)
                             * {
                             *  throw new InvalidOperationException();
                             * }*/

                            outputBlock = SevenZipHelper.LZMA.Decompress(inputBlock, actualUncompressedBlockSize);
                            if (outputBlock.Length != actualUncompressedBlockSize)
                            {
                                throw new NotImplementedException();
                            }

                            output.Write(outputBlock, 0, (int)actualUncompressedBlockSize);
                            left -= uncompressedBlockSize;

#if (WITH_GUI)
                            if (BWork != null)
                            {
                                int perc = (int)(count / (float)entry.blockSizeArray.Length * 100);
                                if (perc > maxPerc)
                                {
                                    maxPerc = perc;
                                    BWork.ReportProgress(perc);
                                }
                            }
#endif
                        }
                    }
                    else
                    {
                        throw new NotImplementedException();
                    }
                    count++;
                }
            }
        }// end of DecompressEntry
Ejemplo n.º 4
0
 public void DecompressEntry(sfarFile entry, Stream input, Stream output, BackgroundWorker BWork = null)
 {
     int maxPerc = 0;
Ejemplo n.º 5
0
 public static void DecompressEntry(sfarFile entry, Stream input, Stream output, CompressionScheme cScheme, BackgroundWorker worker = null)
 {
     int highPerc = 0;
     int count    = 0;
Ejemplo n.º 6
0
            //int highPerc = 0;
#else
        public void Execute(string outputFile)
        {
#endif
            var inputPath = dlcBase.fileName;

            if (!File.Exists(inputPath))
            {
                throw new FileNotFoundException("Error: the input file doesn't exists");
            }

            /*string filePathToReplace = selectedFile;
             * string fileToReplace = Path.GetFileName(filePathToReplace);
             * FileNameHash fileToReplaceHash = new FileNameHash();*/

            string outputFileName = Path.GetFileNameWithoutExtension(inputPath);

            int inPointerBlockSize      = 0;
            int outPointerEntry         = 0x20;
            int outPointerEntryFileList = 0;
            int outPointerBlockSize     = 0;
            int outPointerData          = 0;

            int blocksToRemove = 0;
            int blocksToAdd    = 0;

            using (FileStream input = File.OpenRead(inputPath),
                   output = File.OpenWrite(outputFile))
            {
                string dlcFileList     = "";
                int    outNumOfEntries = 0;
                //recreating the file list
                foreach (var kvp in listComplete)
                {
                    if (kvp.Value != action.delete)
                    {
                        outNumOfEntries++;
                        if (kvp.Key == DLCBase.fileListHash)
                        {
                            continue;
                        }
                        switch (kvp.Value)
                        {
                        case action.copy:
                        case action.replace:
                            dlcFileList += dlcBase.fileList[kvp.Key].fileName + Environment.NewLine;
                            break;

                        case action.add:
                            dlcFileList += listAdd[kvp.Key].fileName + Environment.NewLine;
                            break;
                        }
                    }
                }
                blocksToRemove += dlcBase.fileList[DLCBase.fileListHash].blockSizeArray.Length;
                blocksToAdd    += (int)Math.Ceiling(dlcFileList.Length / (double)DLCBase.MaximumBlockSize);

                foreach (var kvp in listAdd)
                {
                    string fPath = kvp.Value.filePath;
                    if ((Path.GetExtension(fPath) != ".bik" &&
                         Path.GetExtension(fPath) != ".afc"))
                    {
                        blocksToAdd += (int)Math.Ceiling(DLCPack.Getsize(kvp.Value.filePath) / (double)DLCBase.MaximumBlockSize);
                    }
                }

                foreach (var kvp in listReplace)
                {
                    if (dlcBase.fileList[kvp.Key].blockSizeIndex != -1)
                    {
                        blocksToRemove += dlcBase.fileList[kvp.Key].blockSizeArray.Length;
                        blocksToAdd    += (int)Math.Ceiling(DLCPack.Getsize(kvp.Value) / (double)DLCBase.MaximumBlockSize);
                    }
                }

                foreach (var kvp in listDelete)
                {
                    if (dlcBase.fileList[kvp.Key].blockSizeIndex != -1)
                    {
                        blocksToRemove += dlcBase.fileList[kvp.Key].blockSizeArray.Length;
                    }
                }

                var inputBlock  = new byte[DLCBase.MaximumBlockSize];
                var outputBlock = new byte[DLCBase.MaximumBlockSize];
                //writing header of new sfar file
                input.Seek(0, 0);
                input.Read(inputBlock, 0, 32);
                output.Write(inputBlock, 0, 32);

                //getting initial blocks and data offsets
                inPointerBlockSize  = 0x20 + (dlcBase.fileList.Count * 0x1E);
                outPointerBlockSize = 0x20 + outNumOfEntries * 0x1E;
                input.Seek(8, 0);
                int inDataOffset  = input.ReadValueS32();
                int outBlockCount = ((inDataOffset - inPointerBlockSize) / 2) - blocksToRemove + blocksToAdd;
                outPointerData = outPointerBlockSize + (outBlockCount * 2);

                //writing new header's values
                output.Seek(8, 0);
                output.WriteValueS32(outPointerData);

                output.Seek(16, 0);
                output.WriteValueS32(outNumOfEntries);

                output.Seek(20, 0);
                output.WriteValueS32(outPointerBlockSize);

                if (verbose)
                {
                    Console.WriteLine("num entries: {0}", outNumOfEntries);
                    Console.WriteLine("data offset: {0:X8}", inDataOffset);
                    Console.WriteLine("blocks to remove: {0}", blocksToRemove);
                    Console.WriteLine("blocks to add: {0}", blocksToAdd);
                    Console.WriteLine("old block offset: {0:X8}", inPointerBlockSize);
                    Console.WriteLine("new block offset: {0:X8}", outPointerBlockSize);
                    Console.WriteLine("old block count: {0}", (inDataOffset - inPointerBlockSize) / 2);
                    Console.WriteLine("new block count: {0}", outBlockCount);
                    Console.WriteLine("pointer data: {0:X8}\n", outPointerData);
                }

                int numBlocks;
                int outDataOffset;
                int blockIndexCounter = 0;
                int outBlockIndex     = 0;
                int fileSize          = 0;

                int outInitialDataOffset  = outPointerData;
                int outInitialBlockOffset = outPointerBlockSize;

                foreach (var kvp in listComplete)
                {
                    count++;

                    if (kvp.Value == action.delete)
                    {
                        continue;
                    }

                    if (kvp.Key == DLCBase.fileListHash)
                    {
                        //Console.WriteLine("File List Found at {0:X8}", outPointerEntry);
                        outPointerEntryFileList = outPointerEntry;
                        outPointerEntry        += 0x1E;
                        continue;
                    }

                    sfarFile     entry;
                    FileNameHash hashEntry = kvp.Key;

                    if (kvp.Value == action.add)
                    {
                        string fPath = listAdd[kvp.Key].filePath;
                        entry            = new sfarFile();
                        entry.nameHash   = kvp.Key;
                        entry.dataOffset = new long[1];
                        fileSize         = (int)DLCPack.Getsize(fPath);
                        if ((Path.GetExtension(fPath) == ".bik" ||
                             Path.GetExtension(fPath) == ".afc"))
                        {
                            entry.blockSizeIndex = -1;
                        }
                    }
                    else
                    {
                        entry    = dlcBase.fileList[kvp.Key];
                        fileSize = (int)entry.uncompressedSize;
                    }

                    outDataOffset = outPointerData;
                    outBlockIndex = blockIndexCounter;

                    /*#if (WITH_GUI)
                     *                  int perc = (int)Math.Ceiling((float)count++ / (float)listComplete.Count * 100);
                     *                  if (perc > highPerc)
                     *                  {
                     *                      highPerc = perc;
                     *                      if (perc > 100)
                     *                          perc = 100;
                     *                      worker.ReportProgress(perc);
                     *                  }
                     #endif*/

                    switch (kvp.Value)
                    {
                    case action.copy:
                        if (worker != null)
                        {
                            worker.ReportProgress(0, count + "/" + listComplete.Count + ": Copying " + Path.GetFileName(entry.fileName));
                        }
                        if (entry.blockSizeIndex == -1)
                        {
                            inDataOffset = (int)entry.dataOffset[0];
                            input.Seek(inDataOffset, 0);
                            inputBlock = new byte[fileSize];
                            input.Read(inputBlock, 0, fileSize);

                            output.Seek(outPointerData, 0);
                            output.Write(inputBlock, 0, fileSize);
                            outPointerData += fileSize;

                            outBlockIndex = entry.blockSizeIndex;
                        }
                        else
                        {
                            numBlocks    = (int)Math.Ceiling(fileSize / (double)DLCBase.MaximumBlockSize);
                            inDataOffset = (int)entry.dataOffset[0];
                            for (int i = 0; i < numBlocks; i++)
                            {
                                uint blockSize = entry.blockSizeArray[i];
                                if ((ushort)blockSize != entry.blockSizeArray[i])
                                {
                                    throw new Exception("different blocksizes");
                                }
                                blockSize = blockSize == 0 ? DLCBase.MaximumBlockSize : blockSize;

                                inputBlock = new byte[blockSize];
                                input.Seek(inDataOffset, 0);
                                input.Read(inputBlock, 0, (int)blockSize);
                                inDataOffset += (int)blockSize;

                                output.Seek(outPointerBlockSize, 0);
                                if (blockSize == DLCBase.MaximumBlockSize)
                                {
                                    output.WriteValueU16(0);
                                }
                                else
                                {
                                    output.WriteValueU16((ushort)blockSize);
                                }
                                if (outPointerBlockSize > outInitialDataOffset)
                                {
                                    throw new Exception("Block index offset values out of range,\n  last block: " + blockIndexCounter + "\n  Pointer Block: " + outPointerBlockSize.ToString("X8") + "\n  Data Offset: " + outInitialDataOffset.ToString("X8"));
                                }
                                outPointerBlockSize += 2;

                                output.Seek(outPointerData, 0);
                                output.Write(inputBlock, 0, (int)blockSize);
                                if (output.Position - outPointerData != blockSize)
                                {
                                    Console.WriteLine("  diff position: {0}, blocksize: {1}", output.Position - outPointerData, blockSize);
                                    throw new Exception("error writing file");
                                }
                                outPointerData += (int)blockSize;
                            }
                            blockIndexCounter += numBlocks;
                        }
                        break;

                    case action.add:
                    case action.replace:
                        string selectedFile;
                        if (kvp.Value == action.replace)
                        {
                            selectedFile = listReplace[kvp.Key];
                            if (worker != null)
                            {
                                worker.ReportProgress(0, count + "/" + listComplete.Count + ": Replacing " + Path.GetFileName(selectedFile));
                            }
                        }
                        else
                        {
                            selectedFile = listAdd[kvp.Key].filePath;
                            if (worker != null)
                            {
                                worker.ReportProgress(0, count + "/" + listComplete.Count + ": Adding " + Path.GetFileName(selectedFile));
                            }
                        }
                        output.Seek(outPointerBlockSize, 0);
                        //compressing the replacing file
                        ushort[] blockSizeArray;

                        using (FileStream streamFile = new FileStream(selectedFile, FileMode.Open, FileAccess.Read))
                        {
                            fileSize = (int)streamFile.Length;
                            if ((Path.GetExtension(selectedFile) == ".bik" || Path.GetExtension(selectedFile) == ".afc") && entry.blockSizeIndex == -1)
                            {
                                outBlockIndex = -1;
                                output.Seek(outPointerData, SeekOrigin.Begin);
                                output.WriteFromStream(streamFile, streamFile.Length);
                                outPointerData += (int)streamFile.Length;
                            }
                            else
                            {
                                byte[][] comprArr;
                                DLCPack.CompressFile(streamFile, out blockSizeArray, out comprArr, Threads);

                                for (int i = 0; i < blockSizeArray.Length; i++)
                                {
                                    output.WriteValueU16(blockSizeArray[i]);
                                }
                                outPointerBlockSize += (blockSizeArray.Length * 2);
                                blockIndexCounter   += blockSizeArray.Length;

                                output.Seek(outPointerData, SeekOrigin.Begin);
                                int totallength = 0;
                                for (int i = 0; i < comprArr.Length; i++)
                                {
                                    output.WriteBytes(comprArr[i]);
                                    totallength += comprArr[i].Length;
                                }
                                //outPointerData += (int)streamFile.Length;
                                outPointerData += totallength;
                            }
                        }
                        #region blah di blah

                        /*
                         * FileStream streamFile = File.OpenRead(selectedFile);
                         * if ((Path.GetExtension(selectedFile) == ".bik" ||
                         *   Path.GetExtension(selectedFile) == ".afc") &&
                         *  entry.blockSizeIndex == -1)
                         * {
                         *  streamFile.CopyTo(encStream);
                         *  outBlockIndex = -1;
                         * }
                         * else
                         * {
                         *  //DLCPack.CompressFile(streamFile, out blockSizeArray, encStream, worker);
                         *  byte[][] comprArr;
                         *  DLCPack.CompressFile(streamFile, out blockSizeArray, out comprArr);
                         *
                         *  for (int i = 0; i < blockSizeArray.Length; i++)
                         *  {
                         *      output.WriteValueU16(blockSizeArray[i]);
                         *  }
                         *  outPointerBlockSize += (blockSizeArray.Length * 2);
                         *  blockIndexCounter += blockSizeArray.Length;
                         * }
                         * output.Seek((long)outPointerData, 0);
                         * encStream.WriteTo(output);
                         * outPointerData += (int)encStream.Length;
                         *
                         * fileSize = (int)streamFile.Length;
                         * streamFile.Close();
                         */
                        #endregion
                        break;
                    }// end switch

                    if (worker != null)
                    {
                        worker.ReportProgress(100);
                    }

                    output.Seek(outPointerEntry, 0);
                    output.WriteValueU32(hashEntry.A.Swap());
                    output.WriteValueU32(hashEntry.B.Swap());
                    output.WriteValueU32(hashEntry.C.Swap());
                    output.WriteValueU32(hashEntry.D.Swap());
                    output.WriteValueS32(outBlockIndex);
                    output.WriteValueS32(fileSize);
                    output.WriteValueU8(0);
                    output.WriteValueS32(outDataOffset);
                    output.WriteValueU8(0);
                    outPointerEntry += 0x1E;
                    if (outPointerEntry > outInitialBlockOffset)
                    {
                        throw new Exception("Entry index offset values out of range");
                    }
                }// end of foreach

                //writing the file list entry, blocksizes & data
                outDataOffset = outPointerData;
                outBlockIndex = blockIndexCounter;
                {
                    MemoryStream streamRead = new MemoryStream(ASCIIEncoding.Default.GetBytes(dlcFileList));
                    ushort[]     blockSizeArray;
                    MemoryStream encStream = new MemoryStream();
                    DLCPack.CompressFile(streamRead, out blockSizeArray, encStream);

                    output.Seek(outPointerBlockSize, 0);
                    for (int i = 0; i < blockSizeArray.Length; i++)
                    {
                        output.WriteValueU16(blockSizeArray[i]);
                    }
                    outPointerBlockSize += (blockSizeArray.Length * 2);
                    blockIndexCounter   += blockSizeArray.Length;

                    output.Seek(outPointerData, 0);
                    encStream.WriteTo(output);
                    outPointerData += (int)encStream.Length;

                    fileSize = (int)streamRead.Length;

                    output.Seek(outPointerEntryFileList, 0);
                    output.WriteValueU32(DLCBase.fileListHash.A.Swap());
                    output.WriteValueU32(DLCBase.fileListHash.B.Swap());
                    output.WriteValueU32(DLCBase.fileListHash.C.Swap());
                    output.WriteValueU32(DLCBase.fileListHash.D.Swap());
                    output.WriteValueS32(outBlockIndex);
                    output.WriteValueS32(fileSize);
                    output.WriteValueU8(0x00);
                    output.WriteValueS32(outDataOffset);
                    output.WriteValueU8(0x00);
                    outPointerEntry = (int)output.Position;
                }
            }// end of using...
        }