Ejemplo n.º 1
0
        public override void Construct(BinaryEndianReader br, QbItemType type)
        {
            //System.Diagnostics.Debug.WriteLine(string.Format("{0} - 0x{1}", type.ToString(), (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0')));

            base.Construct(br, type);

            _unknown = br.ReadUInt32(base.Root.PakFormat.EndianType);
            uint decompressedSize = br.ReadUInt32(base.Root.PakFormat.EndianType);
            uint compressedSize   = br.ReadUInt32(base.Root.PakFormat.EndianType);

            // Get script data
            Lzss lz = new Lzss();

            _scriptData = br.ReadBytes((int)compressedSize);
            if (compressedSize < decompressedSize)
            {
                _scriptData = lz.Decompress(_scriptData);
            }

            if (_scriptData.Length != decompressedSize)
            {
                throw new ApplicationException(string.Format("Location 0x{0}: Script decompressed to {1} bytes not {2}", (base.StreamPos(br) - compressedSize).ToString("X").PadLeft(8, '0'), _scriptData.Length.ToString(), decompressedSize.ToString()));
            }

            // Padding...
            if ((base.StreamPos(br) % 4) != 0)
            {
                br.BaseStream.Seek(4 - (base.StreamPos(br) % 4), SeekOrigin.Current);
            }

            base.ConstructEnd(br);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Pass null for br if the data was passed as a byte array in the constructor
        /// </summary>
        /// <param name="br"></param>
        /// <param name="type"></param>
        public override void Construct(BinaryEndianReader br, QbItemType type)
        {
            //System.Diagnostics.Debug.WriteLine(string.Format("{0} - 0x????????", this.GetType().ToString()));
            if (br != null)
            {
                base.Construct(br, type);

                //base.Position = (uint)base.StreamPos(br);
                _unknownData = br.ReadBytes(_length);

                base.ConstructEnd(br);
            }
        }
Ejemplo n.º 3
0
        private CompressionType xBoxUncompress(string compFilename, string uncompFilename)
        {
            if (uncompFilename.ToLower() == compFilename.ToLower()) //nothing to do
            {
                return(CompressionType.None);
            }

            if (File.Exists(uncompFilename))
            {
                File.Delete(uncompFilename);
            }

            CompressionType ct = CompressionType.None;

            try
            {
                using (FileStream inFileStream = new FileStream(compFilename, FileMode.Open, FileAccess.Read))
                {
                    using (BinaryEndianReader br = new BinaryEndianReader(inFileStream))
                    {
                        uint chunkLen = 0;

                        while (chunkLen != 0xffffffff)
                        {
                            using (FileStream outFileStream = new FileStream(uncompFilename, chunkLen == 0 ? FileMode.Create : FileMode.Append))
                            {
                                using (ZlibOutputStream outZStream = new ZlibOutputStream(outFileStream, Rebex.IO.Compression.CompressionMode.Decompress))
                                {
                                    //test for newer GHWT+ compression
                                    long pos = inFileStream.Position;

                                    if (Encoding.ASCII.GetString(br.ReadBytes(4)) == "CHNK")
                                    {
                                        ct = CompressionType.ZLibChunk;

                                        EndianType et = this.EndianType;

                                        //Decompress each section
                                        uint headerLen = br.ReadUInt32(et);
                                        uint blockLen  = br.ReadUInt32(et);
                                        chunkLen = br.ReadUInt32(et);
                                        uint nextchunkLen    = br.ReadUInt32(et);
                                        uint uncompressedLen = br.ReadUInt32(et);
                                        uint uncompressedPos = br.ReadUInt32(et);

                                        _zLibHeaderLen = headerLen;
                                        if (uncompressedLen > this._zLibChunkSize)
                                        {
                                            this._zLibChunkSize = uncompressedLen;
                                        }

                                        inFileStream.Seek(headerLen - (inFileStream.Position - pos), SeekOrigin.Current);
                                        outZStream.WriteByte(0x58);  //Search deflate.cs for "Nanook" for the mod to stop it being written out
                                        outZStream.WriteByte(0x85);  //this is the header MS uses, thie zlib deflate uses 78DA ??

                                        copyStream(inFileStream, outZStream, (int)blockLen);

                                        if (chunkLen != 0xffffffff)
                                        {
                                            inFileStream.Seek((chunkLen - blockLen) - headerLen, SeekOrigin.Current);
                                        }
                                    }
                                    else
                                    {
                                        try
                                        {
                                            inFileStream.Seek(pos, SeekOrigin.Begin);

                                            outZStream.WriteByte(0x58);
                                            outZStream.WriteByte(0x85);
                                            copyStream(inFileStream, outZStream);
                                            ct = CompressionType.ZLib;
                                            break;
                                        }
                                        catch
                                        {
                                            break;  //no compression???
                                        }
                                    }

                                    outZStream.Flush();
                                    outFileStream.Flush();
                                    //outZStream.Close();
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new ApplicationException(string.Format("Uncompress Failed: {0}", ex));
            }

            //using (DeflateStream ds = new DeflateStream(File.Open(compFilename, FileMode.Open), CompressionMode.Decompress))
            //{
            //    using (BinaryReader br = new BinaryReader(ds))
            //    {
            //        using (FileStream ms = File.Create(uncompFilename))
            //        {
            //            using (BinaryWriter bw = new BinaryWriter(ms))
            //            {
            //                long l;
            //                do
            //                {
            //                    l = ms.Length;
            //                    bw.Write(br.ReadBytes(10000));
            //                }
            //                while (l != ms.Length);
            //            }
            //        }
            //    }
            //}

            return(ct);
        }
Ejemplo n.º 4
0
        public override void Construct(BinaryEndianReader br, QbItemType type)
        {
            //System.Diagnostics.Debug.WriteLine(string.Format("{0} - 0x{1}", type.ToString(), (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0')));

            _isUnicode = ((type == QbItemType.SectionStringW || type == QbItemType.ArrayStringW || type == QbItemType.StructItemStringW) &&
                (base.Root.PakFormat.PakFormatType == PakFormatType.PC || base.Root.PakFormat.PakFormatType == PakFormatType.XBox));

            byte[] bytes;

            base.Construct(br, type);

            this.Strings = new string[base.ItemCount];

            _charWidth = !_isUnicode ? 1 : 2;

            if (base.ItemCount != 0)
            {
                //use pointers to read quickly
                if (base.ItemCount > 1)
                {

                    for (int i = 0; i < base.ItemCount - 1; i++)
                    {
                        if (base.StreamPos(br) != base.Pointers[i]) //pointer test
                            throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, base.StreamPos(br), base.Pointers[i]));

                        bytes = br.ReadBytes((int)((base.Pointers[i + 1] - _charWidth) - base.StreamPos(br)));

                        _strings[i] = bytesToString(bytes); //handles unicode

                        if (!_isUnicode ? (br.ReadByte() != 0) : (br.ReadByte() != 0 || br.ReadByte() != 0))
                            throw new ApplicationException(string.Format("Null byte expected reading string array at 0x{0}", (base.StreamPos(br) - _charWidth).ToString("X").PadLeft(8, '0')));
                    }

                    if (base.StreamPos(br) != base.Pointers[base.ItemCount - 1]) //pointer test
                        throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, base.StreamPos(br), base.Pointers[base.ItemCount - 1]));
                }

                //use the slow method read the last string
                StringBuilder sb = new StringBuilder();
                //if we have come from an array we must align our position to %4
                int byteAmount = (int)(4 - (base.StreamPos(br) % 4));

                do
                {
                    bytes = br.ReadBytes(byteAmount);
                    sb.Append(bytesToString(bytes));
                    byteAmount = 4;
                }
                while (!_isUnicode ? (bytes[bytes.Length - 1] != '\0') : (bytes[bytes.Length - 1] != '\0' || bytes[bytes.Length - 2] != '\0'));

                //get text and remove any trailing null bytes
                _strings[base.ItemCount - 1] = sb.ToString().TrimEnd(new char[] { '\0' });
            }
            base.ConstructEnd(br);
        }
Ejemplo n.º 5
0
        public static WavSingleChunkHeader ParseWavSingleChunkHeader(Stream wavStream)
        {
            WavSingleChunkHeader w = new WavSingleChunkHeader();
            byte[] b;

            BinaryEndianReader r = new BinaryEndianReader(wavStream);

            b = r.ReadBytes(4);
            w.FileId = Encoding.Default.GetString(b);
            w.FileLength = r.ReadUInt32(EndianType.Little);
            b = r.ReadBytes(4);
            w.RiffType = Encoding.Default.GetString(b);

            b = r.ReadBytes(4);
            w.ChunkHeaderId = Encoding.Default.GetString(b);
            w.ChunkHeaderLength = r.ReadUInt32(EndianType.Little);
            long p = wavStream.Position;
            w.FormatTag = r.ReadUInt16(EndianType.Little);
            w.Channels = r.ReadUInt16(EndianType.Little);
            w.SamplesPerSec = r.ReadUInt32(EndianType.Little);
            w.AvgBytesPerSec = r.ReadUInt32(EndianType.Little);
            w.BlockAlign = r.ReadUInt16(EndianType.Little);
            w.BitsPerSample = r.ReadUInt16(EndianType.Little);

            if (wavStream.Position - p != w.ChunkHeaderLength)
                w.ExtraBytes = r.ReadBytes((int)(w.ChunkHeaderLength - (wavStream.Position - p)));

            b = r.ReadBytes(4);
            w.ChunkId = Encoding.Default.GetString(b);
            w.ChunkLength = r.ReadUInt32(EndianType.Little);

            w.DataOffset = (int)wavStream.Position;
            return w;
        }
Ejemplo n.º 6
0
        private CompressionType xBoxUncompress(string compFilename, string uncompFilename)
        {
            if (uncompFilename.ToLower() == compFilename.ToLower()) //nothing to do
                return CompressionType.None;

            if (File.Exists(uncompFilename))
                File.Delete(uncompFilename);

            CompressionType ct = CompressionType.None;

            try
            {
                using (FileStream inFileStream = new FileStream(compFilename, FileMode.Open, FileAccess.Read))
                {
                    using (BinaryEndianReader br = new BinaryEndianReader(inFileStream))
                    {
                        uint chunkLen = 0;

                        while (chunkLen != 0xffffffff)
                        {
                            using (FileStream outFileStream = new FileStream(uncompFilename, chunkLen == 0 ? FileMode.Create : FileMode.Append))
                            {
                                using (ZlibOutputStream outZStream = new ZlibOutputStream(outFileStream, Rebex.IO.Compression.CompressionMode.Decompress))
                                {
                                    //test for newer GHWT+ compression
                                    long pos = inFileStream.Position;

                                    if (Encoding.ASCII.GetString(br.ReadBytes(4)) == "CHNK")
                                    {
                                        ct = CompressionType.ZLibChunk;

                                        EndianType et = this.EndianType;

                                        //Decompress each section
                                        uint headerLen = br.ReadUInt32(et);
                                        uint blockLen = br.ReadUInt32(et);
                                        chunkLen = br.ReadUInt32(et);
                                        uint nextchunkLen = br.ReadUInt32(et);
                                        uint uncompressedLen = br.ReadUInt32(et);
                                        uint uncompressedPos = br.ReadUInt32(et);

                                        _zLibHeaderLen = headerLen;
                                        if (uncompressedLen > this._zLibChunkSize)
                                            this._zLibChunkSize = uncompressedLen;

                                        inFileStream.Seek(headerLen - (inFileStream.Position - pos), SeekOrigin.Current);
                                        outZStream.WriteByte(0x58);  //Search deflate.cs for "Nanook" for the mod to stop it being written out
                                        outZStream.WriteByte(0x85);  //this is the header MS uses, thie zlib deflate uses 78DA ??

                                        copyStream(inFileStream, outZStream, (int)blockLen);

                                        if (chunkLen != 0xffffffff)
                                            inFileStream.Seek((chunkLen - blockLen) - headerLen, SeekOrigin.Current);

                                    }
                                    else
                                    {
                                        try
                                        {
                                            inFileStream.Seek(pos, SeekOrigin.Begin);

                                            outZStream.WriteByte(0x58);
                                            outZStream.WriteByte(0x85);
                                            copyStream(inFileStream, outZStream);
                                            ct = CompressionType.ZLib;
                                            break;
                                        }
                                        catch
                                        {
                                            break;  //no compression???
                                        }
                                    }

                                    outZStream.Flush();
                                    outFileStream.Flush();
                                    //outZStream.Close();
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new ApplicationException(string.Format("Uncompress Failed: {0}", ex));
            }

            //using (DeflateStream ds = new DeflateStream(File.Open(compFilename, FileMode.Open), CompressionMode.Decompress))
            //{
            //    using (BinaryReader br = new BinaryReader(ds))
            //    {
            //        using (FileStream ms = File.Create(uncompFilename))
            //        {
            //            using (BinaryWriter bw = new BinaryWriter(ms))
            //            {
            //                long l;
            //                do
            //                {
            //                    l = ms.Length;
            //                    bw.Write(br.ReadBytes(10000));
            //                }
            //                while (l != ms.Length);
            //            }
            //        }
            //    }
            //}

            return ct;
        }
Ejemplo n.º 7
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
            }
        }
Ejemplo n.º 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));
            }
        }
Ejemplo n.º 9
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));
        }
