/// <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 = "";


            //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);
                }
            }
            return(rtValues);
        }
Esempio n. 2
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 saveToFile(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 (ImportEntry 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 <ExportEntry> unchangedExports = Exports.Where(export => !export.hasChanged || (export.hasChanged && export.Data.Length <= export.DataSize)).ToList();
                List <ExportEntry> changedExports   = Exports.Where(export => export.hasChanged && export.Data.Length > export.DataSize).ToList();

                foreach (ExportEntry export in unchangedExports)
                {
                    newPccStream.Seek(export.DataOffset, SeekOrigin.Begin);
                    //updating info values
                    export.DataSize   = export.Data.Length;
                    export.DataOffset = (int)newPccStream.Position;

                    //writing data
                    newPccStream.Write(export.Data, 0, export.Data.Length);
                }

                ExportEntry lastExport     = unchangedExports.Find(export => export.DataOffset == unchangedExports.Max(maxExport => maxExport.DataOffset));
                int         lastDataOffset = lastExport.DataOffset + lastExport.DataSize;

                newPccStream.Seek(lastDataOffset, SeekOrigin.Begin);
                foreach (ExportEntry export in changedExports)
                {
                    //updating info values
                    export.DataSize   = export.Data.Length;
                    export.DataOffset = (int)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 (ExportEntry 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>
        ///     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;
            }

            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());
            }
        }