/// <summary> /// Reads and parses the ExHeader file /// </summary> /// <param name="exFile">The Ex file to use.</param> private void ReadExHeader(XivEx exFile) { OffsetTypeDict = new Dictionary <int, int>(); PageList = new List <int>(); LanguageList = new List <int>(); var exdFolderHash = HashGenerator.GetHash("exd"); var exdFileHash = HashGenerator.GetHash(exFile + ExhExtension); var index = new Index(_gameDirectory); var dat = new Dat(_gameDirectory); var offset = index.GetDataOffset(exdFolderHash, exdFileHash, XivDataFile._0A_Exd); if (offset == 0) { throw new Exception($"Could not find offest for exd/{exFile}{ExhExtension}"); } var exhData = dat.GetType2Data(offset, XivDataFile._0A_Exd); // Big Endian Byte Order using (var br = new BinaryReaderBE(new MemoryStream(exhData))) { var signature = br.ReadInt32(); var version = br.ReadInt16(); var dataSetChunk = br.ReadInt16(); var dataSetCount = br.ReadInt16(); var pageTableCount = br.ReadInt16(); var langTableCount = br.ReadInt16(); var unknown = br.ReadInt16(); var unknown1 = br.ReadInt32(); var entryCount = br.ReadInt32(); br.ReadBytes(8); for (var i = 0; i < dataSetCount; i++) { var dataType = br.ReadInt16(); var dataOffset = br.ReadInt16(); if (!OffsetTypeDict.ContainsKey(dataOffset)) { OffsetTypeDict.Add(dataOffset, dataType); } } for (var i = 0; i < pageTableCount; i++) { var pageNumber = br.ReadInt32(); var pageSize = br.ReadInt32(); PageList.Add(pageNumber); } for (var i = 0; i < langTableCount; i++) { var langCode = br.ReadInt16(); LanguageList.Add(langCode); } } }
/// <summary> /// Reads and parses the ExData file /// </summary> /// <remarks> /// This reads the data at each index of the exd file /// It then places the data in a dictionary with format [index, raw data] /// </remarks> /// <param name="exFile"></param> /// <returns>A dictionary containing the Index and Raw Data of the ex file</returns> public async Task <Dictionary <int, byte[]> > ReadExData(XivEx exFile) { var exdNameOffsetDictionary = new Dictionary <long, string>(); var exdDataDictionary = new Dictionary <int, byte[]>(); var errorString = ""; await ReadExHeader(exFile); var language = "_" + _langCode; // Some Ex files are universal and do not have a language code if (LanguageList.Count == 0) { language = ""; } // Each page is a new exd file // A good example is item_[page]_[language].exd // item_0_en.exd, item_500_en.exd, item_1000_en.exd, etc. foreach (var page in PageList) { var exdFile = exFile + "_" + page + language + ExdExtension; var exdFolderHash = HashGenerator.GetHash("exd"); var exdFileHash = HashGenerator.GetHash(exdFile); var offset = await _index.GetDataOffset(exdFolderHash, exdFileHash, XivDataFile._0A_Exd); try { exdNameOffsetDictionary.Add(offset, exdFile); } catch (Exception ex) { var zz = "zz"; throw ex; } } await Task.Run(async() => { foreach (var exdData in exdNameOffsetDictionary) { try { var exData = await _dat.GetType2Data(exdData.Key, XivDataFile._0A_Exd); // Big Endian Byte Order using (var br = new BinaryReaderBE(new MemoryStream(exData))) { br.ReadBytes(8); var offsetTableSize = br.ReadInt32(); for (var i = 0; i < offsetTableSize; i += 8) { br.BaseStream.Seek(i + 32, SeekOrigin.Begin); var entryNum = br.ReadInt32(); var entryOffset = br.ReadInt32(); br.BaseStream.Seek(entryOffset, SeekOrigin.Begin); var entrySize = br.ReadInt32(); br.ReadBytes(2); if (!exdDataDictionary.ContainsKey(entryNum)) { exdDataDictionary.Add(entryNum, br.ReadBytes(entrySize)); } } } } catch (Exception ex) { errorString += $"File: {exdData.Value}\nError: {ex.Message}\n\n"; } } }); if (!string.IsNullOrEmpty(errorString)) { throw new Exception($"There was an error reading EX data for the following\n\n{errorString}"); } return(exdDataDictionary); }
/// <summary> /// Reads and parses the ExData file /// </summary> /// <remarks> /// This reads the data at each index of the exd file /// It then places the data in a dictionary with format [index, raw data] /// </remarks> /// <param name="exFile"></param> /// <returns>A dictionary containing the Index and Raw Data of the ex file</returns> public Dictionary <int, byte[]> ReadExData(XivEx exFile) { var exdOffsetList = new List <int>(); var exdDataDictionary = new Dictionary <int, byte[]>(); ReadExHeader(exFile); var index = new Index(_gameDirectory); var dat = new Dat(_gameDirectory); var language = "_" + _langCode; // Some Ex files are universal and do not have a language code if (LanguageList.Count <= 1) { language = ""; } // Each page is a new exd file // A good example is item_[page]_[language].exd // item_0_en.exd, item_500_en.exd, item_1000_en.exd, etc. foreach (var page in PageList) { var exdFile = exFile + "_" + page + language + ExdExtension; var exdFolderHash = HashGenerator.GetHash("exd"); var exdFileHash = HashGenerator.GetHash(exdFile); exdOffsetList.Add(index.GetDataOffset(exdFolderHash, exdFileHash, XivDataFile._0A_Exd)); } foreach (var offset in exdOffsetList) { var exData = dat.GetType2Data(offset, XivDataFile._0A_Exd); // Big Endian Byte Order using (var br = new BinaryReaderBE(new MemoryStream(exData))) { br.ReadBytes(8); var offsetTableSize = br.ReadInt32(); for (var i = 0; i < offsetTableSize; i += 8) { br.BaseStream.Seek(i + 32, SeekOrigin.Begin); var entryNum = br.ReadInt32(); var entryOffset = br.ReadInt32(); br.BaseStream.Seek(entryOffset, SeekOrigin.Begin); var entrySize = br.ReadInt32(); br.ReadBytes(2); exdDataDictionary.Add(entryNum, br.ReadBytes(entrySize)); } } } return(exdDataDictionary); }