Example #1
0
 private static void UnpackRegulationFile(Options options)
 {
     using (FileStream inputStream = new FileStream(options.InputPath, FileMode.Open, FileAccess.Read))
     {
         EncFile encryptedFile            = EncFile.ReadEncFile(inputStream, DecryptionKeys.RegulationFileKey);
         DcxFile compressedRegulationFile = DcxFile.Read(encryptedFile.Data);
         UnpackBndFile(new MemoryStream(compressedRegulationFile.Decompress()), options.OutputPath);
     }
 }
Example #2
0
        private static void UnpackBdf4File(Options options)
        {
            string bdfDirectoryPath = Path.GetDirectoryName(options.InputPath);
            string bhf4Extension    = Path.GetExtension(options.InputPath).Replace("bdt", "bhd");
            string bhf4FilePath     = Path.Combine(bdfDirectoryPath, Path.GetFileNameWithoutExtension(options.InputPath) + bhf4Extension);

            if (!File.Exists(bhf4FilePath))
            {
                // HACK: Adding 132 to a hash of a text that ends with XXX.bdt will give you the hash of XXX.bhd.
                string[] split = Path.GetFileNameWithoutExtension(options.InputPath).Split('_');
                uint     hash;
                if (uint.TryParse(split[0], out hash))
                {
                    hash        += 132;
                    split[0]     = hash.ToString("D10");
                    bhf4FilePath = Path.Combine(bdfDirectoryPath, string.Join("_", split) + ".bhd");
                }
            }

            using (Bdf4FileStream bdf4InputStream = Bdf4FileStream.OpenFile(options.InputPath, FileMode.Open, FileAccess.Read))
            {
                Bhf4File bhf4File = Bhf4File.OpenBhf4File(bhf4FilePath);
                foreach (var entry in bhf4File.Entries)
                {
                    MemoryStream data = bdf4InputStream.Read(entry.FileOffset, entry.FileSize);

                    string fileName      = entry.FileName;
                    string fileExtension = Path.GetExtension(fileName);
                    if (fileExtension == ".dcx")
                    {
                        DcxFile dcxFile = DcxFile.Read(data);
                        data     = new MemoryStream(dcxFile.Decompress());
                        fileName = Path.Combine(Path.GetDirectoryName(fileName), Path.GetFileNameWithoutExtension(fileName));
                    }

                    string outputFilePath = Path.Combine(options.OutputPath, fileName);
                    Directory.CreateDirectory(Path.GetDirectoryName(outputFilePath));
                    File.WriteAllBytes(outputFilePath, data.ToArray());
                }
            }
        }
Example #3
0
        private static void UnpackDcxFile(Options options)
        {
            string unpackedFileName = Path.GetFileNameWithoutExtension(options.InputPath);
            string outputFilePath   = options.OutputPath;
            bool   hasExtension     = Path.GetExtension(unpackedFileName) != "";

            using (FileStream inputStream = new FileStream(options.InputPath, FileMode.Open, FileAccess.Read))
            {
                DcxFile dcxFile          = DcxFile.Read(inputStream);
                byte[]  decompressedData = dcxFile.Decompress();

                if (!hasExtension)
                {
                    string extension = GetDataExtension(new MemoryStream(decompressedData));
                    if (extension != ".dcx")
                    {
                        outputFilePath += extension;
                    }
                }

                File.WriteAllBytes(outputFilePath, decompressedData);
            }
        }
Example #4
0
        private static bool TryReadFileSize(Bhd5BucketEntry entry, Bdt5FileStream bdtStream, out long fileSize)
        {
            fileSize = 0;

            const int    sampleLength = 48;
            MemoryStream data         = bdtStream.Read(entry.FileOffset, sampleLength);

            if (entry.IsEncrypted)
            {
                data = CryptographyUtility.DecryptAesEcb(data, entry.AesKey.Key);
            }

            string sampleSignature;

            if (!TryGetAsciiSignature(data, 4, out sampleSignature) ||
                sampleSignature != DcxFile.DcxSignature)
            {
                return(false);
            }

            fileSize = DcxFile.DcxSize + DcxFile.ReadCompressedSize(data);
            return(true);
        }
