예제 #1
0
        /// <summary>
        /// Rename the filename, this does not set the fileid for all the qb types
        /// </summary>
        /// <param name="qbFilename">Source full filename.</param>
        /// <param name="newFullQbFilename">Full QB filename</param>
        /// <param name="fileType">.qb or .sqb=QB, .mqb=mid, .img=img .dbg=dbg  etc</param>
        /// <param name="extension">.qb.ngc for Wii for example</param>
        public void RenameFile(string qbFilename, string newQbFilename, QbKey itemType)
        {
            PakHeaderItem phi = _pakHeaders[qbFilename.ToLower()];

            phi.SetFilename(newQbFilename, itemType, _pakFormat.FileExtension, phi);

            using (BinaryEndianWriter bw = new BinaryEndianWriter(File.OpenWrite(_pakFormat.FullPakFilename)))
            {
                bw.BaseStream.Seek(phi.HeaderStart, SeekOrigin.Begin);
                writeHeaderItem(bw, phi);
            }

            //update the filename in the collection
            Dictionary <string, PakHeaderItem> p = new Dictionary <string, PakHeaderItem>(_pakHeaders.Count);

            foreach (PakHeaderItem ph in _pakHeaders.Values)
            {
                p.Add(ph.Filename.ToLower(), ph);
            }

            _pakHeaders = p;

            if (phi.PakFileType == PakItemType.Qb || phi.PakFileType == PakItemType.Sqb || phi.PakFileType == PakItemType.Midi)
            {
                try
                {
                    QbFile qbf = ReadQbFile(newQbFilename);
                    qbf.SetNewFileId();
                    ReplaceFile(newQbFilename, qbf);
                }
                catch
                {
                }
            }
        }
예제 #2
0
        public void ExtractFile(string qbFilename, Stream stream)
        {
            //open input pak
            string fname;
            long   offset;

            if (_pakHeaders.ContainsKey(qbFilename.ToLower()))
            {
                PakHeaderItem phi = _pakHeaders[qbFilename.ToLower()];
                //open output
                if (_debugFile)
                {
                    fname  = _pakFormat.FullDebugFilename;
                    offset = phi.HeaderStart + phi.FileOffset;
                }
                else if (_requiresPab)
                {
                    fname  = _pakFormat.FullPabFilename;
                    offset = (phi.HeaderStart + phi.FileOffset) - (new FileInfo(_pakFormat.FullPakFilename)).Length;
                }
                else
                {
                    fname  = _pakFormat.FullPakFilename;
                    offset = phi.HeaderStart + phi.FileOffset;
                }

                using (BinaryWriter bw = new BinaryWriter(stream))
                {
                    //open input pak
                    using (FileStream fsPak = File.Open(fname, FileMode.Open, FileAccess.ReadWrite))
                    {
                        if ((offset + phi.FileLength) - 1 > fsPak.Length)
                        {
                            throw new ApplicationException(string.Format("End of file '{0}' is located at 0x{1} which is beyond the PAK/PAB size 0x{2}", qbFilename, (offset + phi.FileLength).ToString("X").PadLeft(8, '0'), fsPak.Length.ToString("X").PadLeft(8, '0')));
                        }

                        using (BinaryReader brPak = new BinaryReader(fsPak))
                        {
                            fsPak.Seek(offset, SeekOrigin.Begin);
                            copyData(fsPak, stream, (long)phi.FileLength);
                        }
                    }
                }
            }
            else
            {
                throw new ApplicationException(string.Format("'{0}' does not exist in '{1}'", qbFilename, _pakFilename));
            }
        }
예제 #3
0
        public QbFile ReadQbFile(string qbFilename, string debugFileContents)
        {
            if (_pakHeaders.ContainsKey(qbFilename.ToLower()))
            {
                PakHeaderItem phi = _pakHeaders[qbFilename.ToLower()];
                //open input pak
                string fname;
                long   offset;

                if (_debugFile)
                {
                    fname  = _pakFormat.FullDebugFilename;
                    offset = phi.HeaderStart + phi.FileOffset;
                }
                else if (_requiresPab)
                {
                    fname  = _pakFormat.FullPabFilename;
                    offset = (phi.HeaderStart + phi.FileOffset) - (new FileInfo(_pakFormat.FullPakFilename)).Length;
                }
                else
                {
                    fname  = _pakFormat.FullPakFilename;
                    offset = phi.HeaderStart + phi.FileOffset;
                }

                using (FileStream fsPak = File.Open(fname, FileMode.Open, FileAccess.Read))
                {
                    if ((offset + phi.FileLength) - 1 > fsPak.Length)
                    {
                        throw new ApplicationException(string.Format("End of file '{0}' is located at 0x{1} which is beyond the PAK/PAB size 0x{2}", qbFilename, (offset + phi.FileLength).ToString("X").PadLeft(8, '0'), fsPak.Length.ToString("X").PadLeft(8, '0')));
                    }

                    fsPak.Seek(offset, SeekOrigin.Begin);
                    return(new QbFile(qbFilename, debugFileContents, fsPak, _pakFormat)); //doesn't matter if debug file is empty
                }
            }
            else
            {
                throw new ApplicationException(string.Format("'{0}' does not exist in '{1}'", qbFilename, _pakFilename));
            }
        }
