/// <summary> /// Writes the newly imported data to the .dat for modifications. /// </summary> /// <param name="data">The data to be written.</param> /// <param name="modEntry">The modlist entry (if any) for the given file.</param> /// <param name="inModList">Is the item already contained within the mod list.</param> /// <param name="internalFilePath">The internal file path of the item being modified.</param> /// <param name="category">The category of the item.</param> /// <param name="itemName">The name of the item being modified.</param> /// <param name="lineNum">The line number of the existing mod list entry for the item if it exists.</param> /// <returns>The new offset in which the modified data was placed.</returns> public static int WriteToDat(List <byte> data, JsonEntry modEntry, bool inModList, string internalFilePath, string category, string itemName, int lineNum, string datName) { int offset = 0; bool dataOverwritten = false; var datNum = int.Parse(Info.ModDatDict[datName]); var modDatPath = string.Format(Info.datDir, datName, datNum); if (inModList) { datNum = ((modEntry.modOffset / 8) & 0x0F) / 2; modDatPath = string.Format(Info.datDir, modEntry.datFile, datNum); } else { var fileLength = new FileInfo(modDatPath).Length; while (fileLength >= 2000000000) { datNum += 1; modDatPath = string.Format(Info.datDir, datName, datNum); if (!File.Exists(modDatPath)) { CreateDat.MakeNewDat(datName); } fileLength = new FileInfo(modDatPath).Length; } } var datOffsetAmount = 16 * datNum; if (inModList) { if (modEntry.modOffset == 0) { FlexibleMessageBox.Show("TexTools detected a Mod List entry with a Mod Offset of 0.\n\n" + "Please submit a bug report along with your modlist file.", "ImportTex Error " + Info.appVersion, MessageBoxButtons.OK, MessageBoxIcon.Error); return(0); } else if (modEntry.originalOffset == 0) { FlexibleMessageBox.Show("TexTools detected a Mod List entry with an Original Offset of 0.\n\n" + "Please submit a bug report along with your modlist file.", "ImportTex Error " + Info.appVersion, MessageBoxButtons.OK, MessageBoxIcon.Error); return(0); } } try { using (BinaryWriter bw = new BinaryWriter(File.OpenWrite(modDatPath))) { /* * If the item has been previously modified and the compressed data being imported is smaller or equal to the exisiting data * replace the existing data with new data. */ if (inModList && data.Count <= modEntry.modSize) { if (modEntry.modOffset != 0) { int sizeDiff = modEntry.modSize - data.Count; bw.BaseStream.Seek(modEntry.modOffset - datOffsetAmount, SeekOrigin.Begin); bw.Write(data.ToArray()); bw.Write(new byte[sizeDiff]); Helper.UpdateIndex(modEntry.modOffset, internalFilePath, datName); Helper.UpdateIndex2(modEntry.modOffset, internalFilePath, datName); offset = modEntry.modOffset; dataOverwritten = true; } } else { int emptyLength = 0; int emptyLine = 0; /* * If there is an empty entry in the modlist and the compressed data being imported is smaller or equal to the available space * write the compressed data in the existing space. */ try { foreach (string line in File.ReadAllLines(Properties.Settings.Default.Modlist_Directory)) { JsonEntry emptyEntry = JsonConvert.DeserializeObject <JsonEntry>(line); if (emptyEntry.fullPath.Equals("") && emptyEntry.datFile.Equals(datName)) { if (emptyEntry.modOffset != 0) { emptyLength = emptyEntry.modSize; if (emptyLength > data.Count) { int sizeDiff = emptyLength - data.Count; bw.BaseStream.Seek(emptyEntry.modOffset - datOffsetAmount, SeekOrigin.Begin); bw.Write(data.ToArray()); bw.Write(new byte[sizeDiff]); int originalOffset = Helper.UpdateIndex(emptyEntry.modOffset, internalFilePath, datName) * 8; Helper.UpdateIndex2(emptyEntry.modOffset, internalFilePath, datName); if (inModList) { originalOffset = modEntry.originalOffset; JsonEntry replaceOriginalEntry = new JsonEntry() { category = String.Empty, name = "Empty Replacement", fullPath = String.Empty, originalOffset = 0, modOffset = modEntry.modOffset, modSize = modEntry.modSize, datFile = datName }; string[] oLines = File.ReadAllLines(Properties.Settings.Default.Modlist_Directory); oLines[lineNum] = JsonConvert.SerializeObject(replaceOriginalEntry); File.WriteAllLines(Properties.Settings.Default.Modlist_Directory, oLines); } JsonEntry replaceEntry = new JsonEntry() { category = category, name = itemName, fullPath = internalFilePath, originalOffset = originalOffset, modOffset = emptyEntry.modOffset, modSize = emptyEntry.modSize, datFile = datName }; string[] lines = File.ReadAllLines(Properties.Settings.Default.Modlist_Directory); lines[emptyLine] = JsonConvert.SerializeObject(replaceEntry); File.WriteAllLines(Properties.Settings.Default.Modlist_Directory, lines); offset = emptyEntry.modOffset; dataOverwritten = true; break; } } } emptyLine++; } } catch (Exception ex) { FlexibleMessageBox.Show("Error Accessing .modlist File \n" + ex.Message, "ImportTex Error " + Info.appVersion, MessageBoxButtons.OK, MessageBoxIcon.Error); } if (!dataOverwritten) { bw.BaseStream.Seek(0, SeekOrigin.End); while ((bw.BaseStream.Position & 0xFF) != 0) { bw.Write((byte)0); } int eof = (int)bw.BaseStream.Position + data.Count; while ((eof & 0xFF) != 0) { data.AddRange(new byte[16]); eof = eof + 16; } offset = (int)bw.BaseStream.Position + datOffsetAmount; if (offset != 0) { bw.Write(data.ToArray()); } else { FlexibleMessageBox.Show("There was an issue obtaining the .dat4 offset to write data to, try importing again. " + "\n\n If the problem persists, please submit a bug report.", "ImportTex Error " + Info.appVersion, MessageBoxButtons.OK, MessageBoxIcon.Error); } } } } } catch (Exception ex) { FlexibleMessageBox.Show("Error Accessing .dat4 File \n" + ex.Message, "ImportTex Error " + Info.appVersion, MessageBoxButtons.OK, MessageBoxIcon.Error); return(0); } if (!dataOverwritten) { if (offset != 0) { int oldOffset = Helper.UpdateIndex(offset, internalFilePath, datName) * 8; Helper.UpdateIndex2(offset, internalFilePath, datName); /* * If the item has been previously modifed, but the new compressed data to be imported is larger than the existing data * remove the data from the modlist, leaving the offset and size intact for future use */ if (inModList && data.Count > modEntry.modSize && modEntry != null) { oldOffset = modEntry.originalOffset; JsonEntry replaceEntry = new JsonEntry() { category = String.Empty, name = String.Empty, fullPath = String.Empty, originalOffset = 0, modOffset = modEntry.modOffset, modSize = modEntry.modSize, datFile = datName }; string[] lines = File.ReadAllLines(Properties.Settings.Default.Modlist_Directory); lines[lineNum] = JsonConvert.SerializeObject(replaceEntry); File.WriteAllLines(Properties.Settings.Default.Modlist_Directory, lines); } JsonEntry entry = new JsonEntry() { category = category, name = itemName, fullPath = internalFilePath, originalOffset = oldOffset, modOffset = offset, modSize = data.Count, datFile = datName }; try { using (StreamWriter modFile = new StreamWriter(Properties.Settings.Default.Modlist_Directory, true)) { modFile.BaseStream.Seek(0, SeekOrigin.End); modFile.WriteLine(JsonConvert.SerializeObject(entry)); } } catch (Exception ex) { FlexibleMessageBox.Show("Error Accessing .modlist File \n" + ex.Message, "ImportTex Error " + Info.appVersion, MessageBoxButtons.OK, MessageBoxIcon.Error); } } } return(offset); }
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e) { var backgroundWorker = sender as BackgroundWorker; var packListCount = packList.Count; float i = 0; List <string> modFileLines = new List <string>(File.ReadAllLines(Properties.Settings.Default.Modlist_Directory)); try { using (ZipArchive archive = ZipFile.OpenRead(packPath)) { backgroundWorker.ReportProgress(0, "Opening TTMP Data File...\n"); foreach (var entry in archive.Entries) { if (entry.FullName.EndsWith(".mpd")) { var stream = entry.Open(); var remainingPack = packListCount; var currentPack = 0; var prevPack = 0; long newOffset = 0; long offsetSum = 0; List <ModPackItems> pack; long cursor = 0; while (currentPack != packListCount) { prevPack = currentPack; if (remainingPack > 100) { pack = packList.GetRange(currentPack, 100); currentPack += 100; remainingPack -= 100; } else { pack = packList.GetRange(currentPack, remainingPack); currentPack += remainingPack; } backgroundWorker.ReportProgress((int)((i / packListCount) * 100), $"\nReading Entries ({prevPack} - {currentPack}/{packListCount})\n\n"); long totalSize = 0; var modPackBytes = new List <byte>(); foreach (var p in pack) { if (p.mEntry.ModOffset < cursor) { backgroundWorker.ReportProgress((int)((i / packListCount) * 100), $"There was an warning in importing. \nImproper Mod Offset in ModPack for {p.mEntry.Name}. \nUnable to import {p.mEntry.Name}."); continue; } totalSize += p.mEntry.ModSize; var buf = new byte[p.mEntry.ModSize]; while (p.mEntry.ModOffset > cursor) { cursor++; stream.ReadByte(); //seek forward for next offset } stream.Read(buf, 0, buf.Length); cursor += buf.Length; modPackBytes.AddRange(buf); } var uncompBytes = modPackBytes.ToArray(); offsetSum += newOffset; newOffset = totalSize; using (var ms = new MemoryStream(uncompBytes)) { //backgroundWorker.ReportProgress((int)((i / packListCount) * 100), "Reading TTMP Data...\n"); var dataOffset = 0; using (var br = new BinaryReader(ms)) { //backgroundWorker.ReportProgress((int)((i / packListCount) * 100), "Begining Import...\n"); foreach (var mpi in pack) { currentImport = mpi.Name + "...."; backgroundWorker.ReportProgress((int)((i / packListCount) * 100), currentImport); JsonEntry modEntry = null; bool inModList = false; bool overwrite = false; int lineNum = 0; int originalOffset = 0; int offset = 0; byte[] dataBytes = new byte[mpi.mEntry.ModSize]; List <byte> modDataList = new List <byte>(); br.BaseStream.Seek(dataOffset, SeekOrigin.Begin); modDataList.AddRange(br.ReadBytes(mpi.mEntry.ModSize)); try { foreach (var line in modFileLines) { modEntry = JsonConvert.DeserializeObject <JsonEntry>(line); if (modEntry.fullPath.Equals(mpi.mEntry.FullPath)) { inModList = true; break; } lineNum++; } var datNum = int.Parse(Info.ModDatDict[mpi.mEntry.DatFile]); var modDatPath = string.Format(Info.datDir, mpi.mEntry.DatFile, datNum); var fileLength = new FileInfo(modDatPath).Length; while (fileLength + mpi.mEntry.ModSize >= 2000000000) { datNum += 1; modDatPath = string.Format(Info.datDir, mpi.mEntry.DatFile, datNum); if (!File.Exists(modDatPath)) { CreateDat.MakeNewDat(mpi.mEntry.DatFile); } fileLength = new FileInfo(modDatPath).Length; } //is in modlist and size of new mod is less than or equal to existing mod size if (inModList && mpi.mEntry.ModSize <= modEntry.modSize) { int sizeDiff = modEntry.modSize - modDataList.Count; datNum = ((modEntry.modOffset / 8) & 0x0F) / 2; modDatPath = string.Format(Info.datDir, modEntry.datFile, datNum); var datOffsetAmount = 16 * datNum; using (BinaryWriter bw = new BinaryWriter(File.OpenWrite(modDatPath))) { bw.BaseStream.Seek(modEntry.modOffset - datOffsetAmount, SeekOrigin.Begin); bw.Write(modDataList.ToArray()); bw.Write(new byte[sizeDiff]); } Helper.UpdateIndex(modEntry.modOffset, mpi.mEntry.FullPath, mpi.mEntry.DatFile); Helper.UpdateIndex2(modEntry.modOffset, mpi.mEntry.FullPath, mpi.mEntry.DatFile); offset = modEntry.modOffset; overwrite = true; } if (!overwrite) { using (BinaryWriter bw = new BinaryWriter(File.OpenWrite(modDatPath))) { bw.BaseStream.Seek(0, SeekOrigin.End); while ((bw.BaseStream.Position & 0xFF) != 0) { bw.Write((byte)0); } int eof = (int)bw.BaseStream.Position + modDataList.Count; while ((eof & 0xFF) != 0) { modDataList.AddRange(new byte[16]); eof = eof + 16; } var datOffsetAmount = 16 * datNum; offset = (int)bw.BaseStream.Position + datOffsetAmount; if (offset != 0) { bw.Write(modDataList.ToArray()); } else { FlexibleMessageBox.Show("There was an issue obtaining the .dat4 offset to write data to, try importing again. " + "\n\n If the problem persists, please submit a bug report.", "ImportModel Error " + Info.appVersion, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } int oldOffset = Helper.UpdateIndex(offset, mpi.mEntry.FullPath, mpi.mEntry.DatFile) * 8; Helper.UpdateIndex2(offset, mpi.mEntry.FullPath, mpi.mEntry.DatFile); //is in modlist and size of new mod is larger than existing mod size if (inModList && mpi.mEntry.ModSize > modEntry.modSize) { oldOffset = modEntry.originalOffset; JsonEntry replaceEntry = new JsonEntry() { category = String.Empty, name = String.Empty, fullPath = String.Empty, originalOffset = 0, modOffset = modEntry.modOffset, modSize = modEntry.modSize, datFile = mpi.mEntry.DatFile }; modFileLines[lineNum] = JsonConvert.SerializeObject(replaceEntry); File.WriteAllLines(Properties.Settings.Default.Modlist_Directory, modFileLines); } JsonEntry jsonEntry = new JsonEntry() { category = mpi.Category, name = mpi.Name, fullPath = mpi.mEntry.FullPath, originalOffset = oldOffset, modOffset = offset, modSize = mpi.mEntry.ModSize, datFile = mpi.mEntry.DatFile }; try { modFileLines.Add(JsonConvert.SerializeObject(jsonEntry)); File.WriteAllLines(Properties.Settings.Default.Modlist_Directory, modFileLines); } catch (Exception ex) { FlexibleMessageBox.Show("Error Accessing .modlist File \n" + ex.Message, "ImportModel Error " + Info.appVersion, MessageBoxButtons.OK, MessageBoxIcon.Error); } } } catch (Exception ex) { FlexibleMessageBox.Show("There was an error in importing. \n" + ex.Message, "ImportModPack Error " + Info.appVersion, MessageBoxButtons.OK, MessageBoxIcon.Error); Debug.WriteLine(ex.StackTrace); } i++; backgroundWorker.ReportProgress((int)((i / packListCount) * 100), "Done."); dataOffset += mpi.mEntry.ModSize; } } } } stream.Dispose(); stream.Close(); } } } } catch (Exception ex) { FlexibleMessageBox.Show("Error opening TexTools ModPack file. \n" + ex.Message, "ImportModPack Error " + Info.appVersion, MessageBoxButtons.OK, MessageBoxIcon.Error); Debug.WriteLine(ex.StackTrace); } }