コード例 #1
0
        /// <summary>
        /// Update the dat count within the index files.
        /// </summary>
        /// <param name="dataFile">The data file to update the index for.</param>
        /// <param name="datNum">The dat number to update to.</param>
        public void UpdateIndexDatCount(XivDataFile dataFile, int datNum, bool alreadySemaphoreLocked = false)
        {
            var datCount = (byte)(datNum + 1);

            var indexPaths = new[]
            {
                Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}{IndexExtension}"),
                Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}{Index2Extension}")
            };

            if (!alreadySemaphoreLocked)
            {
                _semaphoreSlim.Wait();
            }
            try
            {
                foreach (var indexPath in indexPaths)
                {
                    using (var bw = new BinaryWriter(File.OpenWrite(indexPath)))
                    {
                        bw.BaseStream.Seek(1104, SeekOrigin.Begin);
                        bw.Write(datCount);
                    }
                }
            }
            finally
            {
                if (!alreadySemaphoreLocked)
                {
                    _semaphoreSlim.Release();
                }
            }
        }
コード例 #2
0
ファイル: Index.cs プロジェクト: 92RED/xivModdingFramework
        /// <summary>
        /// Gets the dat count within the index files.
        /// </summary>
        /// <param name="dataFile">The data file to update the index for.</param>
        public (int Index1, int Index2) GetIndexDatCount(XivDataFile dataFile)
        {
            int index1 = 0, index2 = 0;

            var indexPaths = new[]
            {
                _gameDirectory + "\\" + dataFile.GetDataFileName() + IndexExtension,
                _gameDirectory + "\\" + dataFile.GetDataFileName() + Index2Extension
            };

            for (var i = 0; i < indexPaths.Length; i++)
            {
                using (var br = new BinaryReader(File.OpenRead(indexPaths[i])))
                {
                    br.BaseStream.Seek(1104, SeekOrigin.Begin);
                    if (i == 0)
                    {
                        index1 = br.ReadByte();
                    }
                    else
                    {
                        index2 = br.ReadByte();
                    }
                }
            }

            return(index1, index2);
        }
コード例 #3
0
        /// <summary>
        /// Gets the dat count within the index files.
        /// </summary>
        /// <param name="dataFile">The data file to update the index for.</param>
        public (int Index1, int Index2) GetIndexDatCount(XivDataFile dataFile)
        {
            int index1 = 0, index2 = 0;

            var indexPaths = new[]
            {
                Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}{IndexExtension}"),
                Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}{Index2Extension}")
            };

            _semaphoreSlim.Wait();
            try
            {
                for (var i = 0; i < indexPaths.Length; i++)
                {
                    using (var br = new BinaryReader(File.OpenRead(indexPaths[i])))
                    {
                        br.BaseStream.Seek(1104, SeekOrigin.Begin);
                        if (i == 0)
                        {
                            index1 = br.ReadByte();
                        }
                        else
                        {
                            index2 = br.ReadByte();
                        }
                    }
                }
            } finally
            {
                _semaphoreSlim.Release();
            }

            return(index1, index2);
        }
コード例 #4
0
        /// <summary>
        /// Creates an Index File object from the game index files.
        /// </summary>
        /// <param name="dataFile"></param>
        /// <returns></returns>
        public async Task <IndexFile> GetIndexFile(XivDataFile dataFile, bool alreadySemaphoreLocked = false, bool allowReadOnly = false)
        {
            var index1Path = Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}{IndexExtension}");
            var index2Path = Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}{Index2Extension}");

            if (!alreadySemaphoreLocked)
            {
                await _semaphoreSlim.WaitAsync();
            }
            try {
                IndexFile index;

                if (!allowReadOnly)
                {
                    // If we're getting a writeable index, we need to get a fresh copy to avoid polluting the cache.
                    using (var index1Stream = new BinaryReader(File.OpenRead(index1Path)))
                    {
                        using (var index2Stream = new BinaryReader(File.OpenRead(index2Path)))
                        {
                            index = new IndexFile(dataFile, index1Stream, index2Stream);
                        }
                    }
                    return(index);
                }
                else
                {
                    var lastTime     = File.GetLastWriteTimeUtc(index1Path).Ticks;
                    var creationTime = File.GetCreationTimeUtc(index1Path).Ticks;

                    // If we don't have the file cached or the write time doesn't match exactly.
                    if (!_ReadOnlyIndexLastModifiedTime.ContainsKey(dataFile) || lastTime != _ReadOnlyIndexLastModifiedTime[dataFile] || lastTime == creationTime || lastTime == 0)
                    {
                        using (var index1Stream = new BinaryReader(File.OpenRead(index1Path)))
                        {
                            index = new IndexFile(dataFile, index1Stream, null);
                        }

                        _ReadOnlyIndexLastModifiedTime[dataFile] = lastTime;
                        _CachedReadOnlyIndexFiles[dataFile]      = index;
                        return(index);
                    }
                    else
                    {
                        return(_CachedReadOnlyIndexFiles[dataFile]);
                    }
                }
            }
            finally
            {
                if (!alreadySemaphoreLocked)
                {
                    _semaphoreSlim.Release();
                }
            }
        }