Example #5
0
        private static void UnpackBdtFile(Options options)
        {
            FileNameDictionary dictionary = FileNameDictionary.OpenFromFile(options.InputGameVersion);
            string             fileNameWithoutExtension = Path.GetFileName(options.InputPath).Replace("Ebl.bdt", "").Replace(".bdt", "");
            string             archiveName = fileNameWithoutExtension.ToLower();

            using (Bdt5FileStream bdtStream = Bdt5FileStream.OpenFile(options.InputPath, FileMode.Open, FileAccess.Read))
            {
                Bhd5File bhdFile = Bhd5File.Read(
                    inputStream: DecryptBhdFile(
                        filePath: Path.ChangeExtension(options.InputPath, "bhd"),
                        version: options.InputGameVersion),
                    version: options.InputGameVersion
                    );
                foreach (var bucket in bhdFile.GetBuckets())
                {
                    foreach (var entry in bucket.GetEntries())
                    {
                        MemoryStream data;
                        if (entry.FileSize == 0)
                        {
                            long fileSize;
                            if (!TryReadFileSize(entry, bdtStream, out fileSize))
                            {
                                Console.WriteLine($"Unable to determine the length of file '{entry.FileNameHash:D10}'");
                                continue;
                            }

                            entry.FileSize = fileSize;
                        }

                        if (entry.IsEncrypted)
                        {
                            data = bdtStream.Read(entry.FileOffset, entry.PaddedFileSize);
                            CryptographyUtility.DecryptAesEcb(data, entry.AesKey.Key, entry.AesKey.Ranges);
                            data.Position = 0;
                            data.SetLength(entry.FileSize);
                        }
                        else
                        {
                            data = bdtStream.Read(entry.FileOffset, entry.FileSize);
                        }

                        string fileName;
                        string dataExtension = GetDataExtension(data);
                        bool   fileNameFound = dictionary.TryGetFileName(entry.FileNameHash, archiveName, out fileName);
                        if (!fileNameFound)
                        {
                            fileNameFound = dictionary.TryGetFileName(entry.FileNameHash, archiveName, dataExtension, out fileName);
                        }

                        string extension;
                        if (fileNameFound)
                        {
                            extension = Path.GetExtension(fileName);

                            if (dataExtension == ".dcx" && extension != ".dcx")
                            {
                                extension = ".dcx";
                                fileName += ".dcx";
                            }
                        }
                        else
                        {
                            extension = dataExtension;
                            fileName  = $"{entry.FileNameHash:D10}_{fileNameWithoutExtension}{extension}";
                        }

                        if (extension == ".enc")
                        {
                            byte[] decryptionKey;
                            if (DecryptionKeys.TryGetAesFileKey(Path.GetFileName(fileName), out decryptionKey))
                            {
                                EncFile encFile = EncFile.ReadEncFile(data, decryptionKey);
                                data = encFile.Data;

                                fileName  = Path.Combine(Path.GetDirectoryName(fileName), Path.GetFileNameWithoutExtension(fileName));
                                extension = Path.GetExtension(fileName);
                            }
                            else
                            {
                                Debug.WriteLine($"No decryption key for file \'{fileName}\' found.");
                            }
                        }

                        if (extension == ".dcx")
                        {
                            DcxFile dcxFile = DcxFile.Read(data);
                            data = new MemoryStream(dcxFile.Decompress());

                            fileName = Path.Combine(Path.GetDirectoryName(fileName), Path.GetFileNameWithoutExtension(fileName));

                            if (fileNameFound)
                            {
                                extension = Path.GetExtension(fileName);
                            }
                            else
                            {
                                extension = GetDataExtension(data);
                                fileName += extension;
                            }
                        }

                        if (extension == ".bnd")
                        {
                            UnpackBnd3File(data, options.OutputPath);
                            continue; // don't actually unpack bnds
                        }

                        Debug.WriteLine(
                            "{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}",
                            fileNameWithoutExtension,
                            fileName,
                            extension,
                            entry.FileNameHash,
                            entry.FileOffset,
                            entry.FileSize,
                            entry.PaddedFileSize,
                            entry.IsEncrypted,
                            fileNameFound);

                        string newFileNamePath = Path.Combine(options.OutputPath, fileName);
                        Directory.CreateDirectory(Path.GetDirectoryName(newFileNamePath));
                        File.WriteAllBytes(newFileNamePath, data.ToArray());
                    }
                }
            }
        }