예제 #4
0
        private void writeHeaderItem(BinaryEndianWriter bwPakO, PakHeaderItem ph)
        {
            bwPakO.Write(ph.FileType.Crc, _pakFormat.EndianType);

            uint offset = ph.FileOffset;

            if (_requiresPab)
            {
                offset = (uint)_pakFormat.PakPabMinDataOffset + ((_pakFormat.PakPabMinDataOffset == 0 ? ph.HeaderStart : 0) + ph.FileOffset) - (uint)_pakFileLength;
            }

            bwPakO.Write(offset, _pakFormat.EndianType);
            bwPakO.Write(ph.FileLength, _pakFormat.EndianType);
            bwPakO.Write(ph.PakFullFileNameQbKey, _pakFormat.EndianType);
            bwPakO.Write(ph.FullFilenameQbKey, _pakFormat.EndianType);
            bwPakO.Write(ph.NameOnlyCrc, _pakFormat.EndianType);
            bwPakO.Write(ph.Unknown, _pakFormat.EndianType);
            bwPakO.Write((uint)ph.Flags, _pakFormat.EndianType);

            if ((ph.Flags & PakHeaderFlags.Filename) == PakHeaderFlags.Filename)
            {
                bwPakO.Write(Encoding.UTF8.GetBytes(ph.PaddedFileName), 0, PakHeaderItem.FileNameMaxLength);
            }
        }
예제 #5
0
        /// <summary>
        /// Rename the filename and set the data types
        /// </summary>
        /// <param name="newFullQbFilename">Full QB filename</param>
        /// <param name="fileType">.qb or .sqb=QB, .mqb=mid, .img=img .dbg=dbg  etc</param>
        /// <param name="extension">.ngc for Wii for example</param>
        /// <param name="baseOn">base the qbKeys that are present on the passed item</param>
        public void SetFilename(string newFullQbFilename, QbKey itemType, string extension, PakHeaderItem baseOn)
        {
            if (newFullQbFilename.Length > PakHeaderItem.FileNameMaxLength)
                throw new ApplicationException("newQbFilename is too long");

            if (!itemType.HasText || itemType.Text.Length == 0)
                throw new ApplicationException("fileType is not recognised");

            //filename is stored in the header
            if ((this.Flags & PakHeaderFlags.Filename) == PakHeaderFlags.Filename)
            {
                this.Filename = newFullQbFilename;
                this.FullFilenameQbKey = 0;
            }
            else
            {
                this.Filename = QbKey.Create(newFullQbFilename).Crc.ToString("X").PadLeft(8, '0').ToLower();

                if (baseOn == null || baseOn.FullFilenameQbKey != 0)
                    this.FullFilenameQbKey = QbKey.Create(newFullQbFilename).Crc;
                else
                    this.FullFilenameQbKey = 0;
            }

            string[] pts = newFullQbFilename.Split('.');

            string nameOnly = pts[0];

            if (baseOn == null || baseOn.FullFilenameQbKey != 0)
                this.NameOnlyCrc = QbKey.Create(nameOnly).Crc;
            else
                this.NameOnlyCrc = 0;

            this.FileType = itemType;

            if (baseOn == null || baseOn.PakFullFileNameQbKey != 0)
                this.PakFullFileNameQbKey = QbKey.Create(newFullQbFilename).Crc;
            else
                this.PakFullFileNameQbKey = 0;
        }
예제 #6
0
        /// <summary>
        /// Rename the filename and set the data types
        /// </summary>
        /// <param name="newFullQbFilename">Full QB filename</param>
        /// <param name="fileType">.qb or .sqb=QB, .mqb=mid, .img=img .dbg=dbg  etc</param>
        /// <param name="extension">.ngc for Wii for example</param>
        /// <param name="baseOn">base the qbKeys that are present on the passed item</param>
        public void SetFilename(string newFullQbFilename, QbKey itemType, string extension, PakHeaderItem baseOn)
        {
            if (newFullQbFilename.Length > PakHeaderItem.FileNameMaxLength)
            {
                throw new ApplicationException("newQbFilename is too long");
            }

            if (!itemType.HasText || itemType.Text.Length == 0)
            {
                throw new ApplicationException("fileType is not recognised");
            }

            //filename is stored in the header
            if ((this.Flags & PakHeaderFlags.Filename) == PakHeaderFlags.Filename)
            {
                this.Filename          = newFullQbFilename;
                this.FullFilenameQbKey = 0;
            }
            else
            {
                this.Filename = QbKey.Create(newFullQbFilename).Crc.ToString("X").PadLeft(8, '0').ToLower();

                if (baseOn == null || baseOn.FullFilenameQbKey != 0)
                {
                    this.FullFilenameQbKey = QbKey.Create(newFullQbFilename).Crc;
                }
                else
                {
                    this.FullFilenameQbKey = 0;
                }
            }

            string[] pts = newFullQbFilename.Split('.');

            string nameOnly = pts[0];

            if (baseOn == null || baseOn.FullFilenameQbKey != 0)
            {
                this.NameOnlyCrc = QbKey.Create(nameOnly).Crc;
            }
            else
            {
                this.NameOnlyCrc = 0;
            }


            this.FileType = itemType;

            if (baseOn == null || baseOn.PakFullFileNameQbKey != 0)
            {
                this.PakFullFileNameQbKey = QbKey.Create(newFullQbFilename).Crc;
            }
            else
            {
                this.PakFullFileNameQbKey = 0;
            }
        }