コード例 #5
0
        public Task <bool> CheckForOutdatedBackups(XivDataFile dataFile, DirectoryInfo backupsDirectory)
        {
            return(Task.Run(() =>
            {
                var backupDataFile =
                    new DirectoryInfo(Path.Combine(backupsDirectory.FullName, $"{dataFile.GetDataFileName()}.win32.index"));
                var currentDataFile =
                    new DirectoryInfo(Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}.win32.index"));

                var backupHash = _index.GetIndexSection1Hash(backupDataFile);
                var currentHash = _index.GetIndexSection1Hash(currentDataFile);

                return backupHash.SequenceEqual(currentHash);
            }));
        }
コード例 #6
0
ファイル: Index.cs プロジェクト: 92RED/xivModdingFramework
        /// <summary>
        /// Determines whether the given folder path exists
        /// </summary>
        /// <param name="folderHash">The hashed folder</param>
        /// <param name="dataFile">The data file</param>
        /// <returns>True if it exists, False otherwise</returns>
        public bool FolderExists(int folderHash, XivDataFile dataFile)
        {
            var indexPath = _gameDirectory + "\\" + dataFile.GetDataFileName() + IndexExtension;

            // These are the offsets to relevant data
            const int fileCountOffset = 1036;
            const int dataStartOffset = 2048;

            using (var br = new BinaryReader(File.OpenRead(indexPath)))
            {
                br.BaseStream.Seek(fileCountOffset, SeekOrigin.Begin);
                var numOfFiles = br.ReadInt32();

                br.BaseStream.Seek(dataStartOffset, SeekOrigin.Begin);
                for (var i = 0; i < numOfFiles; br.ReadBytes(4), i += 16)
                {
                    var fileNameHash = br.ReadInt32();

                    var folderPathHash = br.ReadInt32();

                    if (folderPathHash == folderHash)
                    {
                        return(true);
                    }

                    br.ReadBytes(4);
                }
            }

            return(false);
        }
コード例 #7
0
ファイル: Index.cs プロジェクト: 92RED/xivModdingFramework
        /// <summary>
        /// Gets all the folder hashes in a given folder path
        /// </summary>
        /// <param name="dataFile">The data file to look in</param>
        /// <returns>A list of all of the folder hashes</returns>
        public List <int> GetAllFolderHashes(XivDataFile dataFile)
        {
            var folderHashList = new HashSet <int>();

            // These are the offsets to relevant data
            const int fileCountOffset = 1036;
            const int dataStartOffset = 2048;

            var indexPath = _gameDirectory + "\\" + dataFile.GetDataFileName() + IndexExtension;

            using (var br = new BinaryReader(File.OpenRead(indexPath)))
            {
                br.BaseStream.Seek(fileCountOffset, SeekOrigin.Begin);
                var totalFiles = br.ReadInt32();

                br.BaseStream.Seek(dataStartOffset, SeekOrigin.Begin);
                for (var i = 0; i < totalFiles; br.ReadBytes(4), i += 16)
                {
                    br.ReadBytes(4);

                    var folderPathHash = br.ReadInt32();

                    folderHashList.Add(folderPathHash);

                    br.ReadBytes(4);
                }
            }

            return(folderHashList.ToList());
        }
コード例 #8
0
        /// <summary>
        /// Checks to see whether the index file is locked
        /// </summary>
        /// <param name="dataFile">The data file to check</param>
        /// <returns>True if locked</returns>
        public bool IsIndexLocked(XivDataFile dataFile)
        {
            var fileName = dataFile.GetDataFileName();
            var isLocked = false;

            var indexPath  = Path.Combine(_gameDirectory.FullName, $"{fileName}{IndexExtension}");
            var index2Path = Path.Combine(_gameDirectory.FullName, $"{fileName}{Index2Extension}");

            FileStream stream  = null;
            FileStream stream1 = null;

            try
            {
                stream  = File.Open(indexPath, FileMode.Open);
                stream1 = File.Open(index2Path, FileMode.Open);
            }
            catch (Exception e)
            {
                isLocked = true;
            }
            finally
            {
                stream?.Dispose();
                stream?.Close();
                stream1?.Dispose();
                stream1?.Close();
            }

            return(isLocked);
        }