Ejemplo n.º 10
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
        }
Ejemplo n.º 11
0
        private void parse()
        {
            _datItems.Clear();

            using (FileStream fs = File.OpenRead(_datFilename))
            {
                using (BinaryEndianReader br = new BinaryEndianReader(fs))
                {
                    uint files = br.ReadUInt32(_endianType);
                    _headerFileSize = br.ReadUInt32(_endianType);
                    QbKey songQk;

                    for (int i = 0; i < files; i++)
                    {
                        songQk = QbKey.Create(br.ReadUInt32(_endianType));
                        _datItems.Add(songQk.Crc, new DatItem(songQk, br.ReadUInt32(_endianType), br.ReadUInt32(_endianType), br.ReadBytes(8)));
                    }
                }
            }
        }
Ejemplo n.º 12
0
        public override void Construct(BinaryEndianReader br, QbItemType type)
        {
            //System.Diagnostics.Debug.WriteLine(string.Format("{0} - 0x{1}", type.ToString(), (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0')));

            _isUnicode = ((type == QbItemType.SectionStringW || type == QbItemType.ArrayStringW || type == QbItemType.StructItemStringW) &&
                          (base.Root.PakFormat.PakFormatType == PakFormatType.PC || base.Root.PakFormat.PakFormatType == PakFormatType.XBox));

            byte[] bytes;

            base.Construct(br, type);

            this.Strings = new string[base.ItemCount];

            _charWidth = !_isUnicode ? 1 : 2;

            if (base.ItemCount != 0)
            {
                //use pointers to read quickly
                if (base.ItemCount > 1)
                {
                    for (int i = 0; i < base.ItemCount - 1; i++)
                    {
                        if (base.StreamPos(br) != base.Pointers[i]) //pointer test
                        {
                            throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, base.StreamPos(br), base.Pointers[i]));
                        }

                        bytes = br.ReadBytes((int)((base.Pointers[i + 1] - _charWidth) - base.StreamPos(br)));

                        _strings[i] = bytesToString(bytes); //handles unicode

                        if (!_isUnicode ? (br.ReadByte() != 0) : (br.ReadByte() != 0 || br.ReadByte() != 0))
                        {
                            throw new ApplicationException(string.Format("Null byte expected reading string array at 0x{0}", (base.StreamPos(br) - _charWidth).ToString("X").PadLeft(8, '0')));
                        }
                    }

                    if (base.StreamPos(br) != base.Pointers[base.ItemCount - 1]) //pointer test
                    {
                        throw new ApplicationException(QbFile.FormatBadPointerExceptionMessage(this, base.StreamPos(br), base.Pointers[base.ItemCount - 1]));
                    }
                }


                //use the slow method read the last string
                StringBuilder sb = new StringBuilder();
                //if we have come from an array we must align our position to %4
                int byteAmount = (int)(4 - (base.StreamPos(br) % 4));

                do
                {
                    bytes = br.ReadBytes(byteAmount);
                    sb.Append(bytesToString(bytes));
                    byteAmount = 4;
                }while (!_isUnicode ? (bytes[bytes.Length - 1] != '\0') : (bytes[bytes.Length - 1] != '\0' || bytes[bytes.Length - 2] != '\0'));


                //get text and remove any trailing null bytes
                _strings[base.ItemCount - 1] = sb.ToString().TrimEnd(new char[] { '\0' });
            }
            base.ConstructEnd(br);
        }
