private void editFilesizeToolStripMenuItem_Click(object sender, EventArgs e) { int n = listBox1.SelectedIndex; if (n == -1) { return; } string newsize = Microsoft.VisualBasic.Interaction.InputBox("Enter new size in bytes", "ME3 Explorer", content[n].size.ToString()); Inventory temp = content[n]; try { temp.size = Convert.ToUInt32(newsize); } catch (FormatException) { //exit this method return; } content[n] = temp; listBox1.Items.Clear(); uint pos = temp.offset; byte[] buff = BitConverter.GetBytes(temp.size); for (int i = 0; i < 4; i++) { memory[pos + i] = buff[i]; } for (int i = 0; i < content.Count(); i++) { listBox1.Items.Add(content[i].offset.ToString("X") + " : " + content[i].name + " (bytes)" + content[i].size.ToString()); } listBox1.SelectedIndex = n; }
/// <summary> /// Starts reading 'Bits' array at position 'bitOffset'. Read data is /// used on a Huffman Tree to decode read bits into real strings. /// 'bitOffset' variable is updated with last read bit PLUS ONE (first unread bit). /// </summary> /// <param name="bitOffset"></param> /// <returns> /// decoded string or null if there's an error (last string's bit code is incomplete) /// </returns> /// <remarks> /// Global variables used: /// List(of HuffmanNodes) CharacterTree /// BitArray Bits /// </remarks> private string GetString(ref int bitOffset) { HuffmanNode root = CharacterTree[0]; HuffmanNode curNode = root; string curString = ""; int i; for (i = bitOffset; i < Bits.Length; i++) { /* reading bits' sequence and decoding it to Strings while traversing Huffman Tree */ int nextNodeID; if (Bits[i]) { nextNodeID = curNode.RightNodeID; } else { nextNodeID = curNode.LeftNodeID; } /* it's an internal node - keep looking for a leaf */ if (nextNodeID >= 0) { curNode = CharacterTree[nextNodeID]; } else /* it's a leaf! */ { char c = BitConverter.ToChar(BitConverter.GetBytes(0xffff - nextNodeID), 0); if (c != '\0') { /* it's not NULL */ curString += c; curNode = root; } else { /* it's a NULL terminating processed string, we're done */ bitOffset = i + 1; return(curString); } } } bitOffset = i + 1; return(null); }
public bool UpdateFile(string name, uint size, string path) { loadTOCfile(path); int n = -1; for (int i = 0; i < content.Count(); i++) { if (content[i].name.EndsWith(name)) { n = i; } } if (n == -1) { return(false); } //edit entry Inventory temp = content[n]; temp.size = size; content[n] = temp; uint pos = temp.offset; BitConverter.IsLittleEndian = true; byte[] buff = BitConverter.GetBytes(size); for (int i = 0; i < 4; i++) { memory[pos + i] = buff[i]; } //write file FileStream fileStream = new FileStream(path, FileMode.Create, FileAccess.Write); for (int i = 0; i < memsize; i++) { fileStream.WriteByte(memory[i]); } fileStream.Close(); return(true); }
public void ME3PCCObjectHelper(MemoryStream tempStream, string filePath, bool TablesOnly) { tempStream.Seek(0, SeekOrigin.Begin); DataStream = new MemoryStream(); tempStream.WriteTo(DataStream); Names = new List <string>(); Imports = new List <ME3ImportEntry>(); Exports = new List <ME3ExportEntry>(); header = tempStream.ReadBytes(headerSize); if (magic != ZBlock.magic && magic.Swap() != ZBlock.magic) { throw new FormatException(filePath + " is not a pcc file"); } if (lowVers != 684 && highVers != 194) { throw new FormatException("unsupported version"); } if (bCompressed) { // seeks the blocks info position tempStream.Seek(idxOffsets + 60, SeekOrigin.Begin); int generator = tempStream.ReadValueS32(); tempStream.Seek((generator * 12) + 20, SeekOrigin.Current); int blockCount = tempStream.ReadValueS32(); blockList = new List <Block>(); // creating the Block list for (int i = 0; i < blockCount; i++) { Block temp = new Block(); temp.uncOffset = tempStream.ReadValueS32(); temp.uncSize = tempStream.ReadValueS32(); temp.cprOffset = tempStream.ReadValueS32(); temp.cprSize = tempStream.ReadValueS32(); blockList.Add(temp); } // correcting the header, in case there's need to be saved Buffer.BlockCopy(BitConverter.GetBytes(0), 0, header, header.Length - 12, sizeof(int)); tempStream.Read(header, header.Length - 8, 8); headerEnd = (int)tempStream.Position; // copying the extraNamesList int extraNamesLenght = blockList[0].cprOffset - headerEnd; if (extraNamesLenght > 0) { extraNamesList = new byte[extraNamesLenght]; tempStream.Read(extraNamesList, 0, extraNamesLenght); //FileStream fileStream = File.Create(Path.GetDirectoryName(pccFileName) + "\\temp.bin"); //fileStream.Write(extraNamesList, 0, extraNamesLenght); //MessageBox.Show("posizione: " + pccStream.Position.ToString("X8")); } int dataStart = 0; using (MemoryStream he = new MemoryStream(header)) { he.Seek(0, SeekOrigin.Begin); he.ReadValueS32(); he.ReadValueS32(); dataStart = he.ReadValueS32(); } if (TablesOnly) { int TableStart = 0; for (int m = 0; m < blockList.Count; m++) { if (blockList[m].uncOffset + blockList[m].uncSize > dataStart) { TableStart = m; break; } } listsStream = new MemoryStream(); tempStream.Seek(blockList[TableStart].cprOffset, SeekOrigin.Begin); listsStream.Seek(blockList[TableStart].uncOffset, SeekOrigin.Begin); listsStream.WriteBytes(ZBlock.Decompress(tempStream, blockList[TableStart].cprSize)); DataStream = new MemoryStream(); tempStream.WriteTo(DataStream); bCompressed = true; } else { //Decompress ALL blocks listsStream = new MemoryStream(); for (int i = 0; i < blockCount; i++) { tempStream.Seek(blockList[i].cprOffset, SeekOrigin.Begin); listsStream.Seek(blockList[i].uncOffset, SeekOrigin.Begin); listsStream.WriteBytes(ZBlock.Decompress(tempStream, blockList[i].cprSize)); } } bCompressed = false; } else { listsStream = new MemoryStream(); listsStream.WriteBytes(tempStream.ToArray()); } tempStream.Dispose(); //Fill name list listsStream.Seek(NameOffset, SeekOrigin.Begin); for (int i = 0; i < NameCount; i++) { int strLength = listsStream.ReadValueS32(); Names.Add(listsStream.ReadString(strLength * -2, true, Encoding.Unicode)); } // fill import list listsStream.Seek(ImportOffset, SeekOrigin.Begin); byte[] buffer = new byte[ME3ImportEntry.byteSize]; for (int i = 0; i < ImportCount; i++) { Imports.Add(new ME3ImportEntry(this, listsStream)); } //fill export list listsStream.Seek(ExportOffset, SeekOrigin.Begin); for (int i = 0; i < ExportCount; i++) { uint expInfoOffset = (uint)listsStream.Position; listsStream.Seek(44, SeekOrigin.Current); int count = listsStream.ReadValueS32(); listsStream.Seek(-48, SeekOrigin.Current); int expInfoSize = 68 + (count * 4); buffer = new byte[expInfoSize]; listsStream.Read(buffer, 0, buffer.Length); Exports.Add(new ME3ExportEntry(this, buffer, expInfoOffset)); } }
/// <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); }