示例#1
0
        public TOCFileInfo parseToc()
        {
            FileStream  TBL = File.OpenRead(Properties.Settings.Default.inputPsarcTBLBinary);
            TOCFileInfo toc = new TOCFileInfo();

            uint                 fileCount;
            List <uint>          fileNameSizes      = new List <uint>();
            List <bool>          fileSubFolderFlags = new List <bool>();
            List <uint>          fileIndexPointers  = new List <uint>();
            List <PACFileInfoV2> fileInfos          = new List <PACFileInfoV2>();

            changeStreamFile(TBL);

            Stream.Seek(0, SeekOrigin.Begin);
            int magic = readIntBigEndian(Stream.Position);

            if (magic != 0x54424C20)
            {
                throw new Exception("PATCH.TBL is not in TBL format!");
            }

            Stream.Seek(0x04, SeekOrigin.Current);

            fileCount = readUIntBigEndian(Stream.Position);
            uint totalFileCount = readUIntBigEndian(Stream.Position);

            toc.totalFileEntries = totalFileCount;

            ushort subFolderFlag = readUShort(Stream.Position, true);
            bool   hasSubFolder  = subFolderFlag == 0x8000 ? true : false;

            fileSubFolderFlags.Add(hasSubFolder);

            ushort initFileNamePointer = readUShort(Stream.Position, true);
            uint   prevFileNamePointer = initFileNamePointer;

            for (int i = 0; i < fileCount; i++)
            {
                if (i != fileCount - 1)
                {
                    subFolderFlag = readUShort(Stream.Position, true);
                    hasSubFolder  = subFolderFlag == 0x8000 ? true : false;
                    fileSubFolderFlags.Add(hasSubFolder);
                    uint currentFileNamePointer = readUShort(Stream.Position, true);
                    fileNameSizes.Add(currentFileNamePointer - prevFileNamePointer);
                    prevFileNamePointer = currentFileNamePointer;
                }
                else
                {
                    fileNameSizes.Add((uint)Stream.Length - prevFileNamePointer);
                }
            }

            for (int i = 0; i < totalFileCount; i++)
            {
                fileIndexPointers.Add(readUIntBigEndian(Stream.Position));
            }

            uint fileNamePointer = initFileNamePointer;

            for (int i = 0; i < fileCount; i++)
            {
                PACFileInfoV2 pacFileInfo = new PACFileInfoV2();
                uint          nameSize    = fileNameSizes[i];
                Stream.Seek(fileNamePointer, SeekOrigin.Begin);
                string relativePatchPath = readString(Stream.Position, nameSize);
                pacFileInfo.relativePatchPath = relativePatchPath;
                string nameHash = Path.GetFileNameWithoutExtension(relativePatchPath);
                if (nameHash.Contains("PATCH"))
                {
                    pacFileInfo.namePrefix = prefixEnum.PATCH;
                    nameHash = nameHash.Replace("PATCH", "");
                }
                else if (nameHash.Contains("STREAM"))
                {
                    pacFileInfo.namePrefix = prefixEnum.STREAM;
                    nameHash = nameHash.Replace("STREAM", "");
                }
                else
                {
                    pacFileInfo.namePrefix = prefixEnum.NONE;
                }
                if (!uint.TryParse(nameHash, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out uint res))
                {
                    throw new Exception("Failed to convert " + nameHash + " to uint!");
                }
                pacFileInfo.hasRelativePatchSubPath = fileSubFolderFlags[i];
                pacFileInfo.fileFlags = fileFlagsEnum.hasFileName;
                //pacFileInfo.relativePathIndex = (uint)i;
                pacFileInfo.nameHash = res;
                fileNamePointer     += nameSize;
                fileInfos.Add(pacFileInfo);
            }

            List <uint> non_Zero_fileIndexPointers = fileIndexPointers.Where(s => !s.Equals(0)).ToList();

            for (int i = 0; i < non_Zero_fileIndexPointers.Count; i++)
            {
                bool newInfo = false;
                Stream.Seek(non_Zero_fileIndexPointers[i], SeekOrigin.Begin);
                patchNoEnum patchNo        = (patchNoEnum)readUIntBigEndian(Stream.Position);
                uint        relativePathNo = readUIntBigEndian(Stream.Position);
                uint        unk04          = readUIntBigEndian(Stream.Position);
                uint        Size1          = readUIntBigEndian(Stream.Position);
                uint        Size2          = readUIntBigEndian(Stream.Position);
                uint        Size3          = readUIntBigEndian(Stream.Position);
                uint        unk00          = readUIntBigEndian(Stream.Position);
                uint        nameHash       = readUIntBigEndian(Stream.Position);
                int         fileIndex      = fileIndexPointers.FindIndex(a => a.Equals(non_Zero_fileIndexPointers[i]));

                PACFileInfoV2 pacFileInfo = fileInfos.FirstOrDefault(a => a.nameHash.Equals(nameHash));

                if (pacFileInfo == null)
                {
                    pacFileInfo = new PACFileInfoV2();
                    newInfo     = true;
                }
                else
                {
                    //if (relativePathNo != pacFileInfo.relativePathIndex)
                    //throw new Exception("Different relative Path Index between name and fileInfo for nameHash " + nameHash.ToString("X8"));
                }

                pacFileInfo.fileFlags |= fileFlagsEnum.hasFileInfo;
                pacFileInfo.patchNo    = patchNo;
                //pacFileInfo.relativePathIndex = relativePathNo;
                pacFileInfo.unk04         = unk04;
                pacFileInfo.Size1         = Size1;
                pacFileInfo.Size2         = Size2;
                pacFileInfo.Size3         = Size3;
                pacFileInfo.unk00         = unk00;
                pacFileInfo.nameHash      = nameHash;
                pacFileInfo.fileInfoIndex = fileIndex;

                if (Properties.Settings.Default.identifyPACFilesTBLParse)
                {
                    // Trying to find the file inside the folder.
                    string[] allFiles = Directory.GetFiles(Properties.Settings.Default.psarcTBLParseRepackFolder, "*", SearchOption.AllDirectories);

                    string nameHashStr = nameHash.ToString("X8");
                    string path        = allFiles.FirstOrDefault(s => s.Contains(nameHashStr));

                    if (path != null)
                    {
                        pacFileInfo.fileFlags |= fileFlagsEnum.hasFilePath;
                    }
                    pacFileInfo.filePath = path;
                }

                if (newInfo)
                {
                    fileInfos.Add(pacFileInfo);
                }
            }

            toc.allFiles = fileInfos;
            return(toc);
        }