예제 #7
0
 private bool pakItemExists(string qbFilename, PakHeaderItem exclude)
 {
     string fn = qbFilename.ToLower();
     QbKey qk = QbKey.Create(fn);
     foreach (PakHeaderItem phi in _pakFile.Headers.Values)
     {
         if (exclude != null && exclude == phi)
             continue;
         if (fn == phi.Filename.ToLower() || phi.PakFullFileNameQbKey == qk.Crc)
             return true;
     }
     return false;
 }
예제 #8
0
        private void replaceFile(string qbFilename, long newLength, bool remove, WriteDataToStream callback)
        {
            int filePad = _pakFormat.FilePadSize;

            PakHeaderItem phi = null;

            if (_pakHeaders.ContainsKey(qbFilename.ToLower()))
            {
                phi = _pakHeaders[qbFilename.ToLower()];
            }
            else
            {
                string fqk = QbKey.Create(qbFilename).Crc.ToString("X").PadLeft(8, '0').ToLower();

                if (_pakHeaders.ContainsKey(fqk))
                {
                    phi = _pakHeaders[fqk];
                }
            }

            if (phi != null)
            {
                long pad = filePad - (newLength % filePad);
                if (pad == filePad)
                {
                    pad = 0;
                }

                string newPakFilename = string.Format("{0}_{1}", _pakFormat.FullPakFilename, Guid.NewGuid().ToString("N"));
                string newPabFilename = string.Format("{0}_{1}", _pakFormat.FullPabFilename, Guid.NewGuid().ToString("N"));

                uint minOffset  = uint.MaxValue;
                bool itemFound  = false;
                uint nextOffset = 0;

                foreach (PakHeaderItem ph in _pakHeaders.Values)
                {
                    if (itemFound)
                    {
                        nextOffset = ph.FileOffset + ph.HeaderStart;
                        itemFound  = false; //don't enter this if again
                    }

                    if (object.ReferenceEquals(phi, ph))
                    {
                        itemFound = true;
                    }

                    if (ph.HeaderStart + ph.FileOffset < minOffset)
                    {
                        minOffset = ph.HeaderStart + ph.FileOffset;
                    }
                }

                uint lastItemPad = 0;
                int  repPad      = filePad - ((int)phi.FileLength % filePad);
                if (repPad == filePad)
                {
                    repPad = 0;
                }

                //previously badly padded or last file
                if (nextOffset != 0 && (nextOffset - (phi.FileOffset + phi.HeaderStart)) % filePad != 0)
                {
                    repPad = (int)((nextOffset - (phi.FileOffset + phi.HeaderStart)) - phi.FileLength);
                }


                //position of the LAST header item
                long lastHeaderPos = 0;
                //the length of all the headers (like pak when there's a pab) with padding
                long allHeadersLen = minOffset;
                //position in the input file where our file is to be replaced (not including header pos)
                long fileReplacePos = (phi.HeaderStart + phi.FileOffset) - allHeadersLen;
                //position in the input file after the file that is to be replaced
                long fileAfterReplacePos = fileReplacePos + phi.FileLength + repPad; //item size before modifying header

                //open input pak
                using (FileStream fsPakI = File.Open(_pakFilename, FileMode.Open, FileAccess.Read))
                {
                    using (BinaryEndianReader brPakI = new BinaryEndianReader(fsPakI))
                    {
                        //open output pak temp file
                        using (FileStream fsPakO = File.Create(newPakFilename))
                        {
                            using (BinaryEndianWriter bwPakO = new BinaryEndianWriter(fsPakO))
                            {
                                long diffLen = 0;

                                //do not compensate for missing header when using zlib compression as the header is padded
                                if (remove && _pakFormat.CompressionType != CompressionType.ZLibChunk) //we need to cater for the header being removed on all items before it.
                                {
                                    diffLen = PakHeaderItem.FullHeaderLength;
                                    if ((phi.Flags & PakHeaderFlags.Filename) != PakHeaderFlags.Filename)
                                    {
                                        diffLen -= PakHeaderItem.FileNameMaxLength;
                                    }
                                }


                                //write out the headers
                                foreach (PakHeaderItem ph in _pakHeaders.Values)
                                {
                                    //apply offset change before finding file to be replaced
                                    //this will prevents the offset of the replaced file being changed
                                    ph.FileOffset = (uint)(ph.FileOffset - (long)diffLen);
                                    if (object.ReferenceEquals(phi, ph))
                                    {
                                        if (remove)
                                        {
                                            long remPad = filePad - (phi.FileLength % filePad);
                                            if (remPad == filePad)
                                            {
                                                remPad = 0;
                                            }

                                            diffLen = phi.FileLength + remPad; //now cater for the difference in file size
                                        }
                                        else
                                        {
                                            diffLen       = (long)((ph.FileLength + repPad) - (newLength + pad));
                                            ph.FileLength = (uint)newLength; //0 for remove
                                        }
                                    }

                                    lastHeaderPos += PakHeaderItem.FullHeaderLength;

                                    if (!(remove && object.ReferenceEquals(phi, ph)))
                                    {
                                        writeHeaderItem(bwPakO, ph);
                                    }


                                    if ((ph.Flags & PakHeaderFlags.Filename) != PakHeaderFlags.Filename)
                                    {
                                        lastHeaderPos -= PakHeaderItem.FileNameMaxLength;
                                    }
                                }

                                //Move to the "last" header
                                fsPakI.Seek(lastHeaderPos, SeekOrigin.Begin);

                                //write out "last" HeaderType
                                bwPakO.Write(brPakI.ReadBytes(4));

                                //Modify and write the offset of the "last" header's data
                                uint lastOffset = brPakI.ReadUInt32(_pakFormat.EndianType);
                                lastOffset = (uint)(lastOffset - (long)diffLen);

                                //fix bad padding on last file
                                if (nextOffset == 0 && ((lastOffset - (phi.FileOffset + phi.HeaderStart) % filePad) % filePad) != 0)
                                {
                                    lastItemPad = (uint)filePad - (uint)(lastOffset % filePad);
                                    lastOffset += lastItemPad;
                                }

                                bwPakO.Write(lastOffset, _pakFormat.EndianType);

                                //write out the end of the last header
                                copyData(fsPakI, fsPakO, allHeadersLen - fsPakI.Position);
                            }
                        }
                    }
                }

                //open input pak
                using (FileStream fsPakI = File.Open(_requiresPab ? _pakFormat.FullPabFilename : _pakFilename, FileMode.Open, FileAccess.Read))
                {
                    using (BinaryEndianReader brPakI = new BinaryEndianReader(fsPakI))
                    {
                        //open output pak temp file
                        using (FileStream fsPakO = _requiresPab ? File.Open(newPabFilename, FileMode.Create) : File.Open(newPakFilename, FileMode.Append))
                        {
                            using (BinaryEndianWriter bwPakO = new BinaryEndianWriter(fsPakO))
                            {
                                if (!_requiresPab)
                                {
                                    fsPakI.Seek(allHeadersLen, SeekOrigin.Begin);
                                }

                                //Write out the data starting from the last header to the start of the file to be replaced (minus the length of the type and offset)
                                copyData(fsPakI, fsPakO, fileReplacePos);

                                //Write the new file into the pak file
                                int pos = (int)fsPakO.Position;
                                callback(fsPakO);
                                if (pad != 0)
                                {
                                    fsPakO.Write(new byte[pad], 0, (int)pad);
                                }

                                if (!_requiresPab)
                                {
                                    fileAfterReplacePos += allHeadersLen;
                                }

                                if (lastItemPad != 0)
                                {
                                    fileAfterReplacePos -= lastItemPad; // a bit of a hack as this was not applied when this var was set as we didn't know the values
                                }
                                //write the remainder of source the pak file
                                fsPakI.Seek(fileAfterReplacePos, SeekOrigin.Begin);
                                copyData(fsPakI, fsPakO, fsPakI.Length - fileAfterReplacePos);

                                fsPakO.Flush();
                            }
                        }
                    }
                }

                fixUncompressedFileLengths(newPakFilename, newPabFilename);


                File.Delete(_pakFilename);
                File.Move(newPakFilename, _pakFilename);
                if (_requiresPab)
                {
                    File.Delete(_pakFormat.FullPabFilename);
                    File.Move(newPabFilename, _pakFormat.FullPabFilename);
                }


                _pakFormat.Compress();
            }
            else
            {
                throw new ApplicationException(string.Format("'{0}' does not exist in '{1}'", qbFilename, _pakFilename));
            }
        }