コード例 #9
0
ファイル: Index.cs プロジェクト: 92RED/xivModdingFramework
        /// <summary>
        /// Get all the file hash and file offset in a given folder
        /// </summary>
        /// <param name="hashedFolder">The hashed value of the folder path</param>
        /// <param name="dataFile">The data file to look in</param>
        /// <returns>A list containing the hashed values of the files in the given folder</returns>
        public Dictionary <int, int> GetAllHashedFilesAndOffsetsInFolder(int hashedFolder, XivDataFile dataFile)
        {
            var fileHashesDict = new Dictionary <int, int>();

            // These are the offsets to relevant data
            const int fileCountOffset = 1036;
            const int dataStartOffset = 2048;

            var indexPath = _gameDirectory + "\\" + dataFile.GetDataFileName() + IndexExtension;

            using (var br = new BinaryReader(File.OpenRead(indexPath)))
            {
                br.BaseStream.Seek(fileCountOffset, SeekOrigin.Begin);
                var totalFiles = br.ReadInt32();

                br.BaseStream.Seek(dataStartOffset, SeekOrigin.Begin);
                for (var i = 0; i < totalFiles; br.ReadBytes(4), i += 16)
                {
                    var hashedFile = br.ReadInt32();

                    var folderPathHash = br.ReadInt32();

                    if (folderPathHash == hashedFolder)
                    {
                        fileHashesDict.Add(hashedFile, br.ReadInt32() * 8);
                    }
                    else
                    {
                        br.ReadBytes(4);
                    }
                }
            }

            return(fileHashesDict);
        }
コード例 #10
0
        /// <summary>
        /// Gets all the folder hashes in a given folder path
        /// </summary>
        /// <param name="dataFile">The data file to look in</param>
        /// <returns>A list of all of the folder hashes</returns>
        public async Task <List <int> > GetAllFolderHashes(XivDataFile dataFile)
        {
            var folderHashList = new HashSet <int>();

            // These are the offsets to relevant data
            const int fileCountOffset = 1036;
            const int dataStartOffset = 2048;

            var indexPath = Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}{IndexExtension}");

            await Task.Run(() =>
            {
                using (var br = new BinaryReader(File.OpenRead(indexPath)))
                {
                    br.BaseStream.Seek(fileCountOffset, SeekOrigin.Begin);
                    var totalFiles = br.ReadInt32();

                    br.BaseStream.Seek(dataStartOffset, SeekOrigin.Begin);
                    for (var i = 0; i < totalFiles; br.ReadBytes(4), i += 16)
                    {
                        br.ReadBytes(4);

                        var folderPathHash = br.ReadInt32();

                        folderHashList.Add(folderPathHash);

                        br.ReadBytes(4);
                    }
                }
            });

            return(folderHashList.ToList());
        }
コード例 #11
0
        /// <summary>
        /// Determines whether the given folder path exists
        /// </summary>
        /// <param name="folderHash">The hashed folder</param>
        /// <param name="dataFile">The data file</param>
        /// <returns>True if it exists, False otherwise</returns>
        public async Task <bool> FolderExists(int folderHash, XivDataFile dataFile)
        {
            var indexPath = Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}{IndexExtension}");

            // These are the offsets to relevant data
            const int fileCountOffset = 1036;
            const int dataStartOffset = 2048;

            return(await Task.Run(() =>
            {
                using (var br = new BinaryReader(File.OpenRead(indexPath)))
                {
                    br.BaseStream.Seek(fileCountOffset, SeekOrigin.Begin);
                    var numOfFiles = br.ReadInt32();

                    br.BaseStream.Seek(dataStartOffset, SeekOrigin.Begin);
                    for (var i = 0; i < numOfFiles; br.ReadBytes(4), i += 16)
                    {
                        var fileNameHash = br.ReadInt32();

                        var folderPathHash = br.ReadInt32();

                        if (folderPathHash == folderHash)
                        {
                            return true;
                        }

                        br.ReadBytes(4);
                    }
                }

                return false;
            }));
        }
コード例 #12
0
        /// <summary>
        /// Gets the file dictionary for the data in the .dat file
        /// </summary>
        /// <param name="dataFile">The data file to look in</param>
        /// <returns>Dictionary containing (concatenated string of file+folder hashes, offset) </returns>
        public Task <Dictionary <string, int> > GetFileDictionary(XivDataFile dataFile)
        {
            return(Task.Run(() =>
            {
                var fileDictionary = new Dictionary <string, int>();
                var indexPath = Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}{IndexExtension}");

                // These are the offsets to relevant data
                const int fileCountOffset = 1036;
                const int dataStartOffset = 2048;

                using (var br = new BinaryReader(File.OpenRead(indexPath)))
                {
                    br.BaseStream.Seek(fileCountOffset, SeekOrigin.Begin);
                    var fileCount = br.ReadInt32();

                    br.BaseStream.Seek(dataStartOffset, SeekOrigin.Begin);

                    // loop through each file entry
                    for (var i = 0; i < fileCount; br.ReadBytes(4), i += 16)
                    {
                        var fileNameHash = br.ReadInt32();
                        var folderPathHash = br.ReadInt32();
                        var offset = br.ReadInt32() * 8;

                        fileDictionary.Add($"{fileNameHash}{folderPathHash}", offset);
                    }
                }

                return fileDictionary;
            }));
        }
