public void Pack(string inPath, string outPath, string archiveName, string archivePath = "")
        {
            uint   fileTime = 0x506fa78e;
            string dirPath  = archivePath;

            if (archivePath.Length > 0)
            {
                if (!dirPath.StartsWith("\\"))
                {
                    dirPath     = "\\" + dirPath;
                    archivePath = "\\" + archivePath;
                }

                if (!dirPath.EndsWith("\\"))
                {
                    dirPath     = dirPath + "\\";
                    archivePath = archivePath + "\\";
                }

                dirPath = ".\\" + archiveName + dirPath + "%08x.dat";
            }
            else
            {
                dirPath = ".\\" + archiveName + "\\" + "%08x.dat";
            }

            dirPath = dirPath.Replace("\\", "/");
            FpmfArchive archive = new FpmfArchive();

            if (inPath.EndsWith("\\"))
            {
                inPath = inPath.Substring(0, inPath.Length - 1);
            }

            uint   currentOffset   = 0;
            string baseArchivePath = inPath + "\\" + archiveName + archivePath;

            string[] inFiles = Directory.GetFiles(baseArchivePath, "*", SearchOption.AllDirectories);
            archive.numFiles   = (uint)inFiles.Length;
            archive.datPath    = dirPath;
            archive.datPathLen = dirPath.Length;

            foreach (string inFile in inFiles)
            {
                IBuffer         inReader = new StreamBuffer(inFile);
                FpmfArchiveFile datFile  = new FpmfArchiveFile();
                datFile.size      = (uint)inReader.Size;
                datFile.datNumber = 0;
                datFile.offset    = currentOffset;
                IBuffer encryptedBuff = EncryptDat(inReader, archive.key);
                datFile.data              = encryptedBuff.GetAllBytes();
                datFile.filePath          = inFile.Replace(inPath + "\\" + archiveName, ".");
                datFile.filePathSize      = (uint)datFile.filePath.Length;
                datFile.directoryPath     = ".\\" + archiveName + "\\";
                datFile.directoryPathSize = (uint)datFile.directoryPath.Length;
                datFile.unknown0          = fileTime;
                datFile.unknown1          = 0;
                archive.AddFile(datFile);
                currentOffset += datFile.size;
            }

            if (archivePath.Length > 0)
            {
                outPath = outPath + "\\" + archiveName + archivePath;
            }
            else
            {
                outPath = outPath + "\\" + archiveName + "\\";
            }

            SavePack(archive, inPath, outPath, archiveName);
        }
        public FpmfArchive Open(string hedFilePath)
        {
            FileInfo hedFile = new FileInfo(hedFilePath);

            if (!hedFile.Exists)
            {
                throw new FileNotFoundException($"File: {hedFilePath} not found.");
            }

            IBuffer hedBuffer = new StreamBuffer(hedFile.FullName);

            if (hedBuffer.Size < 12)
            {
                throw new Exception("File to small");
            }

            hedBuffer.SetPositionStart();
            byte[] magicBytes = hedBuffer.ReadBytes(4);
            for (int i = 0; i < 4; i++)
            {
                if (magicBytes[i] != MagicBytes[i])
                {
                    throw new Exception("Invalid File");
                }
            }

            FpmfArchive archive = new FpmfArchive();

            archive.Size = hedBuffer.ReadUInt32();
            uint unknown0 = hedBuffer.ReadUInt32();

            hedBuffer = DecryptHed(hedBuffer);
            hedBuffer.SetPositionStart();

            uint unknown1 = hedBuffer.ReadUInt32();
            uint unknown2 = hedBuffer.ReadUInt32();
            byte unknown3 = hedBuffer.ReadByte();
            byte unknown4 = hedBuffer.ReadByte();
            uint unknown5 = hedBuffer.ReadUInt32();
            uint unknown6 = hedBuffer.ReadUInt32();
            int  strLen   = hedBuffer.ReadByte();

            archive.DatPath = hedBuffer.ReadString(strLen);
            uint unknown7  = hedBuffer.ReadUInt32();
            uint unknown8  = hedBuffer.ReadUInt32();
            uint unknown9  = hedBuffer.ReadUInt32();
            uint unknown10 = hedBuffer.ReadUInt32();
            uint keyLen    = hedBuffer.ReadUInt32();

            archive.Key = hedBuffer.ReadBytes((int)keyLen);
            uint unknown11 = hedBuffer.ReadUInt32();
            uint unknown12 = hedBuffer.ReadUInt32();
            uint numFiles  = hedBuffer.ReadUInt32();

            string relativeArchiveDir = archive.DatPath
                                        .Replace("/%08x.dat", "")
                                        .Replace("./", "")
                                        .Replace('/', Path.DirectorySeparatorChar);
            string        hedPath       = hedFile.FullName.Replace(".hed", "");
            string        rootPath      = hedPath.Replace(relativeArchiveDir, "");
            DirectoryInfo rootDirectory = new DirectoryInfo(rootPath);

            if (!rootDirectory.Exists)
            {
                throw new FileNotFoundException(
                          $"Could not determinate root path. (Rel:{relativeArchiveDir} Hed:{hedPath}  Root:{rootPath}");
            }

            _logger.Info($"Using Root:{rootPath}");

            Dictionary <uint, IBuffer> datBufferPool = new Dictionary <uint, IBuffer>();

            for (int i = 0; i < numFiles; i++)
            {
                FpmfArchiveFile archiveFile = new FpmfArchiveFile();
                strLen = hedBuffer.ReadByte();
                archiveFile.DirectoryPath = hedBuffer.ReadString(strLen);
                strLen = hedBuffer.ReadByte();
                archiveFile.FilePath  = hedBuffer.ReadString(strLen);
                archiveFile.DatNumber = hedBuffer.ReadUInt32();
                archiveFile.Offset    = hedBuffer.ReadUInt32();
                archiveFile.Size      = hedBuffer.ReadUInt32();
                uint unknown13 = hedBuffer.ReadUInt32();
                uint unknown14 = hedBuffer.ReadUInt32();

                _logger.Info($"Processing: {archiveFile.FilePath}");

                IBuffer datBuffer;
                if (datBufferPool.ContainsKey(archiveFile.DatNumber))
                {
                    datBuffer = datBufferPool[archiveFile.DatNumber];
                }
                else
                {
                    string datFileName = archive.DatPath
                                         .Replace("%08x", $"{archiveFile.DatNumber:X8}")
                                         .Replace("./", "")
                                         .Replace('/', Path.DirectorySeparatorChar);
                    string   datFilePath = Path.Combine(rootDirectory.FullName, datFileName);
                    FileInfo datFile     = new FileInfo(datFilePath);
                    if (!datFile.Exists)
                    {
                        throw new FileNotFoundException($"File: {datFilePath} not found.");
                    }

                    datBuffer = new StreamBuffer(datFile.FullName);
                    datBufferPool.Add(archiveFile.DatNumber, datBuffer);
                }

                IBuffer decrypted = DecryptDat(datBuffer, archiveFile.Offset, archiveFile.Size, archive.Key);
                archiveFile.Data = decrypted.GetAllBytes();

                archive.AddFile(archiveFile);
            }

            return(archive);
        }
        public FpmfArchive Open(string hedFilePath, string outPath = "")
        {
            FileInfo hedFile = new FileInfo(hedFilePath);

            if (!hedFile.Exists)
            {
                throw new FileNotFoundException($"File: {hedFilePath} not found.");
            }

            IBuffer hedBuffer = new StreamBuffer(hedFile.FullName);

            if (hedBuffer.Size < 12)
            {
                throw new Exception("File to small");
            }

            hedBuffer.SetPositionStart();
            byte[] magicBytes = hedBuffer.ReadBytes(4);
            for (int i = 0; i < 4; i++)
            {
                if (magicBytes[i] != MagicBytes[i])
                {
                    throw new Exception("Invalid File");
                }
            }

            FpmfArchive archive = new FpmfArchive();

            archive.Size = hedBuffer.ReadUInt32();
            uint unknown0 = hedBuffer.ReadUInt32();

            //BinaryWriter tmpwriter = new BinaryWriter(File.Open("C:\\Users\\kevin\\Desktop\\GameFilesSteamTest\\script_encrypted.hed", FileMode.Create));
            //tmpwriter.Write(hedBuffer.GetAllBytes());
            //tmpwriter.Flush();
            //tmpwriter.Close();

            hedBuffer = DecryptHed(hedBuffer);
            //tmpwriter = new BinaryWriter(File.Open("C:\\Users\\kevin\\Desktop\\GameFilesSteamTest\\script_unencrypted.hed", FileMode.Create));
            //tmpwriter.Write(magicBytes);
            //tmpwriter.Write(archive.Size);
            //tmpwriter.Write(unknown0);
            //tmpwriter.Write(hedBuffer.GetAllBytes());
            //tmpwriter.Flush();
            //tmpwriter.Close();

            hedBuffer.SetPositionStart();
            uint unknown1 = hedBuffer.ReadUInt32();
            uint unknown2 = hedBuffer.ReadUInt32();
            byte unknown3 = hedBuffer.ReadByte();
            byte unknown4 = hedBuffer.ReadByte();
            uint unknown5 = hedBuffer.ReadUInt32();
            uint unknown6 = hedBuffer.ReadUInt32();
            int  strLen   = hedBuffer.ReadByte();

            archive.DatPath = hedBuffer.ReadString(strLen);
            uint unknown7  = hedBuffer.ReadUInt32();
            uint unknown8  = hedBuffer.ReadUInt32();
            uint unknown9  = hedBuffer.ReadUInt32();
            uint unknown10 = hedBuffer.ReadUInt32();
            uint keyLen    = hedBuffer.ReadUInt32();

            archive.Key = hedBuffer.ReadBytes((int)keyLen);
            uint unknown11 = hedBuffer.ReadUInt32();
            uint unknown12 = hedBuffer.ReadUInt32();
            uint numFiles  = hedBuffer.ReadUInt32();

            //headerBuff.SetPositionStart();
            string relativeArchiveDir = archive.DatPath
                                        .Replace("/%08x.dat", "")
                                        .Replace("./", "")
                                        .Replace('/', Path.DirectorySeparatorChar);
            string        hedPath       = hedFile.FullName.Replace(".hed", "");
            string        hedName       = hedPath.Substring(hedPath.LastIndexOf("\\") + 1);
            string        rootPath      = hedPath.Replace(relativeArchiveDir, "");
            DirectoryInfo rootDirectory = new DirectoryInfo(rootPath);

            if (!rootDirectory.Exists)
            {
                throw new FileNotFoundException(
                          $"Could not determinate root path. (Rel:{relativeArchiveDir} Hed:{hedPath}  Root:{rootPath}");
            }

            Logger.Info($"Using Root:{rootPath}");
            Dictionary <uint, IBuffer> datBufferPool = new Dictionary <uint, IBuffer>();

            for (int i = 0; i < numFiles; i++)
            {
                FpmfArchiveFile archiveFile = new FpmfArchiveFile();
                strLen = hedBuffer.ReadByte();
                archiveFile.DirectoryPath = hedBuffer.ReadString(strLen);
                strLen = hedBuffer.ReadByte();
                archiveFile.FilePath  = hedBuffer.ReadString(strLen);
                archiveFile.DatNumber = hedBuffer.ReadUInt32();
                archiveFile.Offset    = hedBuffer.ReadUInt32();
                archiveFile.Size      = hedBuffer.ReadUInt32();
                uint unknown13 = hedBuffer.ReadUInt32();
                uint unknown14 = hedBuffer.ReadUInt32();

                uint unknown15 = addFileName(archiveFile.FilePath);
                uint unknown16 = addFileName(archiveFile.DirectoryPath);
                Logger.Info($"Processing: {archiveFile.FilePath}");

                IBuffer datBuffer;
                if (datBufferPool.ContainsKey(archiveFile.DatNumber))
                {
                    datBuffer = datBufferPool[archiveFile.DatNumber];
                }
                else
                {
                    string datFileName = archive.DatPath
                                         .Replace("%08x", $"{archiveFile.DatNumber:X8}")
                                         .Replace("./", "")
                                         .Replace('/', Path.DirectorySeparatorChar);
                    string   datFilePath = Path.Combine(rootDirectory.FullName, datFileName);
                    FileInfo datFile     = new FileInfo(datFilePath);
                    if (!datFile.Exists)
                    {
                        throw new FileNotFoundException($"File: {datFilePath} not found.");
                    }

                    datBuffer = new StreamBuffer(datFile.FullName);
                    datBufferPool.Add(archiveFile.DatNumber, datBuffer);
                }

                IBuffer decrypted = DecryptDat(datBuffer, archiveFile.Offset, archiveFile.Size, archive.Key);
                if (archiveFile.FilePath.Contains("\\item.csv"))
                {
                    decrypted = OpenWoItm(decrypted);
                }

                archiveFile.Data = decrypted.GetAllBytes();

                archive.AddFile(archiveFile);
            }

            return(archive);
        }