예제 #9
0
        private void parsePak(PakFormat pakFormat, bool debugFile)
        {
            _debugFile   = debugFile;
            _pakFormat   = pakFormat;
            _pakFilename = (!_debugFile ? _pakFormat.FullPakFilename : _pakFormat.FullDebugFilename);

            Dictionary <uint, PakDbgQbKey> qbKeyFilenames = new Dictionary <uint, PakDbgQbKey>();

            //if PC or xbox then we need to look up the filename from the debug file
            //create a PakEditor and load the debug pak, then load all internal debug files, add the first line to our filenames dictionary
            if (!debugFile) // && (_pakFormat.PakFormatType == PakFormatType.PC || _pakFormat.PakFormatType == PakFormatType.XBox))
            {
                try
                {
                    _pakFormat.Decompress();
                    _pakFilename = _pakFormat.FullPakFilename;
                }
                catch (Exception ex)
                {
                    throw new Exception("Decompression Error", ex);
                }


                if (_pakFormat.DebugFileExists && _debugFile) // cancer
                {
                    string    debugFileContents;
                    string    filename;
                    uint      crc;
                    PakEditor pakDebug = new PakEditor(new PakFormat(_pakFormat.FullDebugFilename, "", _pakFormat.FullDebugFilename, _pakFormat.PakFormatType), true);
                    foreach (PakHeaderItem dphi in pakDebug.Headers.Values)
                    {
                        debugFileContents = string.Empty;
                        filename          = string.Empty;
                        crc = 0;
                        if (dphi.FullFilenameQbKey != 0)
                        {
                            crc = dphi.FullFilenameQbKey;
                        }
                        else if (dphi.PakFullFileNameQbKey != 0)
                        {
                            crc = dphi.PakFullFileNameQbKey;
                        }
                        else if (dphi.NameOnlyCrc != 0)
                        {
                            crc = dphi.NameOnlyCrc;
                        }

                        if (crc != 0)
                        {
                            filename = crc.ToString("X").PadLeft(8, '0');
                            if (pakDebug.Headers.ContainsKey(filename.ToLower()))
                            {
                                debugFileContents = pakDebug.ExtractFileToString(filename);

                                if (debugFileContents.Length != 0)
                                {
                                    addDebugFilename(debugFileContents, qbKeyFilenames, crc);
                                }
                            }
                        }
                    }
                }
            }

            long minOffset = uint.MaxValue;
            long maxOffset = 0;

            _pakHeaders = new Dictionary <string, PakHeaderItem>();

            using (Stream st = File.Open(_pakFilename, FileMode.Open, FileAccess.Read))
            {
                _pakFileLength = st.Length;

                using (BinaryEndianReader br = new BinaryEndianReader(st))
                {
                    PakHeaderItem phi = null;

                    QbKey lastQbKey    = QbKey.Create("last");
                    QbKey dotLastQbKey = QbKey.Create(".last");

                    do
                    {
                        phi = new PakHeaderItem();

                        phi.HeaderStart   = (uint)st.Position;
                        phi.IsStoredInPak = true;

                        phi.FileType = QbKey.Create(br.ReadUInt32(_pakFormat.EndianType));

                        //if the entry has the file type of last then we're done
                        if (phi.FileType == lastQbKey || phi.FileType == dotLastQbKey)
                        {
                            break;
                        }

                        phi.FileOffset           = br.ReadUInt32(_pakFormat.EndianType);
                        phi.FileLength           = br.ReadUInt32(_pakFormat.EndianType);
                        phi.PakFullFileNameQbKey = br.ReadUInt32(_pakFormat.EndianType);
                        phi.FullFilenameQbKey    = br.ReadUInt32(_pakFormat.EndianType);
                        phi.NameOnlyCrc          = br.ReadUInt32(_pakFormat.EndianType);
                        phi.Unknown = br.ReadUInt32(_pakFormat.EndianType);
                        phi.Flags   = (PakHeaderFlags)br.ReadUInt32(_pakFormat.EndianType);

                        if ((phi.Flags & PakHeaderFlags.Filename) != PakHeaderFlags.Filename)
                        {
                            uint crc = 0;

                            //get any Crc
                            if (phi.FullFilenameQbKey != 0)
                            {
                                crc = phi.FullFilenameQbKey;
                            }
                            else if (phi.PakFullFileNameQbKey != 0)
                            {
                                crc = phi.PakFullFileNameQbKey;
                            }
                            else if (phi.NameOnlyCrc != 0)
                            {
                                crc = phi.NameOnlyCrc;
                            }

                            if (!debugFile)
                            {
                                uint crc2 = 0;
                                //get a crc that exists in the debug names
                                if (qbKeyFilenames.ContainsKey(phi.FullFilenameQbKey))
                                {
                                    crc2 = phi.FullFilenameQbKey;
                                }
                                else if (qbKeyFilenames.ContainsKey(phi.PakFullFileNameQbKey))
                                {
                                    crc2 = phi.PakFullFileNameQbKey;
                                }
                                else if (qbKeyFilenames.ContainsKey(phi.NameOnlyCrc))
                                {
                                    crc2 = phi.NameOnlyCrc;
                                }

                                //if 0 then get any crc
                                if (crc2 != 0)
                                {
                                    phi.Filename   = qbKeyFilenames[crc2].Filename;
                                    phi.DebugQbKey = qbKeyFilenames[crc2].DebugQbKey;
                                    crc            = crc2;
                                }
                            }

                            if (phi.Filename == null)
                            {
                                if (crc != 0)
                                {
                                    phi.Filename = crc.ToString("X").PadLeft(8, '0');
                                }
                                else
                                {
                                    phi.Filename = string.Format("Unknown={0}", phi.HeaderStart.ToString("X").PadLeft(8, '0'));
                                }
                            }
                        }
                        else
                        {
                            phi.Filename = UTF8Encoding.UTF8.GetString(br.ReadBytes(PakHeaderItem.FileNameMaxLength)).TrimEnd(new char[] { '\0' });
                        }

                        try
                        {
                            _pakHeaders.Add(phi.Filename.ToLower(), phi);
                        }
                        catch (Exception ex)
                        {
                            throw new ApplicationException(string.Format("Error adding '{0}' to headers: {1}", phi.Filename, ex.Message));
                        }

                        if (phi.HeaderStart + phi.FileOffset < minOffset)
                        {
                            minOffset = phi.HeaderStart + phi.FileOffset;
                        }

                        if (phi.HeaderStart + phi.FileOffset > maxOffset)
                        {
                            maxOffset = phi.HeaderStart + phi.FileOffset;
                        }
                    }while (1 == 1); //minOffset > fs.Position + 0x100); //drop out if we reach the data



                    //this is a simple hack/fix to cater for padding on PAK files,
                    //it relies on the data starting at the top of the PAB file (which it always does, currently)
                    _requiresPab = maxOffset >= st.Length;

                    if (!debugFile)                                 //only when loading pak
                    {
                        _pakFormat.PakPabMinDataOffset = minOffset; //remember this value
                    }
                    //detect GH5 PAB files
                    if (_requiresPab)
                    {
                        foreach (PakHeaderItem ph in _pakHeaders.Values)
                        {
                            ph.FileOffset += (uint)(_pakFileLength - _pakFormat.PakPabMinDataOffset) - (_pakFormat.PakPabMinDataOffset == 0 ? ph.HeaderStart : 0); //gh5 doesn't hold the offset in relation to the data.
                        }
                        minOffset = _pakFileLength;
                    }
                }
            }

            _qbFilenames = new string[_pakHeaders.Count];
            int i = 0;

            foreach (PakHeaderItem hi in _pakHeaders.Values)
            {
                _qbFilenames[i++] = hi.Filename;
            }

            StructItemChildrenType s;

            if (!debugFile)
            {
                s = this.StructItemChildrenType;  //auto detect the structitemchildren type
            }
        }