コード例 #13
0
ファイル: Index.cs プロジェクト: 92RED/xivModdingFramework
        /// <summary>
        /// Checks to see whether the index file is locked
        /// </summary>
        /// <param name="dataFile">The data file to check</param>
        /// <returns>True if locked</returns>
        public bool IsIndexLocked(XivDataFile dataFile)
        {
            var fileName = dataFile.GetDataFileName();

            var indexPath  = $"{_gameDirectory}\\{fileName}{IndexExtension}";
            var index2Path = $"{_gameDirectory}\\{fileName}{Index2Extension}";

            FileStream stream  = null;
            FileStream stream1 = null;

            try
            {
                stream  = File.Open(indexPath, FileMode.Open);
                stream1 = File.Open(index2Path, FileMode.Open);
            }
            catch (Exception e)
            {
                return(true);
            }
            finally
            {
                stream?.Close();
                stream1?.Close();
            }

            return(false);
        }
コード例 #14
0
        /// <summary>
        /// Gets the offset for the data in the .dat file
        /// </summary>
        /// <param name="hashedFolder">The hashed value of the folder path</param>
        /// <param name="hashedFile">The hashed value of the file name</param>
        /// <param name="dataFile">The data file to look in</param>
        /// <returns>The offset to the data</returns>
        public Task <int> GetDataOffset(int hashedFolder, int hashedFile, XivDataFile dataFile)
        {
            return(Task.Run(async() =>
            {
                var indexPath = Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}{IndexExtension}");
                var offset = 0;

                // These are the offsets to relevant data
                const int fileCountOffset = 1036;
                const int dataStartOffset = 2048;

                await _semaphoreSlim.WaitAsync();

                try
                {
                    using (var br = new BinaryReader(File.OpenRead(indexPath)))
                    {
                        br.BaseStream.Seek(fileCountOffset, SeekOrigin.Begin);
                        var fileCount = br.ReadInt32();

                        br.BaseStream.Seek(dataStartOffset, SeekOrigin.Begin);

                        // loop through each file entry
                        for (var i = 0; i < fileCount; br.ReadBytes(4), i += 16)
                        {
                            var fileNameHash = br.ReadInt32();

                            // check if the provided file name hash matches the current file name hash
                            if (fileNameHash == hashedFile)
                            {
                                var folderPathHash = br.ReadInt32();

                                // check if the provided folder path hash matches the current folder path hash
                                if (folderPathHash == hashedFolder)
                                {
                                    // this is the entry we are looking for, get the offset and break out of the loop
                                    offset = br.ReadInt32() * 8;
                                    break;
                                }

                                br.ReadBytes(4);
                            }
                            else
                            {
                                br.ReadBytes(8);
                            }
                        }
                    }
                }
                finally
                {
                    _semaphoreSlim.Release();
                }

                return offset;
            }));
        }
コード例 #15
0
        /// <summary>
        /// Retrieves all of the offsets for an arbitrary list of files within the same data file, via their Index2 entries.
        /// </summary>
        /// <param name="dataFile"></param>
        /// <returns></returns>
        private async Task <Dictionary <string, long> > GetDataOffsetsIndex2(XivDataFile dataFile, Dictionary <uint, string> fileHashes)
        {
            var ret = new Dictionary <string, long>();

            return(await Task.Run(async() =>
            {
                var index2Path = Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}{Index2Extension}");


                var SegmentHeaders = new int[4];
                var SegmentOffsets = new int[4];
                var SegmentSizes = new int[4];

                // Segment header offsets
                SegmentHeaders[0] = 1028;                   // Files
                SegmentHeaders[1] = 1028 + (72 * 1) + 4;    // Unknown
                SegmentHeaders[2] = 1028 + (72 * 2) + 4;    // Unknown
                SegmentHeaders[3] = 1028 + (72 * 3) + 4;    // Folders


                await _semaphoreSlim.WaitAsync();
                try
                {
                    // Might as well grab the whole thing since we're doing a full scan.
                    byte[] originalIndex = File.ReadAllBytes(index2Path);

                    // Get all the segment header data
                    for (int i = 0; i < SegmentHeaders.Length; i++)
                    {
                        SegmentOffsets[i] = BitConverter.ToInt32(originalIndex, SegmentHeaders[i] + 4);
                        SegmentSizes[i] = BitConverter.ToInt32(originalIndex, SegmentHeaders[i] + 8);
                    }

                    int fileCount = SegmentSizes[0] / 8;

                    for (int i = 0; i < fileCount; i++)
                    {
                        int position = SegmentOffsets[0] + (i * 8);
                        uint iFullPathHash = BitConverter.ToUInt32(originalIndex, position);
                        uint iOffset = BitConverter.ToUInt32(originalIndex, position + 4);

                        // Index 2 is just in hash order, so find the spot where we fit in.
                        if (fileHashes.ContainsKey(iFullPathHash))
                        {
                            long offset = (long)iOffset;
                            ret.Add(fileHashes[iFullPathHash], offset * 8);
                        }
                    }
                }
                finally
                {
                    _semaphoreSlim.Release();
                }
                return ret;
            }));
        }