示例#2
0
        public MemoryStream writeToc(TOCFileInfo Toc)
        {
            List <PACFileInfoV2> fileInfos = Toc.allFiles;
            uint totalFileCount            = Toc.totalFileEntries;

            Dictionary <int, long> fileInfoOffsets = new Dictionary <int, long>();

            List <PACFileInfoV2> onlyFileInfoswithNames = fileInfos.Where(a => a.fileFlags.HasFlag(fileFlagsEnum.hasFileName)).ToList();
            List <PACFileInfoV2> onlyFileInfoswithIndex = fileInfos.Where(a => a.fileFlags.HasFlag(fileFlagsEnum.hasFileInfo)).ToList();

            // Depreceated as we just use data's position in JSON as is.

            /*
             * // Validating index data:
             * List<uint> relPathIndexes = onlyFileInfoswithNames.Select(s => s.relativePathIndex).ToList();
             * List<int> castedIndex = relPathIndexes.ConvertAll(x => (int)x);
             *
             * // Check duplicate
             * List<int> duplicates = castedIndex.GroupBy(x => x)
             *                          .SelectMany(g => g.Skip(1)).ToList();
             *
             *
             * //List<PACFileInfo> newFiles = fileInfos.Where(a => a.fileInfoIndex > 6144).ToList();
             * //totalFileCount += (uint)newFiles.Count;
             *
             *
             * if (duplicates.Count >= 1)
             * {
             *  string dupStr = string.Empty;
             *  foreach (int dup in duplicates)
             *  {
             *      dupStr += " | " + dup;
             *  }
             *  throw new Exception("Found duplicate Relative Path Indexes! Duplicates: " + dupStr.ToString());
             * }
             *
             *
             * // Check sequential
             * int missingNo = findMissing(castedIndex.ToArray(), castedIndex.Count());
             * if (missingNo != -1)
             *  throw new Exception("Relative Path Indexes is not Consecutive! Found missing non consecutive number: " + missingNo.ToString());
             */

            // Check if there is dulplicate hashes
            // Validating nameHash data:
            List <uint> nameHashes       = fileInfos.Select(s => s.nameHash).ToList();
            List <int>  castedNameHashes = nameHashes.ConvertAll(x => (int)x);

            // Check duplicate
            List <int> duplicateNameHashes = castedNameHashes.GroupBy(x => x)
                                             .SelectMany(g => g.Skip(1)).ToList();

            if (duplicateNameHashes.Count >= 1)
            {
                string dupStr = string.Empty;
                foreach (int dup in duplicateNameHashes)
                {
                    dupStr += " | " + dup;
                }
                throw new Exception("Found duplicate Name Hash Indexes! Duplicates: " + dupStr.ToString());
            }

            uint fileNo = (uint)onlyFileInfoswithNames.Count;

            MemoryStream TBL = new MemoryStream();

            appendIntMemoryStream(TBL, 0x54424C20, true);
            appendIntMemoryStream(TBL, 0x01010000, true);
            appendUIntMemoryStream(TBL, fileNo, true);
            appendUIntMemoryStream(TBL, totalFileCount, true);

            MemoryStream fileNamePointersStream  = new MemoryStream();
            MemoryStream fileIndexPointersStream = new MemoryStream();
            MemoryStream fileInfosStream         = new MemoryStream();
            MemoryStream fileNamesStream         = new MemoryStream();

            long fileInfoStart = TBL.Length + fileNo * 0x04 + totalFileCount * 0x04;

            uint startPointer         = (uint)(0x10 + (onlyFileInfoswithNames.Count * 0x4) + (totalFileCount * 0x4));
            uint paddingRequired      = addHalfPaddingSizeCalculation(startPointer) - startPointer;
            long fileNameStartPointer = fileInfoStart + (onlyFileInfoswithIndex.Count * 0x20) + paddingRequired;

            //List<PACFileInfoV2> orderedRelativePathIndex = onlyFileInfoswithNames.OrderBy(s => s.relativePathIndex).ToList();

            List <PACFileInfoV2> actualFileNameIndex = new List <PACFileInfoV2>();

            for (int i = 0; i < onlyFileInfoswithNames.Count; i++)
            {
                PACFileInfoV2 fileInfo = onlyFileInfoswithNames[i];
                //if (fileInfo.relativePathIndex != i)
                //throw new Exception("ordered Relative Path Index is not continious!");

                string relativePath  = fileInfo.relativePatchPath;
                long   initPos       = fileNamesStream.Position;
                ushort subFolderFlag = fileInfo.hasRelativePatchSubPath ? (ushort)0x8000 : (ushort)0;
                appendStringMemoryStream(fileNamesStream, relativePath, Encoding.Default);
                appendZeroMemoryStream(fileNamesStream, 1);
                appendUIntMemoryStream(fileNamePointersStream, (uint)(fileNameStartPointer + initPos), true);
                //appendUShortMemoryStream(fileNamePointersStream, subFolderFlag, true);

                actualFileNameIndex.Add(fileInfo);
            }

            for (int i = 0; i < onlyFileInfoswithIndex.Count; i++)
            {
                PACFileInfoV2 fileInfo = onlyFileInfoswithIndex[i];

                int fileIndexes = fileInfo.fileInfoIndex;
                fileInfoOffsets[fileIndexes] = fileInfoStart + fileInfosStream.Position + paddingRequired;

                //foreach(int fileIndex in fileIndexes)
                //{
                //    fileInfoOffsets[fileIndex] = fileInfoStart + fileInfosStream.Position;
                //}

                appendUIntMemoryStream(fileInfosStream, (uint)fileInfo.patchNo, true);

                if (fileInfo.fileFlags.HasFlag(fileFlagsEnum.hasFileName))
                {
                    int trueIndex = actualFileNameIndex.FindIndex(x => x == fileInfo);
                    appendUIntMemoryStream(fileInfosStream, (uint)trueIndex, true);
                }
                else
                {
                    appendUIntMemoryStream(fileInfosStream, (uint)0, true);
                }

                appendIntMemoryStream(fileInfosStream, 0x00040000, true);
                appendUIntMemoryStream(fileInfosStream, fileInfo.Size1, true);
                appendUIntMemoryStream(fileInfosStream, fileInfo.Size2, true);
                appendUIntMemoryStream(fileInfosStream, fileInfo.Size3, true);
                appendIntMemoryStream(fileInfosStream, 0, true);
                appendUIntMemoryStream(fileInfosStream, fileInfo.nameHash, true);
            }

            for (int i = 0; i < totalFileCount; i++)
            {
                if (fileInfoOffsets.ContainsKey(i))
                {
                    appendUIntMemoryStream(fileIndexPointersStream, (uint)fileInfoOffsets[i], true);
                }
                else
                {
                    appendZeroMemoryStream(fileIndexPointersStream, 0x04);
                }
            }

            // fileIndexPointer must be aligned to 8
            MemoryStream combinedfileNamePointersandIndexPointersStream = new MemoryStream();

            combinedfileNamePointersandIndexPointersStream.Write(fileNamePointersStream.ToArray(), 0, (int)fileNamePointersStream.Length);
            combinedfileNamePointersandIndexPointersStream.Write(fileIndexPointersStream.ToArray(), 0, (int)fileIndexPointersStream.Length);
            combinedfileNamePointersandIndexPointersStream = addHalfPaddingStream(combinedfileNamePointersandIndexPointersStream);

            //TBL.Write(fileNamePointersStream.ToArray(), 0, (int)fileNamePointersStream.Length);
            //TBL.Write(fileIndexPointersStream.ToArray(), 0, (int)fileIndexPointersStream.Length);

            TBL.Write(combinedfileNamePointersandIndexPointersStream.ToArray(), 0, (int)combinedfileNamePointersandIndexPointersStream.Length);
            TBL.Write(fileInfosStream.ToArray(), 0, (int)fileInfosStream.Length);
            TBL.Write(fileNamesStream.ToArray(), 0, (int)fileNamesStream.Length);

            return(TBL);
        }