예제 #10
0
        private PakHeaderItem createBlankFile(string newQbFilename, QbKey itemType, bool filenameInHeader)
        {
            //update the filename in the collection
            List <PakHeaderItem> hd = new List <PakHeaderItem>(_pakHeaders.Values);

            PakHeaderItem newHdr = new PakHeaderItem();

            newHdr.FileLength    = 0; // (uint)(new FileInfo(localFilename)).Length;
            newHdr.FileOffset    = hd[0].FileOffset + (uint)(filenameInHeader ? PakHeaderItem.FullHeaderLength : 0x20);
            newHdr.Flags         = (PakHeaderFlags)(filenameInHeader ? PakHeaderFlags.Filename : 0);
            newHdr.HeaderStart   = 0;
            newHdr.IsStoredInPak = true;
            newHdr.Filename      = newQbFilename;
            newHdr.FileType      = itemType;
            hd.Insert(0, newHdr);

            //update the filename in the collection
            bool pastNew = false;
            Dictionary <string, PakHeaderItem> p = new Dictionary <string, PakHeaderItem>(_pakHeaders.Count);

            bool hasFoundMatch = filenameInHeader;

            foreach (PakHeaderItem ph in hd)
            {
                //small hack to determine which items need to be filled - Find another header with
                if (!hasFoundMatch && ((ph.Flags & PakHeaderFlags.Filename) != PakHeaderFlags.Filename) && ph != newHdr)
                {
                    newHdr.SetFilename(newQbFilename, itemType, _pakFormat.FileExtension, ph);
                    hasFoundMatch = true;
                }

                if (pastNew)
                {
                    ph.HeaderStart += (uint)(filenameInHeader ? PakHeaderItem.FullHeaderLength : 0x20);
                }
                else if (ph != newHdr)
                {
                    ph.FileOffset += (uint)(filenameInHeader ? PakHeaderItem.FullHeaderLength : 0x20);
                }
                else // (ph == newHdr)
                {
                    pastNew = true;
                }

                p.Add(ph.Filename.ToLower(), ph);
            }

            if (!hasFoundMatch)
            {
                newHdr.SetFilename(newQbFilename, itemType, _pakFormat.FileExtension, null);
            }

            _pakFileLength += (uint)(filenameInHeader ? PakHeaderItem.FullHeaderLength : PakHeaderItem.FullHeaderLength - PakHeaderItem.FileNameMaxLength);

            _pakHeaders = p;

            string newPakFilename = string.Format("{0}_{1}", _pakFilename, Guid.NewGuid().ToString("N"));

            using (FileStream fsO = File.Open(newPakFilename, FileMode.CreateNew))
            {
                using (BinaryEndianWriter bw = new BinaryEndianWriter(fsO))
                {
                    writeHeaderItem(bw, newHdr);
                    using (FileStream fsI = File.OpenRead(_pakFilename))
                        copyData(fsI, fsO, new FileInfo(_pakFilename).Length);
                }
            }

            File.Delete(_pakFilename);
            File.Move(newPakFilename, _pakFilename);

            return(newHdr);
        }