コード例 #16
0
        /// <summary>
        /// Updates the .index files offset for a given item.
        /// </summary>
        /// <param name="offset">The new offset to be used.</param>
        /// <param name="fullPath">The internal path of the file whos offset is to be updated.</param>
        /// <param name="dataFile">The data file to update the index for</param>
        /// <returns>The offset which was replaced.</returns>
        public async Task <int> UpdateIndex(long offset, string fullPath, XivDataFile dataFile)
        {
            fullPath = fullPath.Replace("\\", "/");
            var folderHash =
                HashGenerator.GetHash(fullPath.Substring(0, fullPath.LastIndexOf("/", StringComparison.Ordinal)));
            var fileHash  = HashGenerator.GetHash(Path.GetFileName(fullPath));
            var oldOffset = 0;

            // These are the offsets to relevant data
            const int fileCountOffset = 1036;
            const int dataStartOffset = 2048;

            var indexPath = Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}{IndexExtension}");

            await Task.Run(() =>
            {
                using (var index = File.Open(indexPath, FileMode.Open))
                {
                    using (var br = new BinaryReader(index))
                    {
                        using (var bw = new BinaryWriter(index))
                        {
                            br.BaseStream.Seek(fileCountOffset, SeekOrigin.Begin);
                            var numOfFiles = br.ReadInt32();

                            br.BaseStream.Seek(dataStartOffset, SeekOrigin.Begin);
                            for (var i = 0; i < numOfFiles; br.ReadBytes(4), i += 16)
                            {
                                var fileNameHash = br.ReadInt32();

                                if (fileNameHash == fileHash)
                                {
                                    var folderPathHash = br.ReadInt32();

                                    if (folderPathHash == folderHash)
                                    {
                                        oldOffset = br.ReadInt32();
                                        bw.BaseStream.Seek(br.BaseStream.Position - 4, SeekOrigin.Begin);
                                        bw.Write(offset / 8);
                                        break;
                                    }

                                    br.ReadBytes(4);
                                }
                                else
                                {
                                    br.ReadBytes(8);
                                }
                            }
                        }
                    }
                }
            });

            return(oldOffset);
        }
コード例 #17
0
ファイル: Dat.cs プロジェクト: goaaats/xivModdingFramework
        /// <summary>
        /// Gets the largest dat number for a given data file.
        /// </summary>
        /// <param name="dataFile">The data file to check.</param>
        /// <returns>The largest dat number for the given data file.</returns>
        private int GetLargestDatNumber(XivDataFile dataFile)
        {
            var allFiles = Directory.GetFiles(_gameDirectory.FullName);

            var dataFiles = from file in allFiles where file.Contains(dataFile.GetDataFileName()) && file.Contains(".dat") select file;

            var max = dataFiles.Select(file => int.Parse(file.Substring(file.Length - 1))).Concat(new[] { 0 }).Max();

            return(max);
        }
コード例 #18
0
ファイル: Index.cs プロジェクト: 92RED/xivModdingFramework
        /// <summary>
        /// Update the dat count within the index files.
        /// </summary>
        /// <param name="dataFile">The data file to update the index for.</param>
        /// <param name="datNum">The dat number to update to.</param>
        public void UpdateIndexDatCount(XivDataFile dataFile, int datNum)
        {
            var datCount = (byte)(datNum + 1);

            var indexPaths = new[]
            {
                _gameDirectory + "\\" + dataFile.GetDataFileName() + IndexExtension,
                _gameDirectory + "\\" + dataFile.GetDataFileName() + Index2Extension
            };

            foreach (var indexPath in indexPaths)
            {
                using (var bw = new BinaryWriter(File.OpenWrite(indexPath)))
                {
                    bw.BaseStream.Seek(1104, SeekOrigin.Begin);
                    bw.Write(datCount);
                }
            }
        }
コード例 #19
0
        public Task <bool> CheckForOutdatedBackups(XivDataFile dataFile, DirectoryInfo backupsDirectory)
        {
            return(Task.Run(() =>
            {
                var backupDataFile =
                    new DirectoryInfo(Path.Combine(backupsDirectory.FullName, $"{dataFile.GetDataFileName()}.win32.index"));
                var currentDataFile =
                    new DirectoryInfo(Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}.win32.index"));

                // Since the material addition directly adds to section 1 we can no longer check for outdated using that section header
                // so instead compare the hahes of sections 2 and 3
                var backupHashSection2 = _index.GetIndexSection2Hash(backupDataFile);
                var currentHashSection2 = _index.GetIndexSection2Hash(currentDataFile);
                var backupHashSection3 = _index.GetIndexSection3Hash(backupDataFile);
                var currentHashSection3 = _index.GetIndexSection3Hash(currentDataFile);

                return backupHashSection2.SequenceEqual(currentHashSection2) && backupHashSection3.SequenceEqual(currentHashSection3);
            }));
        }
コード例 #20
0
        public Task <bool> CheckForOutdatedBackups(XivDataFile dataFile, DirectoryInfo backupsDirectory)
        {
            return(Task.Run(async() =>
            {
                var haveFilesAddedByTexTools = await _index.HaveFilesAddedByTexTools(dataFile);
                if (haveFilesAddedByTexTools)
                {
                    return true;
                }
                var backupDataFile =
                    new DirectoryInfo(Path.Combine(backupsDirectory.FullName, $"{dataFile.GetDataFileName()}.win32.index"));
                var currentDataFile =
                    new DirectoryInfo(Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}.win32.index"));

                var backupHash = _index.GetIndexSection1Hash(backupDataFile);
                var currentHash = _index.GetIndexSection1Hash(currentDataFile);

                return backupHash.SequenceEqual(currentHash);
            }));
        }