Ejemplo n.º 13
0
        public override void Construct(BinaryEndianReader br, QbItemType type)
        {
            //System.Diagnostics.Debug.WriteLine(string.Format("{0} - 0x{1}", type.ToString(), (base.StreamPos(br) - 4).ToString("X").PadLeft(8, '0')));

            base.Construct(br, type);

            _unknown = br.ReadUInt32(base.Root.PakFormat.EndianType);
            uint decompressedSize = br.ReadUInt32(base.Root.PakFormat.EndianType);
            uint compressedSize = br.ReadUInt32(base.Root.PakFormat.EndianType);

            // Get script data
            Lzss lz = new Lzss();
            _scriptData = br.ReadBytes((int)compressedSize);
            if (compressedSize < decompressedSize)
                _scriptData = lz.Decompress(_scriptData);

            if (_scriptData.Length != decompressedSize)
                throw new ApplicationException(string.Format("Location 0x{0}: Script decompressed to {1} bytes not {2}", (base.StreamPos(br) - compressedSize).ToString("X").PadLeft(8, '0'), _scriptData.Length.ToString(), decompressedSize.ToString()));

            // Padding...
            if ((base.StreamPos(br) % 4) != 0)
                br.BaseStream.Seek(4 - (base.StreamPos(br) % 4), SeekOrigin.Current);

            base.ConstructEnd(br);
        }