예제 #11
0
        private void writeHeaderItem(BinaryEndianWriter bwPakO, PakHeaderItem ph)
        {
            bwPakO.Write(ph.FileType.Crc, _pakFormat.EndianType);

            uint offset = ph.FileOffset;
            if (_requiresPab)
                offset = (uint)_pakFormat.PakPabMinDataOffset + ((_pakFormat.PakPabMinDataOffset == 0 ? ph.HeaderStart : 0) + ph.FileOffset) - (uint)_pakFileLength;

            bwPakO.Write(offset, _pakFormat.EndianType);
            bwPakO.Write(ph.FileLength, _pakFormat.EndianType);
            bwPakO.Write(ph.PakFullFileNameQbKey, _pakFormat.EndianType);
            bwPakO.Write(ph.FullFilenameQbKey, _pakFormat.EndianType);
            bwPakO.Write(ph.NameOnlyCrc, _pakFormat.EndianType);
            bwPakO.Write(ph.Unknown, _pakFormat.EndianType);
            bwPakO.Write((uint)ph.Flags, _pakFormat.EndianType);

            if ((ph.Flags & PakHeaderFlags.Filename) == PakHeaderFlags.Filename)
                bwPakO.Write(Encoding.UTF8.GetBytes(ph.PaddedFileName), 0, PakHeaderItem.FileNameMaxLength);
        }
