Наследование: IExportEntry, ICloneable
Пример #1
0
        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);
        }
Пример #2
0
        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);
        }
Пример #3
0
        /// <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.");
        }
Пример #4
0
        /// <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);
        }