コード例 #21
0
        /// <summary>
        /// This function returns TRUE if the backups should be used, and FALSE if they should not.
        /// </summary>
        /// <param name="dataFile"></param>
        /// <param name="backupsDirectory"></param>
        /// <returns></returns>
        public Task <bool> CheckForOutdatedBackups(XivDataFile dataFile, DirectoryInfo backupsDirectory)
        {
            return(Task.Run(() =>
            {
                var backupDataFile =
                    new DirectoryInfo(Path.Combine(backupsDirectory.FullName, $"{dataFile.GetDataFileName()}.win32.index"));
                var currentDataFile =
                    new DirectoryInfo(Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}.win32.index"));

                // Since the material addition directly adds to section 1 we can no longer check for outdated using that section header
                // so instead compare the hashes of sections 2 and 3
                byte[] currentHashSection2;
                byte[] currentHashSection3;
                byte[] backupHashSection2;
                byte[] backupHashSection3;
                try
                {
                    currentHashSection2 = _index.GetIndexSection2Hash(currentDataFile);
                    currentHashSection3 = _index.GetIndexSection3Hash(currentDataFile);
                }
                catch
                {
                    // Base files are f****d, use *any* backups.
                    return true;
                }

                try
                {
                    backupHashSection2 = _index.GetIndexSection2Hash(backupDataFile);
                    backupHashSection3 = _index.GetIndexSection3Hash(backupDataFile);
                }
                catch
                {
                    // Backups are f****d, can't use those.
                    return false;
                }


                return backupHashSection2.SequenceEqual(currentHashSection2) && backupHashSection3.SequenceEqual(currentHashSection3);
            }));
        }
コード例 #22
0
ファイル: Dat.cs プロジェクト: goaaats/xivModdingFramework
        /// <summary>
        /// Gets the data for type 2 files.
        /// </summary>
        /// <remarks>
        /// Type 2 files vary in content.
        /// </remarks>
        /// <param name="offset">The offset where the data is located.</param>
        /// <param name="dataFile">The data file that contains the data.</param>
        /// <returns>Byte array containing the decompressed type 2 data.</returns>
        public byte[] GetType2Data(int offset, XivDataFile dataFile)
        {
            var type2Bytes = new List <byte>();

            // This formula is used to obtain the dat number in which the offset is located
            var datNum = ((offset / 8) & 0x0F) / 2;

            var datPath = _gameDirectory + "\\" + dataFile.GetDataFileName() + DatExtension + datNum;

            offset = OffsetCorrection(datNum, offset);

            using (var br = new BinaryReader(File.OpenRead(datPath)))
            {
                br.BaseStream.Seek(offset, SeekOrigin.Begin);

                var headerLength = br.ReadInt32();

                br.ReadBytes(16);

                var dataBlockCount = br.ReadInt32();

                for (var i = 0; i < dataBlockCount; i++)
                {
                    br.BaseStream.Seek(offset + (24 + (8 * i)), SeekOrigin.Begin);

                    var dataBlockOffset = br.ReadInt32();

                    br.BaseStream.Seek(offset + headerLength + dataBlockOffset, SeekOrigin.Begin);

                    br.ReadBytes(8);

                    var compressedSize   = br.ReadInt32();
                    var uncompressedSize = br.ReadInt32();

                    // When the compressed size of a data block shows 32000, it is uncompressed.
                    if (compressedSize == 32000)
                    {
                        type2Bytes.AddRange(br.ReadBytes(uncompressedSize));
                    }
                    else
                    {
                        var compressedData = br.ReadBytes(compressedSize);

                        var decompressedData = IOUtil.Decompressor(compressedData, uncompressedSize);

                        type2Bytes.AddRange(decompressedData);
                    }
                }
            }

            return(type2Bytes.ToArray());
        }