예제 #12
0
        private void parsePak(PakFormat pakFormat, bool debugFile)
        {
            _debugFile = debugFile;
            _pakFormat = pakFormat;
            _pakFilename = (!_debugFile ? _pakFormat.FullPakFilename : _pakFormat.FullDebugFilename);

            Dictionary<uint, PakDbgQbKey> qbKeyFilenames = new Dictionary<uint, PakDbgQbKey>();

            //if PC or xbox then we need to look up the filename from the debug file
            //create a PakEditor and load the debug pak, then load all internal debug files, add the first line to our filenames dictionary
            if (!debugFile) // && (_pakFormat.PakFormatType == PakFormatType.PC || _pakFormat.PakFormatType == PakFormatType.XBox))
            {
                try
                {
                    _pakFormat.Decompress();
                    _pakFilename = _pakFormat.FullPakFilename;
                }
                catch (Exception ex)
                {
                    throw new Exception("Decompression Error", ex);
                }

                if (_pakFormat.DebugFileExists)
                {
                    string debugFileContents;
                    string filename;
                    uint crc;
                    PakEditor pakDebug = new PakEditor(new PakFormat(_pakFormat.FullDebugFilename, "", _pakFormat.FullDebugFilename, _pakFormat.PakFormatType), true);
                    foreach (PakHeaderItem dphi in pakDebug.Headers.Values)
                    {
                        debugFileContents = string.Empty;
                        filename = string.Empty;
                        crc = 0;
                        if (dphi.FullFilenameQbKey != 0)
                            crc = dphi.FullFilenameQbKey;
                        else if (dphi.PakFullFileNameQbKey != 0)
                            crc = dphi.PakFullFileNameQbKey;
                        else if (dphi.NameOnlyCrc != 0)
                            crc = dphi.NameOnlyCrc;

                        if (crc != 0)
                        {
                            filename = crc.ToString("X").PadLeft(8, '0');
                            if (pakDebug.Headers.ContainsKey(filename.ToLower()))
                            {
                                debugFileContents = pakDebug.ExtractFileToString(filename);

                                if (debugFileContents.Length != 0)
                                    addDebugFilename(debugFileContents, qbKeyFilenames, crc);
                            }
                        }
                    }
                }

            }

            long minOffset = uint.MaxValue;
            long maxOffset = 0;

            _pakHeaders = new Dictionary<string, PakHeaderItem>();

            using (Stream st = File.Open(_pakFilename, FileMode.Open, FileAccess.Read))
            {
                _pakFileLength = st.Length;

                using (BinaryEndianReader br = new BinaryEndianReader(st))
                {
                    PakHeaderItem phi = null;

                    QbKey lastQbKey = QbKey.Create("last");
                    QbKey dotLastQbKey = QbKey.Create(".last");

                    do
                    {
                        phi = new PakHeaderItem();

                        phi.HeaderStart = (uint)st.Position;
                        phi.IsStoredInPak = true;

                        phi.FileType = QbKey.Create(br.ReadUInt32(_pakFormat.EndianType));

                        //if the entry has the file type of last then we're done
                        if (phi.FileType == lastQbKey || phi.FileType == dotLastQbKey)
                            break;

                        phi.FileOffset = br.ReadUInt32(_pakFormat.EndianType);
                        phi.FileLength = br.ReadUInt32(_pakFormat.EndianType);
                        phi.PakFullFileNameQbKey = br.ReadUInt32(_pakFormat.EndianType);
                        phi.FullFilenameQbKey = br.ReadUInt32(_pakFormat.EndianType);
                        phi.NameOnlyCrc = br.ReadUInt32(_pakFormat.EndianType);
                        phi.Unknown = br.ReadUInt32(_pakFormat.EndianType);
                        phi.Flags = (PakHeaderFlags)br.ReadUInt32(_pakFormat.EndianType);

                        if ((phi.Flags & PakHeaderFlags.Filename) != PakHeaderFlags.Filename)
                        {
                            uint crc = 0;

                            //get any Crc
                            if (phi.FullFilenameQbKey != 0)
                                crc = phi.FullFilenameQbKey;
                            else if (phi.PakFullFileNameQbKey != 0)
                                crc = phi.PakFullFileNameQbKey;
                            else if (phi.NameOnlyCrc != 0)
                                crc = phi.NameOnlyCrc;

                            if (!debugFile)
                            {
                                uint crc2 = 0;
                                //get a crc that exists in the debug names
                                if (qbKeyFilenames.ContainsKey(phi.FullFilenameQbKey))
                                    crc2 = phi.FullFilenameQbKey;
                                else if (qbKeyFilenames.ContainsKey(phi.PakFullFileNameQbKey))
                                    crc2 = phi.PakFullFileNameQbKey;
                                else if (qbKeyFilenames.ContainsKey(phi.NameOnlyCrc))
                                    crc2 = phi.NameOnlyCrc;

                                //if 0 then get any crc
                                if (crc2 != 0)
                                {
                                    phi.Filename = qbKeyFilenames[crc2].Filename;
                                    phi.DebugQbKey = qbKeyFilenames[crc2].DebugQbKey;
                                    crc = crc2;
                                }
                            }

                            if (phi.Filename == null)
                            {
                                if (crc != 0)
                                    phi.Filename = crc.ToString("X").PadLeft(8, '0');
                                else
                                    phi.Filename = string.Format("Unknown={0}", phi.HeaderStart.ToString("X").PadLeft(8, '0'));
                            }
                        }
                        else
                            phi.Filename = UTF8Encoding.UTF8.GetString(br.ReadBytes(PakHeaderItem.FileNameMaxLength)).TrimEnd(new char[] { '\0' });

                        try
                        {
                            _pakHeaders.Add(phi.Filename.ToLower(), phi);
                        }
                        catch (Exception ex)
                        {
                            throw new ApplicationException(string.Format("Error adding '{0}' to headers: {1}", phi.Filename, ex.Message));
                        }

                        if (phi.HeaderStart + phi.FileOffset < minOffset)
                            minOffset = phi.HeaderStart + phi.FileOffset;

                        if (phi.HeaderStart + phi.FileOffset > maxOffset)
                            maxOffset = phi.HeaderStart + phi.FileOffset;

                    }
                    while (1 == 1); //minOffset > fs.Position + 0x100); //drop out if we reach the data

                    //this is a simple hack/fix to cater for padding on PAK files,
                    //it relies on the data starting at the top of the PAB file (which it always does, currently)
                    _requiresPab = maxOffset >= st.Length;

                    if (!debugFile) //only when loading pak
                        _pakFormat.PakPabMinDataOffset = minOffset; //remember this value

                    //detect GH5 PAB files
                    if (_requiresPab)
                    {
                        foreach (PakHeaderItem ph in _pakHeaders.Values)
                            ph.FileOffset += (uint)(_pakFileLength - _pakFormat.PakPabMinDataOffset) - (_pakFormat.PakPabMinDataOffset == 0 ? ph.HeaderStart : 0); //gh5 doesn't hold the offset in relation to the data.
                        minOffset = _pakFileLength;
                    }

                }
            }

            _qbFilenames = new string[_pakHeaders.Count];
            int i = 0;
            foreach (PakHeaderItem hi in _pakHeaders.Values)
                _qbFilenames[i++] = hi.Filename;

            StructItemChildrenType s;
            if (!debugFile)
                s = this.StructItemChildrenType;  //auto detect the structitemchildren type
        }
