/// <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 appendSave(string newFileName, bool attemptOverwrite, int HeadeNameOffset = 34) { string rtValues = ""; string loc = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); //Get info expInfoEndOffset = ExportOffset + Exports.Sum(export => export.header.Length); if (expDataBegOffset < expInfoEndOffset) { expDataBegOffset = expInfoEndOffset; } //List<ExportEntry> unchangedExports = Exports.Where(export => !export.hasChanged || (export.hasChanged && export.Data.Length <= export.DataSize)).ToList(); List <ExportEntry> unchangedExports = Exports.Where(export => !export.hasChanged).ToList(); List <ExportEntry> changedExports; List <ExportEntry> 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(); } int max = Exports.Max(maxExport => maxExport.DataOffset); ExportEntry lastExport = Exports.Find(export => export.DataOffset == max); int lastDataOffset = lastExport.DataOffset + lastExport.DataSize; //byte[] oldName; if (!attemptOverwrite) { int offset = ExportOffset; foreach (ExportEntry export in Exports) { if (!export.hasChanged) { offset += export.header.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].header, 32, 8); } } byte[] oldPCC = new byte[lastDataOffset];//Check whether compressed if (this.bCompressed) { oldPCC = PCCHandler.Decompress(pccFileName).Take(lastDataOffset).ToArray(); } else { using (FileStream oldPccStream = new FileStream(this.pccFileName, FileMode.Open)) { //Read the original data up to the last export oldPccStream.Read(oldPCC, 0, lastDataOffset); } } //Start writing the new file using (FileStream newPCCStream = new FileStream(newFileName, FileMode.Create)) { newPCCStream.Seek(0, SeekOrigin.Begin); //Write the original file up til the last original export (note that this leaves in all the original exports) newPCCStream.Write(oldPCC, 0, lastDataOffset); if (!attemptOverwrite) { //If we're not trying to overwrite then just append all the changed exports foreach (ExportEntry export in changedExports) { export.DataOffset = (int)newPCCStream.Position; export.DataSize = export.Data.Length; newPCCStream.Write(export.Data, 0, export.Data.Length); } } else { //If we are then move to each offset and overwrite the data with the new exports foreach (ExportEntry 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); } //Then move to the end and append the new data //newPCCStream.Position = lastDataOffset; newPCCStream.Seek(lastDataOffset, SeekOrigin.Begin); foreach (ExportEntry export in changedExports) { export.DataOffset = (int)newPCCStream.Position; export.DataSize = export.Data.Length; newPCCStream.Write(export.Data, 0, export.Data.Length); } } //Set the new nameoffset and namecounts NameOffset = (int)newPCCStream.Position; NameCount = Names.Count; //Then write out the namelist foreach (string name in Names) { newPCCStream.WriteValueS32(-(name.Length + 1)); newPCCStream.WriteString(name + "\0", (uint)(name.Length + 1) * 2, Encoding.Unicode); } //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); //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); //update the import list newPCCStream.Seek(ImportOffset, SeekOrigin.Begin); foreach (ImportEntry import in Imports) { newPCCStream.Write(import.header, 0, import.header.Length); } //Finally, update the export list newPCCStream.Seek(ExportOffset, SeekOrigin.Begin); foreach (ExportEntry export in Exports) { newPCCStream.Write(export.header, 0, export.header.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].header, 32, 8); } } } return(rtValues); }
/// <summary> /// save PCCObject to file by reconstruction from data /// </summary> /// <param name="path">full path + file name.</param> /// <param name="compress">true if you want a zlib compressed pcc file.</param> public void saveByReconstructing(string path, bool compress = false) { //load in all data byte[] buff; foreach (ExportEntry e in Exports) { buff = e.Data; } try { this.bCompressed = false; MemoryStream m = new MemoryStream(); m.WriteBytes(header); //name table NameOffset = (int)m.Position; NameCount = Names.Count; foreach (string s in Names) { string text = s; if (!text.EndsWith("\0")) { text += "\0"; } m.Write(BitConverter.GetBytes(-text.Length), 0, 4); foreach (char c in text) { m.WriteByte((byte)c); m.WriteByte(0); } } //import table ImportOffset = (int)m.Position; ImportCount = Imports.Count; foreach (ImportEntry e in Imports) { m.WriteBytes(e.header); } //export table ExportOffset = (int)m.Position; ExportCount = Exports.Count; for (int i = 0; i < Exports.Count; i++) { ExportEntry e = Exports[i]; e.offset = (uint)m.Position; m.WriteBytes(e.header); } //freezone int FreeZoneSize = (int)FreeZoneEnd - (int)FreeZoneStart; FreeZoneStart = (uint)m.Position; m.Write(new byte[FreeZoneSize], 0, FreeZoneSize); FreeZoneEnd = HeaderLength = (uint)m.Position; //export data for (int i = 0; i < Exports.Count; i++) { ExportEntry e = Exports[i]; e.DataOffset = (int)m.Position; e.DataSize = e.Data.Length; m.WriteBytes(e.Data); long pos = m.Position; m.Seek(e.offset + 32, SeekOrigin.Begin); m.Write(BitConverter.GetBytes(e.DataSize), 0, 4); m.Write(BitConverter.GetBytes(e.DataOffset), 0, 4); m.Seek(pos, SeekOrigin.Begin); } //update header m.Seek(0, SeekOrigin.Begin); m.WriteBytes(header); if (compress) { PCCHandler.CompressAndSave(m, path); } else { File.WriteAllBytes(path, m.ToArray()); } } catch (Exception ex) { Console.WriteLine("PCC Save error:\n" + ex.ToString()); } }