コード例 #23
0
        /// <summary>
        /// Checks whether the index file contains any of the folders passed in
        /// </summary>
        /// <remarks>
        /// Runs through the index file once checking if the hashed folder value exists in the dictionary
        /// then adds it to the list if it does.
        /// </remarks>
        /// <param name="hashNumDictionary">A Dictionary containing the folder hash and item number</param>
        /// <param name="dataFile">The data file to look in</param>
        /// <returns></returns>
        public Task <List <int> > GetFolderExistsList(Dictionary <int, int> hashNumDictionary, XivDataFile dataFile)
        {
            return(Task.Run(async() =>
            {
                await _semaphoreSlim.WaitAsync();

                // HashSet because we don't want any duplicates
                var folderExistsList = new HashSet <int>();

                try
                {
                    // These are the offsets to relevant data
                    const int fileCountOffset = 1036;
                    const int dataStartOffset = 2048;

                    var indexPath = Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}{IndexExtension}");

                    using (var br = new BinaryReader(File.OpenRead(indexPath)))
                    {
                        br.BaseStream.Seek(fileCountOffset, SeekOrigin.Begin);
                        var totalFiles = br.ReadInt32();

                        br.BaseStream.Seek(dataStartOffset, SeekOrigin.Begin);
                        for (var i = 0; i < totalFiles; br.ReadBytes(4), i += 16)
                        {
                            br.ReadBytes(4);

                            var folderPathHash = br.ReadInt32();

                            if (hashNumDictionary.ContainsKey(folderPathHash))
                            {
                                folderExistsList.Add(hashNumDictionary[folderPathHash]);

                                br.ReadBytes(4);
                            }
                            else
                            {
                                br.ReadBytes(4);
                            }
                        }
                    }
                }
                finally
                {
                    _semaphoreSlim.Release();
                }

                return folderExistsList.ToList();
            }));
        }
コード例 #24
0
        /// <summary>
        /// Retrieves all of the offsets for an arbitrary list of files within the same data file.
        /// </summary>
        /// <param name="dataFile"></param>
        /// <returns></returns>
        private async Task <Dictionary <string, long> > GetDataOffsets(XivDataFile dataFile, Dictionary <int, Dictionary <int, string> > FolderFiles)
        {
            var ret = new Dictionary <string, long>();

            return(await Task.Run(() =>
            {
                var indexPath = Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}{IndexExtension}");

                // These are the offsets to relevant data
                const int fileCountOffset = 1036;
                const int dataStartOffset = 2048;

                int count = 0;
                _semaphoreSlim.Wait();
                try
                {
                    using (var br = new BinaryReader(File.OpenRead(indexPath)))
                    {
                        br.BaseStream.Seek(fileCountOffset, SeekOrigin.Begin);
                        var fileCount = br.ReadInt32();

                        br.BaseStream.Seek(dataStartOffset, SeekOrigin.Begin);

                        // loop through each file entry
                        for (var i = 0; i < fileCount; i += 16)
                        {
                            var fileNameHash = br.ReadInt32();
                            var folderPathHash = br.ReadInt32();
                            long offset = br.ReadUInt32();
                            var unused = br.ReadInt32();

                            if (FolderFiles.ContainsKey(folderPathHash))
                            {
                                if (FolderFiles[folderPathHash].ContainsKey(fileNameHash))
                                {
                                    count++;
                                    ret.Add(FolderFiles[folderPathHash][fileNameHash], offset * 8);
                                }
                            }
                        }
                    }
                }
                finally
                {
                    _semaphoreSlim.Release();
                }

                return ret;
            }));
        }
コード例 #25
0
ファイル: Index.cs プロジェクト: 92RED/xivModdingFramework
        /// <summary>
        /// Creates a backup of the index file.
        /// </summary>
        /// <param name="backupsDirectory">The directory in which to place the backup files.
        /// The directory will be created if it does not exist.</param>
        /// <param name="dataFile">The file to backup.</param>
        public void CreateIndexBackups(DirectoryInfo backupsDirectory, XivDataFile dataFile)
        {
            var fileName = dataFile.GetDataFileName();

            var indexPath  = _gameDirectory + "\\" + fileName + IndexExtension;
            var index2Path = _gameDirectory + "\\" + fileName + Index2Extension;

            var indexBackupPath  = backupsDirectory.FullName + "\\" + fileName + IndexExtension;
            var index2BackupPath = backupsDirectory.FullName + "\\" + fileName + Index2Extension;

            Directory.CreateDirectory(backupsDirectory.FullName);

            File.Copy(indexPath, indexBackupPath, true);
            File.Copy(index2Path, index2BackupPath, true);
        }
コード例 #26
0
        /// <summary>
        /// Creates a backup of the index file.
        /// </summary>
        /// <param name="backupsDirectory">The directory in which to place the backup files.
        /// The directory will be created if it does not exist.</param>
        /// <param name="dataFile">The file to backup.</param>
        public void CreateIndexBackups(DirectoryInfo backupsDirectory, XivDataFile dataFile)
        {
            var fileName = dataFile.GetDataFileName();

            var indexPath  = Path.Combine(_gameDirectory.FullName, $"{fileName}{IndexExtension}");
            var index2Path = Path.Combine(_gameDirectory.FullName, $"{fileName}{Index2Extension}");

            var indexBackupPath  = Path.Combine(backupsDirectory.FullName, $"{fileName}{IndexExtension}");
            var index2BackupPath = Path.Combine(backupsDirectory.FullName, $"{fileName}{Index2Extension}");

            Directory.CreateDirectory(backupsDirectory.FullName);

            File.Copy(indexPath, indexBackupPath, true);
            File.Copy(index2Path, index2BackupPath, true);
        }