예제 #13
0
        private PakHeaderItem createBlankFile(string newQbFilename, QbKey itemType, bool filenameInHeader)
        {
            //update the filename in the collection
            List<PakHeaderItem> hd = new List<PakHeaderItem>(_pakHeaders.Values);

            PakHeaderItem newHdr = new PakHeaderItem();
            newHdr.FileLength = 0; // (uint)(new FileInfo(localFilename)).Length;
            newHdr.FileOffset = hd[0].FileOffset + (uint)(filenameInHeader ? PakHeaderItem.FullHeaderLength : 0x20);
            newHdr.Flags = (PakHeaderFlags)(filenameInHeader ? PakHeaderFlags.Filename : 0);
            newHdr.HeaderStart = 0;
            newHdr.IsStoredInPak = true;
            newHdr.Filename = newQbFilename;
            newHdr.FileType = itemType;
            hd.Insert(0, newHdr);

            //update the filename in the collection
            bool pastNew = false;
            Dictionary<string, PakHeaderItem> p = new Dictionary<string, PakHeaderItem>(_pakHeaders.Count);

            bool hasFoundMatch = filenameInHeader;

            foreach (PakHeaderItem ph in hd)
            {
                //small hack to determine which items need to be filled - Find another header with
                if (!hasFoundMatch && ((ph.Flags & PakHeaderFlags.Filename) != PakHeaderFlags.Filename) && ph != newHdr)
                {
                    newHdr.SetFilename(newQbFilename, itemType, _pakFormat.FileExtension, ph);
                    hasFoundMatch = true;
                }

                if (pastNew)
                    ph.HeaderStart += (uint)(filenameInHeader ? PakHeaderItem.FullHeaderLength : 0x20);
                else if (ph != newHdr)
                    ph.FileOffset += (uint)(filenameInHeader ? PakHeaderItem.FullHeaderLength : 0x20);
                else // (ph == newHdr)
                    pastNew = true;

                p.Add(ph.Filename.ToLower(), ph);
            }

            if (!hasFoundMatch)
                newHdr.SetFilename(newQbFilename, itemType, _pakFormat.FileExtension, null);

            _pakFileLength += (uint)(filenameInHeader ? PakHeaderItem.FullHeaderLength : PakHeaderItem.FullHeaderLength - PakHeaderItem.FileNameMaxLength);

            _pakHeaders = p;

            string newPakFilename = string.Format("{0}_{1}", _pakFilename, Guid.NewGuid().ToString("N"));
            using (FileStream fsO = File.Open(newPakFilename, FileMode.CreateNew))
            {
                using (BinaryEndianWriter bw = new BinaryEndianWriter(fsO))
                {
                    writeHeaderItem(bw, newHdr);
                    using (FileStream fsI = File.OpenRead(_pakFilename))
                        copyData(fsI, fsO, new FileInfo(_pakFilename).Length);
                }
            }

            File.Delete(_pakFilename);
            File.Move(newPakFilename, _pakFilename);

            return newHdr;
        }