public ME3ExportEntry Clone() { ME3ExportEntry newExport = (ME3ExportEntry)this.MemberwiseClone(); // copy all reference-types vars // now creates new copies of referenced objects newExport.info = (byte[])this.info.Clone(); newExport.Data = (byte[])this.Data.Clone(); return(newExport); }
public void addExport(IExportEntry exportEntry) { if (exportEntry.pccRef != this) { throw new Exception("you cannot add a new export entry from another pcc file, it has invalid references!"); } exportEntry.hasChanged = true; //changing data offset in order to append it at the end of the file ME3ExportEntry lastExport = Exports.Find(export => export.DataOffset == Exports.Max(entry => entry.DataOffset)); int lastOffset = (int)(lastExport.DataOffset + lastExport.Data.Length); exportEntry.DataOffset = (uint)lastOffset; Exports.Add((ME3ExportEntry)exportEntry); }
/// <summary> /// save PCCObject to file. /// </summary> /// <param name="newFileName">set full path + file name.</param> /// <param name="saveCompress">set true if you want a zlib compressed pcc file.</param> public void saveToCprFile(string newFileName = null, bool saveCompress = false) { bool bOverwriteFile = false; if (string.IsNullOrWhiteSpace(newFileName) || newFileName == pccFileName) { bOverwriteFile = true; newFileName = Path.GetFullPath(pccFileName) + ".tmp"; } if (bDLCStored) { saveCompress = false; } using (MemoryStream newPccStream = new MemoryStream()) { //ME3Explorer.DebugOutput.Clear(); DebugOutput.PrintLn("Saving file..."); DebugOutput.PrintLn("writing names list..."); // this condition needs a deeper check. todo... if (bExtraNamesList) { //MessageBox.Show("sono dentro, dimensione extranamelist: " + extraNamesList.Length + " bytes"); newPccStream.Seek(headerSize, SeekOrigin.Begin); newPccStream.Write(extraNamesList, 0, extraNamesList.Length); } //writing names list newPccStream.Seek(NameOffset, SeekOrigin.Begin); NameCount = Names.Count; foreach (string name in Names) { newPccStream.WriteValueS32(-(name.Length + 1)); newPccStream.WriteString(name + "\0", (uint)(name.Length + 1) * 2, Encoding.Unicode); } DebugOutput.PrintLn("writing imports list..."); //writing import infos ImportOffset = (int)newPccStream.Position; ImportCount = Imports.Count; foreach (ME3ImportEntry import in Imports) { newPccStream.Write(import.data, 0, import.data.Length); } //updating general export infos ExportOffset = (int)newPccStream.Position; ExportCount = Exports.Count; expInfoEndOffset = ExportOffset + Exports.Sum(export => export.info.Length); expDataBegOffset = expInfoEndOffset; // WV code stuff... DebugOutput.PrintLn("writing export data..."); int counter = 0; int breaker = Exports.Count / 100; if (breaker == 0) { breaker = 1; } //updating general export infos ExportOffset = (int)newPccStream.Position; ExportCount = Exports.Count; expInfoEndOffset = ExportOffset + Exports.Sum(export => export.info.Length); if (expDataBegOffset < expInfoEndOffset) { expDataBegOffset = expInfoEndOffset; } //writing export data /*newPccStream.Seek(expDataBegOffset, SeekOrigin.Begin); * foreach (ExportEntry export in Exports) * { * //updating info values * export.DataSize = export.Data.Length; * export.DataOffset = (int)newPccStream.Position; * * //writing data * newPccStream.Write(export.Data, 0, export.Data.Length); * }*/ //writing export data List <ME3ExportEntry> unchangedExports = Exports.Where(export => !export.hasChanged || (export.hasChanged && export.Data.Length <= export.DataSize)).ToList(); List <ME3ExportEntry> changedExports = Exports.Where(export => export.hasChanged && export.Data.Length > export.DataSize).ToList(); foreach (ME3ExportEntry export in unchangedExports) { newPccStream.Seek(export.DataOffset, SeekOrigin.Begin); //updating info values export.DataSize = export.Data.Length; //export.DataOffset = (int)newPccStream.Position; export.DataOffset = (uint)newPccStream.Position; //writing data newPccStream.Write(export.Data, 0, export.Data.Length); } ME3ExportEntry lastExport = unchangedExports.Find(export => export.DataOffset == unchangedExports.Max(maxExport => maxExport.DataOffset)); int lastDataOffset = (int)(lastExport.DataOffset + lastExport.DataSize); newPccStream.Seek(lastDataOffset, SeekOrigin.Begin); foreach (ME3ExportEntry export in changedExports) { //updating info values export.DataSize = export.Data.Length; export.DataOffset = (uint)newPccStream.Position; //writing data newPccStream.Write(export.Data, 0, export.Data.Length); } //if (Exports.Any(x => x.Data == null)) // throw new Exception("values null!!"); //writing export info newPccStream.Seek(ExportOffset, SeekOrigin.Begin); foreach (ME3ExportEntry export in Exports) { newPccStream.Write(export.info, 0, export.info.Length); } /*foreach (ExportEntry export in unchangedExports) * { * newPccStream.Write(export.info, 0, export.info.Length); * } * foreach (ExportEntry export in changedExports) * { * newPccStream.Write(export.info, 0, export.info.Length); * }*/ DebugOutput.PrintLn("writing header file..."); //writing header bCompressed = false; newPccStream.Seek(0, SeekOrigin.Begin); newPccStream.Write(header, 0, header.Length); newPccStream.Seek(0, SeekOrigin.Begin); if (saveCompress) { DebugOutput.PrintLn("compressing in zlib format, it may take a while..."); PCCHandler.CompressAndSave(newPccStream, newFileName); } else { using (FileStream outputStream = File.Create(newFileName)) { newPccStream.CopyTo(outputStream); } } } if (bOverwriteFile) { File.Delete(pccFileName); File.Move(newFileName, pccFileName); } DebugOutput.PrintLn(Path.GetFileName(pccFileName) + " has been saved."); }
/// <summary> /// This method is an alternate way of saving PCCs /// Instead of reconstructing the PCC from the data taken, it instead copies across the existing /// data, appends new exports, updates the export list, changes the namelist location and updates the /// value in the header /// </summary> /// <param name="newFileName">The filename to write to</param> /// <param name="attemptOverwrite">Do you wish to attempt to overwrite the existing export</param> public string altSaveToFile(string newFileName, bool attemptOverwrite, int HeadeNameOffset = 34) { DebugOutput.PrintLn("Saving pcc with alternate method."); string rtValues = ""; string loc = KFreonLib.Misc.Methods.GetExecutingLoc(); //Check whether compressed if (this.bCompressed) { KFreonLib.PCCObjects.Misc.PCCDecompress(this.pccFileName); } //Get info expInfoEndOffset = ExportOffset + Exports.Sum(export => export.info.Length); if (expDataBegOffset < expInfoEndOffset) { expDataBegOffset = expInfoEndOffset; } //List<ExportEntry> unchangedExports = Exports.Where(export => !export.hasChanged || (export.hasChanged && export.Data.Length <= export.DataSize)).ToList(); List <ME3ExportEntry> unchangedExports = Exports.Where(export => !export.hasChanged).ToList(); List <ME3ExportEntry> changedExports; List <ME3ExportEntry> replaceExports = null; if (!attemptOverwrite) { //If not trying to overwrite, then select all exports that have been changed changedExports = Exports.Where(export => export.hasChanged).ToList(); //MessageBox.Show("No changed exports = " + changedExports.Count); //throw new NullReferenceException(); } else { //If we are trying to overwrite, then split up the exports that have been changed that can and can't overwrite the originals changedExports = Exports.Where(export => export.hasChanged && export.Data.Length > export.DataSize).ToList(); replaceExports = Exports.Where(export => export.hasChanged && export.Data.Length <= export.DataSize).ToList(); } //ExportEntry lastExport = unchangedExports.Find(export => export.DataOffset == unchangedExports.Max(maxExport => maxExport.DataOffset)); uint max = Exports.Max(maxExport => maxExport.DataOffset); ME3ExportEntry lastExport = Exports.Find(export => export.DataOffset == max); int lastDataOffset = (int)(lastExport.DataOffset + lastExport.DataSize); byte[] oldPCC = new byte[lastDataOffset]; //byte[] oldName; if (!attemptOverwrite) { int offset = ExportOffset; foreach (ME3ExportEntry export in Exports) { if (!export.hasChanged) { offset += export.info.Length; } else { break; } } rtValues += offset.ToString() + " "; using (FileStream stream = new FileStream(loc + "\\exec\\infoCache.bin", FileMode.Append)) { stream.Seek(0, SeekOrigin.End); rtValues += stream.Position + " "; //throw new FileNotFoundException(); stream.Write(changedExports[0].info, 32, 8); } } using (FileStream oldPccStream = new FileStream(this.pccFileName, FileMode.Open)) { //Read the original data up to the last export oldPccStream.Read(oldPCC, 0, lastDataOffset); #region Unused code /* Maybe implement this if I want to directly copy the names across. * Not useful at this time * if (NameOffset == 0x8E) * { * oldName = new byte[ImportOffset - 0x8E]; * oldPccStream.Seek(0x8E, SeekOrigin.Begin); * oldPccStream.Read(oldName, 0, (int)oldPccStream.Length - lastDataOffset); * } * else * { * oldName = new byte[oldPccStream.Length - lastDataOffset]; * oldPccStream.Seek(lastDataOffset, SeekOrigin.Begin); * oldPccStream.Read(oldName, 0, (int)oldPccStream.Length - lastDataOffset); * } * */ #endregion } //Start writing the new file using (FileStream newPCCStream = new FileStream(newFileName, FileMode.Create)) { Console.WriteLine(); Console.WriteLine("Starting Save"); newPCCStream.Seek(0, SeekOrigin.Begin); Console.WriteLine("newPCCStream length: " + newPCCStream.Length); //Write the original file up til the last original export (note that this leaves in all the original exports) newPCCStream.Write(oldPCC, 0, lastDataOffset); Console.WriteLine("OldPCC length: " + oldPCC.Length); Console.WriteLine("lastDataOFfset: " + lastDataOffset); Console.WriteLine("overwriting?: " + attemptOverwrite); if (!attemptOverwrite) { //If we're not trying to overwrite then just append all the changed exports foreach (ME3ExportEntry export in changedExports) { export.DataOffset = (uint)newPCCStream.Position; export.DataSize = export.Data.Length; newPCCStream.Write(export.Data, 0, export.Data.Length); } } else { Console.WriteLine("replaceExports count: " + replaceExports.Count); //If we are then move to each offset and overwrite the data with the new exports foreach (ME3ExportEntry export in replaceExports) { //newPCCStream.Position = export.DataOffset; newPCCStream.Seek(export.DataOffset, SeekOrigin.Begin); export.DataSize = export.Data.Length; newPCCStream.Write(export.Data, 0, export.Data.Length); //Console.WriteLine("exports.DataOffset: " + export.DataOffset); //Console.WriteLine("export datalength: " + export.Data.Length); } //Then move to the end and append the new data //newPCCStream.Position = lastDataOffset; newPCCStream.Seek(lastDataOffset, SeekOrigin.Begin); Console.WriteLine("changedExports count: " + changedExports.Count); foreach (ME3ExportEntry export in changedExports) { export.DataOffset = (uint)newPCCStream.Position; //Console.WriteLine("newstream position: " + newPCCStream.Position); export.DataSize = export.Data.Length; //Console.WriteLine("export size: " + export.DataSize); newPCCStream.Write(export.Data, 0, export.Data.Length); //Console.WriteLine("datalength: " + export.Data.Length); } } //Set the new nameoffset and namecounts NameOffset = (int)newPCCStream.Position; Console.WriteLine("nameoffset: " + NameOffset); NameCount = Names.Count; Console.WriteLine("namecount: " + Names.Count); //Then write out the namelist foreach (string name in Names) { //Console.WriteLine("name: " + name); newPCCStream.WriteValueS32(-(name.Length + 1)); newPCCStream.WriteString(name + "\0", (uint)(name.Length + 1) * 2, Encoding.Unicode); } Console.WriteLine("newPCCStream.length: " + newPCCStream.Length); //Move to the name info position in the header - not a strong piece of code, but it's working so far //newPCCStream.Position = 34; newPCCStream.Seek(HeadeNameOffset, SeekOrigin.Begin); Console.WriteLine("headernameoffset: " + HeadeNameOffset); //And write the new info byte[] nameHeader = new byte[8]; byte[] nameCount = BitConverter.GetBytes(NameCount); byte[] nameOff = BitConverter.GetBytes(NameOffset); for (int i = 0; i < 4; i++) { nameHeader[i] = nameCount[i]; } for (int i = 0; i < 4; i++) { nameHeader[i + 4] = nameOff[i]; } newPCCStream.Write(nameHeader, 0, 8); //Finally, update the export list newPCCStream.Seek(ExportOffset, SeekOrigin.Begin); foreach (ME3ExportEntry export in Exports) { newPCCStream.Write(export.info, 0, export.info.Length); } if (!attemptOverwrite) { using (FileStream stream = new FileStream(loc + "\\exec\\infoCache.bin", FileMode.Append)) { stream.Seek(0, SeekOrigin.End); rtValues += stream.Position + " "; stream.Write(changedExports[0].info, 32, 8); } } } return(rtValues); }