Example #6
0
        private bool unpackBDT(string name, string key, Progress progress, bool required)
        {
            if (stop)
            {
                return(true);
            }

            string bhdPath = gameDir + "\\" + name + ".bhd";
            string bdtPath = gameDir + "\\" + name + ".bdt";

            if (!(File.Exists(bhdPath) && File.Exists(bdtPath)))
            {
                if (required)
                {
                    Error = "File not found:\n" + (File.Exists(bhdPath) ? bdtPath : bhdPath);
                    return(false);
                }
                else
                {
                    return(true);
                }
            }
            Status = "Unpacking " + name + "...";

            Bhd5File bhd;

            try
            {
                using (MemoryStream bhdStream = CryptographyUtility.DecryptRsa(bhdPath, key))
                {
                    bhd = Bhd5File.Read(bhdStream, GameVersion.DarkSouls3);
                }
            }
            catch (Exception ex)
            {
                Error = $"Failed to open BHD:\n{bhdPath}\n\n{ex}";
                return(false);
            }

            int fileCount = 0;

            foreach (Bhd5Bucket bucket in bhd.GetBuckets())
            {
                fileCount += bucket.GetEntries().Count();
            }
            progress.Value = 0;
            progress.Max   = fileCount;

            try
            {
                using (Bdt5FileStream bdtStream = Bdt5FileStream.OpenFile(bdtPath, FileMode.Open, FileAccess.Read))
                {
                    foreach (Bhd5Bucket bucket in bhd.GetBuckets())
                    {
                        foreach (Bhd5BucketEntry entry in bucket.GetEntries())
                        {
                            if (stop)
                            {
                                return(true);
                            }

                            if (entry.FileSize == 0)
                            {
                                MemoryStream header = bdtStream.Read(entry.FileOffset, 48);
                                if (entry.IsEncrypted)
                                {
                                    MemoryStream disposer = header;
                                    header = CryptographyUtility.DecryptAesEcb(header, entry.AesKey.Key);
                                    disposer.Dispose();
                                }

                                byte[] signatureBytes = new byte[4];
                                header.Read(signatureBytes, 0, 4);
                                string signature = ASCII.GetString(signatureBytes);
                                if (signature != DcxFile.DcxSignature)
                                {
                                    Error = "Zero-length entry is not DCX in BHD:\n" + bhdPath;
                                    return(false);
                                }

                                header.Position = 0;
                                entry.FileSize  = DcxFile.DcxSize + DcxFile.ReadCompressedSize(header);
                                header.Dispose();
                            }

                            MemoryStream data;
                            if (entry.IsEncrypted)
                            {
                                data = bdtStream.Read(entry.FileOffset, entry.PaddedFileSize);
                                CryptographyUtility.DecryptAesEcb(data, entry.AesKey.Key, entry.AesKey.Ranges);
                                data.Position = 0;
                                data.SetLength(entry.FileSize);
                            }
                            else
                            {
                                data = bdtStream.Read(entry.FileOffset, entry.FileSize);
                            }

                            string path;
                            if (ArchiveDictionary.GetPath(entry.FileNameHash, out path))
                            {
                                path = gameDir + path.Replace('/', '\\');
                            }
                            else
                            {
                                path = $"{gameDir}\\_unknown\\{name}_{entry.FileNameHash:D10}";
                            }

                            try
                            {
                                Directory.CreateDirectory(Path.GetDirectoryName(path));
                                File.WriteAllBytes(path, data.ToArray());
                            }
                            catch (Exception ex)
                            {
                                Error = $"Failed to write file:\n{path}\n\n{ex}";
                                return(false);
                            }

                            data.Dispose();
                            progress.Value++;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Error = $"Failed to unpack BDT:\n{bdtPath}\n\n{ex}";
                return(false);
            }

            return(true);
        }