コード例 #27
0
ファイル: Index.cs プロジェクト: 92RED/xivModdingFramework
        /// <summary>
        /// Gets the offset for the data in the .dat file
        /// </summary>
        /// <param name="hashedFolder">The hashed value of the folder path</param>
        /// <param name="hashedFile">The hashed value of the file name</param>
        /// <param name="dataFile">The data file to look in</param>
        /// <returns>The offset to the data</returns>
        public int GetDataOffset(int hashedFolder, int hashedFile, XivDataFile dataFile)
        {
            var indexPath = _gameDirectory + "\\" + dataFile.GetDataFileName() + IndexExtension;
            var offset    = 0;

            // These are the offsets to relevant data
            const int fileCountOffset = 1036;
            const int dataStartOffset = 2048;

            using (var br = new BinaryReader(File.OpenRead(indexPath)))
            {
                br.BaseStream.Seek(fileCountOffset, SeekOrigin.Begin);
                var fileCount = br.ReadInt32();

                br.BaseStream.Seek(dataStartOffset, SeekOrigin.Begin);

                // loop through each file entry
                for (var i = 0; i < fileCount; br.ReadBytes(4), i += 16)
                {
                    var fileNameHash = br.ReadInt32();

                    // check if the provided file name hash matches the current file name hash
                    if (fileNameHash == hashedFile)
                    {
                        var folderPathHash = br.ReadInt32();

                        // check if the provided folder path hash matches the current folder path hash
                        if (folderPathHash == hashedFolder)
                        {
                            // this is the entry we are looking for, get the offset and break out of the loop
                            offset = br.ReadInt32() * 8;
                            break;
                        }

                        br.ReadBytes(4);
                    }
                    else
                    {
                        br.ReadBytes(8);
                    }
                }
            }

            return(offset);
        }
コード例 #28
0
ファイル: Dat.cs プロジェクト: goaaats/xivModdingFramework
        private bool IsOriginalDat(XivDataFile dataFile)
        {
            // Checks if any entry in the modlist is within the datafile
            // If there is, then a modded dat has already been created
            using (var streamReader = new StreamReader(_modListDirectory.FullName))
            {
                string line;
                while ((line = streamReader.ReadLine()) != null)
                {
                    var modInfo = JsonConvert.DeserializeObject <ModInfo>(line);
                    if (modInfo.datFile.Contains(dataFile.GetDataFileName()))
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
コード例 #29
0
        /// <summary>
        /// Updates the .index2 files offset for a given item.
        /// </summary>
        /// <param name="offset">The new offset to be used.</param>
        /// <param name="fullPath">The internal path of the file whos offset is to be updated.</param>
        /// <param name="dataFile">The data file to update the index for</param>
        /// <returns>The offset which was replaced.</returns>
        public async Task UpdateIndex2(long offset, string fullPath, XivDataFile dataFile)
        {
            fullPath = fullPath.Replace("\\", "/");
            var pathHash = HashGenerator.GetHash(fullPath);

            // These are the offsets to relevant data
            const int fileCountOffset = 1036;
            const int dataStartOffset = 2048;

            var index2Path = Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}{Index2Extension}");

            await Task.Run(() =>
            {
                using (var index = File.Open(index2Path, FileMode.Open))
                {
                    using (var br = new BinaryReader(index))
                    {
                        using (var bw = new BinaryWriter(index))
                        {
                            br.BaseStream.Seek(fileCountOffset, SeekOrigin.Begin);
                            var numOfFiles = br.ReadInt32();

                            br.BaseStream.Seek(dataStartOffset, SeekOrigin.Begin);
                            for (var i = 0; i < numOfFiles; i += 8)
                            {
                                var fullPathHash = br.ReadInt32();

                                if (fullPathHash == pathHash)
                                {
                                    bw.BaseStream.Seek(br.BaseStream.Position, SeekOrigin.Begin);
                                    bw.Write((int)(offset / 8));
                                    break;
                                }

                                br.ReadBytes(4);
                            }
                        }
                    }
                }
            });
        }
コード例 #30
0
ファイル: Dat.cs プロジェクト: goaaats/xivModdingFramework
        /// <summary>
        /// Creates a new dat file to store moddified data.
        /// </summary>
        /// <remarks>
        /// This will first find what the largest dat number is for a given data file
        /// It will then create a new dat file that is one number larger
        /// Lastly it will update the index files to reflect the new dat count
        /// </remarks>
        /// <param name="dataFile">The data file to create a new dat for.</param>
        /// <returns>The new dat number.</returns>
        public int CreateNewDat(XivDataFile dataFile)
        {
            var nextDatNumber = GetLargestDatNumber(dataFile) + 1;

            var datPath = _gameDirectory.FullName + "\\" + dataFile.GetDataFileName() + DatExtension + nextDatNumber;

            using (var fs = File.Create(datPath))
            {
                using (var bw = new BinaryWriter(fs))
                {
                    bw.Write(MakeSqPackHeader());
                    bw.Write(MakeDatHeader());
                }
            }

            var index = new Index(_gameDirectory);

            index.UpdateIndexDatCount(dataFile, nextDatNumber);

            return(nextDatNumber);
        }