public void Save(FpmfArchive archive, string directoryPath)
        {
            DirectoryInfo directory = new DirectoryInfo(directoryPath);

            if (!directory.Exists)
            {
                throw new FileNotFoundException($"Directory: {directoryPath} not found.");
            }


            string relativeArchiveDir = archive.DatPath
                                        .Replace("/%08x.dat", "")
                                        .Replace("./", "")
                                        .Replace('/', Path.DirectorySeparatorChar);

            string rootPath = Path.Combine(directory.FullName, relativeArchiveDir);

            List <FpmfArchiveFile> files = archive.GetFiles();

            foreach (FpmfArchiveFile file in files)
            {
                string relativeFilePath = file.FilePath
                                          .Replace(".\\", "")
                                          .Replace('\\', Path.DirectorySeparatorChar);
                string filePath = Path.Combine(rootPath, relativeFilePath);

                FileInfo fileInfo = new FileInfo(filePath);
                if (!Directory.Exists(fileInfo.DirectoryName))
                {
                    Directory.CreateDirectory(fileInfo.DirectoryName);
                }

                File.WriteAllBytes(filePath, file.Data);
            }
        }
        public void Header(string hedFilePath, string outPath)
        {
            if (outPath.LastIndexOf("\\") != outPath.Length - 1)
            {
                outPath += "\\";
            }

            string type = hedFilePath.Substring(hedFilePath.LastIndexOf("\\") + 1,
                                                hedFilePath.LastIndexOf(".") - hedFilePath.LastIndexOf("\\") - 1).Replace("\\data", "");
            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);
            BinaryWriter tmpwriter = new BinaryWriter(File.Open(outPath + type + "_header.bin", FileMode.Create));

            tmpwriter.Write(magicBytes);
            tmpwriter.Write(archive.size);
            tmpwriter.Write(unknown0);
            tmpwriter.Write(hedBuffer.GetAllBytes());
            tmpwriter.Flush();
            tmpwriter.Close();
        }
        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);
        }
        private void SavePack(FpmfArchive archive, string inPath, string outPath, string archiveName)
        {
            Directory.CreateDirectory(outPath);
            IBuffer fileBuff   = new StreamBuffer();
            IBuffer headerBuff = new StreamBuffer();
            List <FpmfArchiveFile> archiveFiles = archive.GetFiles();

            foreach (FpmfArchiveFile archiveFile in archiveFiles)
            {
                fileBuff.WriteByte((byte)archiveFile.directoryPathSize);
                fileBuff.WriteCString(archiveFile.directoryPath);
                fileBuff.Position = fileBuff.Position - 1;
                fileBuff.WriteByte((byte)archiveFile.filePathSize);
                fileBuff.WriteCString(archiveFile.filePath);
                fileBuff.Position = fileBuff.Position - 1;
                fileBuff.WriteUInt32(archiveFile.datNumber);
                fileBuff.WriteUInt32(archiveFile.offset);
                fileBuff.WriteUInt32(archiveFile.size);
                fileBuff.WriteUInt32(archiveFile.unknown0);
                fileBuff.WriteUInt32(archiveFile.unknown1);
            }

            headerBuff.WriteBytes(_MagicBytes);
            headerBuff.WriteInt32(0);
            headerBuff.WriteUInt32(archive.unknown0);
            headerBuff.WriteUInt32(archive.unknown1);
            headerBuff.WriteUInt32(archive.unknown2);
            headerBuff.WriteByte(archive.unknown3);
            headerBuff.WriteByte(archive.unknown4);
            headerBuff.WriteUInt32(archive.unknown5);
            headerBuff.WriteInt32(archive.datPath.Length + 9);
            headerBuff.WriteByte((byte)archive.datPath.Length);
            headerBuff.WriteCString(archive.datPath);
            headerBuff.Position = headerBuff.Position - 1;
            uint type = 0;

            switch (archiveName)
            {
            case "script":
            case "settings":
            case "item":
            case "interface":
                type = 1;
                break;

            case "help_end":
                type = 2;
                break;
            }

            headerBuff.WriteUInt32(type);
            headerBuff.WriteUInt32(archive.unknown8);
            headerBuff.WriteUInt32(archive.unknown9);
            headerBuff.WriteUInt32(archive.unknown10);
            headerBuff.WriteInt32(archive.key.Length);
            headerBuff.WriteBytes(archive.key);
            headerBuff.WriteUInt32(archive.unknown11);
            headerBuff.WriteInt32(fileBuff.Size + 4);
            headerBuff.WriteUInt32(archive.numFiles);
            headerBuff.WriteBytes(fileBuff.GetAllBytes());

            headerBuff = EncryptHed(headerBuff);

            string       hedPath      = outPath.Substring(0, outPath.LastIndexOf("\\")) + ".hed";
            BinaryWriter headerWriter = new BinaryWriter(File.Open(hedPath, FileMode.Create));

            headerBuff.Position = 4;
            headerBuff.WriteInt32(headerBuff.Size - 12);
            headerWriter.Write(headerBuff.GetAllBytes(), 0, headerBuff.Size);
            headerWriter.Flush();
            headerWriter.Close();

            BinaryWriter datWriter = new BinaryWriter(File.Open(outPath + "\\" + "00000000.dat", FileMode.Create));
            IBuffer      outBuff   = new StreamBuffer();

            foreach (FpmfArchiveFile archiveFile in archiveFiles)
            {
                string  inputFile     = inPath + "\\" + archiveName + archiveFile.filePath.Substring(1);
                IBuffer datFileReader = new StreamBuffer(inputFile);
                datFileReader = EncryptDat(datFileReader, archive.key);
                outBuff.WriteBytes(datFileReader.GetAllBytes());
            }

            datWriter.Write(outBuff.GetAllBytes(), 0, outBuff.Size);
            datWriter.Flush();
            datWriter.Close();
        }
        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, 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);
        }