Example #1
0
 private static void WriteEncodeBody(BinaryReader br, BinaryWriter bw, PsbStreamContext context, PsbHeader header)
 {
     bw.Write
     (
         context.Encode
         (
             br.ReadBytes((int)(header.OffsetChunkOffsets - header.OffsetNames))
         )
     );
     WriteToEnd(br, bw);
 }
Example #2
0
        public static PsbHeader Load(BinaryReader br, uint key)
        {
            PsbHeader header = new PsbHeader
            {
                Signature     = br.ReadChars(4),
                Version       = br.ReadUInt16(),
                HeaderEncrypt = br.ReadUInt16()
            };
            var sig = new string(header.Signature).ToUpperInvariant();

            if (sig.StartsWith("MDF"))
            {
                throw new PsbBadFormatException(PsbBadFormatReason.IsMdf, "Maybe a MDF file");
            }
            if (!sig.StartsWith("PSB"))
            {
                throw new PsbBadFormatException(PsbBadFormatReason.Header, "Not a valid PSB file");
            }

            PsbStreamContext context = new PsbStreamContext(key);

            header.HeaderLength       = context.ReadUInt32(br);
            header.OffsetNames        = context.ReadUInt32(br);
            header.OffsetStrings      = context.ReadUInt32(br);
            header.OffsetStringsData  = context.ReadUInt32(br);
            header.OffsetChunkOffsets = context.ReadUInt32(br);
            header.OffsetChunkLengths = context.ReadUInt32(br);
            header.OffsetChunkData    = context.ReadUInt32(br);
            header.OffsetEntries      = context.ReadUInt32(br);
            if (header.Version > 2)
            {
                header.Checksum = context.ReadUInt32(br);
            }
            if (header.Version > 3)
            {
                header.OffsetExtraChunkOffsets = context.ReadUInt32(br);
                header.OffsetExtraChunkLengths = context.ReadUInt32(br);
                header.OffsetExtraChunkData    = context.ReadUInt32(br);
            }
            return(header);
        }
Example #3
0
        public static PsbHeader Load(BinaryReader br, uint key)
        {
            PsbHeader header = new PsbHeader
            {
                Signature     = br.ReadChars(4),
                Version       = br.ReadUInt16(),
                HeaderEncrypt = br.ReadUInt16()
            };

            if (!new string(header.Signature).ToUpperInvariant().StartsWith("PSB"))
            {
                throw new BadImageFormatException("Not a valid PSB file");
            }

            PsbStreamContext context = new PsbStreamContext(key);

            header.HeaderLength       = context.ReadUInt32(br);
            header.OffsetNames        = context.ReadUInt32(br);
            header.OffsetStrings      = context.ReadUInt32(br);
            header.OffsetStringsData  = context.ReadUInt32(br);
            header.OffsetChunkOffsets = context.ReadUInt32(br);
            header.OffsetChunkLengths = context.ReadUInt32(br);
            header.OffsetChunkData    = context.ReadUInt32(br);
            header.OffsetEntries      = context.ReadUInt32(br);
            if (header.Version > 2)
            {
                header.Checksum = context.ReadUInt32(br);
            }
            if (header.Version > 3)
            {
                header.OffsetUnknown1        = context.ReadUInt32(br);
                header.OffsetUnknown2        = context.ReadUInt32(br);
                header.OffsetResourceOffsets = context.ReadUInt32(br);
            }
            return(header);
        }
Example #4
0
        /// <summary>
        /// Encode (Encrypt/Decrypt) PSB file
        /// </summary>
        /// <param name="key"></param>
        /// <param name="mode"></param>
        /// <param name="position"></param>
        /// <param name="input"></param>
        /// <param name="output"></param>
        /// <returns>Unencrypted Header for reference. Usually you shouldn't use it.</returns>
        public static PsbHeader Encode(uint key, EncodeMode mode, EncodePosition position, Stream input, Stream output)
        {
            input.Seek(0, SeekOrigin.Begin);
            output.Seek(0, SeekOrigin.Begin);
            PsbHeader        header  = new PsbHeader();
            PsbStreamContext context = new PsbStreamContext(key);
            BinaryReader     br      = new BinaryReader(input);
            BinaryWriter     bw      = new BinaryWriter(output);

            header.Signature = br.ReadChars(4);
            header.Version   = br.ReadUInt16();
            bw.Write(header.Signature);             //Signature
            bw.Write(header.Version);               //Version
            header.HeaderEncrypt = br.ReadUInt16(); //headerEncrypt, sometimes we don't believe it when encoding
            header.HeaderLength  = br.ReadUInt32();
            header.OffsetNames   = br.ReadUInt32();
            br.BaseStream.Seek(-8, SeekOrigin.Current);

            void WriteOriginal()
            {
                bw.Write(header.HeaderEncrypt);
                WriteOriginalPartialHeader(br, bw, header);
                WriteOriginalBody(br, bw);
            }

            switch (position)
            {
            case EncodePosition.Auto:
                bool headerEnc = TestHeaderEncrypted(br.BaseStream, header);
                bool bodyEnc   = TestBodyEncrypted(br, header);
                if (headerEnc && bodyEnc)     //MARK: is this possible?
                {
                    mode = EncodeMode.Decrypt;
                }

                if (!headerEnc && !bodyEnc)
                {
                    mode = EncodeMode.Encrypt;
                }

                switch (mode)
                {
                case EncodeMode.Encrypt:
                    if (header.Version > 2)         //Header Encrypted; Body Clean
                    {
                        bw.Write((ushort)1);
                        if (headerEnc)
                        {
                            WriteOriginalPartialHeader(br, bw, header);
                            WriteOriginalBody(br, bw);
                            break;
                        }

                        WriteEncryptPartialHeader(br, bw, context, header);
                        WriteOriginalBody(br, bw);
                        break;
                    }
                    else                     //Header Clean; Body Encrpyted
                    {
                        bw.Write((ushort)0); //
                        if (headerEnc)
                        {
                            WriteDecryptPartialHeader(br, bw, context, header);
                            context = new PsbStreamContext(key);
                            WriteEncodeBody(br, bw, context, header);
                        }
                        else
                        {
                            WriteOriginalPartialHeader(br, bw, header);
                            WriteEncodeBody(br, bw, context, header);
                        }
                    }

                    break;

                case EncodeMode.Decrypt:
                    bw.Write((ushort)0);          //
                    if (headerEnc)
                    {
                        WriteDecryptPartialHeader(br, bw, context, header);
                    }
                    else
                    {
                        WriteOriginalPartialHeader(br, bw, header);
                    }

                    if (bodyEnc)
                    {
                        WriteEncodeBody(br, bw, context, header);
                    }
                    else
                    {
                        WriteOriginalBody(br, bw);
                    }

                    break;

                default:
                    WriteOriginal();
                    break;
                }

                break;

            case EncodePosition.Body:
                switch (mode)
                {
                case EncodeMode.Encrypt:
                case EncodeMode.Decrypt:
                    bw.Write(header.HeaderEncrypt);
                    //We believe file is clean so write original header but encrypt body
                    WriteOriginalPartialHeader(br, bw, header);
                    WriteEncodeBody(br, bw, context, header);
                    break;

                default:
                    WriteOriginal();
                    break;
                }

                break;

            case EncodePosition.Header:
                switch (mode)
                {
                case EncodeMode.Encrypt:
                    bw.Write((ushort)1);
                    WriteEncryptPartialHeader(br, bw, context, header);
                    WriteOriginalBody(br, bw);
                    break;

                case EncodeMode.Decrypt:
                    bw.Write((ushort)0);          //
                    WriteDecryptPartialHeader(br, bw, context, header);
                    WriteOriginalBody(br, bw);
                    break;

                default:
                    WriteOriginal();
                    break;
                }

                break;

            case EncodePosition.Full:
                switch (mode)
                {
                case EncodeMode.Encrypt:
                    bw.Write((ushort)1);
                    WriteEncryptPartialHeader(br, bw, context, header);
                    WriteEncodeBody(br, bw, context, header);
                    break;

                case EncodeMode.Decrypt:
                    bw.Write((ushort)1);          //
                    WriteDecryptPartialHeader(br, bw, context, header);
                    WriteEncodeBody(br, bw, context, header);
                    break;

                default:
                    WriteOriginal();
                    break;
                }

                break;

            default:
                WriteOriginal();
                break;
            }

            bw.Flush();
            output.Seek(0, SeekOrigin.Begin);
            return(header);
        }
Example #5
0
        /// <summary>
        /// Assume header is clean
        /// </summary>
        /// <param name="br"></param>
        /// <param name="bw"></param>
        /// <param name="context"></param>
        /// <param name="header"></param>
        private static void WriteEncryptPartialHeader(BinaryReader br, BinaryWriter bw, PsbStreamContext context,
                                                      PsbHeader header)
        {
            var checksumStartPosition = br.BaseStream.Position;

            header.HeaderLength = br.ReadUInt32();
            header.OffsetNames  = br.ReadUInt32();
            if (header.HeaderLength == 0)
            {
                header.HeaderLength = header.OffsetNames;
            }

            header.OffsetStrings      = br.ReadUInt32();
            header.OffsetStringsData  = br.ReadUInt32();
            header.OffsetChunkOffsets = br.ReadUInt32();
            header.OffsetChunkLengths = br.ReadUInt32();
            header.OffsetChunkData    = br.ReadUInt32();
            header.OffsetEntries      = br.ReadUInt32();
            if (header.Version > 2)
            {
                header.Checksum = br.ReadUInt32();
            }

            if (header.Version > 3)
            {
                header.OffsetUnknownOffsets = br.ReadUInt32();
                header.OffsetUnknownLengths = br.ReadUInt32();
                header.OffsetUnknownData    = br.ReadUInt32();
            }

            var checksumEndPosition = br.BaseStream.Position;

            context.Write(header.HeaderLength, bw);
            context.Write(header.OffsetNames, bw);
            context.Write(header.OffsetStrings, bw);
            context.Write(header.OffsetStringsData, bw);
            context.Write(header.OffsetChunkOffsets, bw);
            context.Write(header.OffsetChunkLengths, bw);
            context.Write(header.OffsetChunkData, bw);
            context.Write(header.OffsetEntries, bw);

            if (header.Version > 2)
            {
                int checkLength = 32;
                br.BaseStream.Seek(checksumStartPosition, SeekOrigin.Begin);
                var checkBuffer = new byte[checkLength];
                br.BaseStream.Read(checkBuffer, 0, checkLength);
                br.BaseStream.Seek(checksumEndPosition, SeekOrigin.Begin); //Jump back
                Adler32 adler32 = new Adler32();
                adler32.Update(checkBuffer);
                header.Checksum = (uint)adler32.Checksum;
                if (header.Version == 3)
                {
                    context.Write(header.Checksum, bw);
                }
                else //PSBv4
                {
                    checkBuffer = BitConverter.GetBytes(header.OffsetUnknownOffsets)
                                  .Concat(BitConverter.GetBytes(header.OffsetUnknownLengths))
                                  .Concat(BitConverter.GetBytes(header.OffsetUnknownData)).ToArray();
                    adler32.Update(checkBuffer);
                    header.Checksum = (uint)adler32.Checksum;
                    context.Write(header.Checksum, bw);
                    context.Write(header.OffsetUnknownOffsets, bw);
                    context.Write(header.OffsetUnknownLengths, bw);
                    context.Write(header.OffsetUnknownData, bw);
                }
            }
        }
Example #6
0
        /// <summary>
        /// Assume header is encrypted
        /// </summary>
        /// <param name="br"></param>
        /// <param name="bw"></param>
        /// <param name="context"></param>
        /// <param name="header"></param>
        private static void WriteDecryptPartialHeader(BinaryReader br, BinaryWriter bw, PsbStreamContext context,
                                                      PsbHeader header)
        {
            header.HeaderLength       = context.ReadUInt32(br);
            header.OffsetNames        = context.ReadUInt32(br);
            header.OffsetStrings      = context.ReadUInt32(br);
            header.OffsetStringsData  = context.ReadUInt32(br);
            header.OffsetChunkOffsets = context.ReadUInt32(br);
            header.OffsetChunkLengths = context.ReadUInt32(br);
            header.OffsetChunkData    = context.ReadUInt32(br);
            header.OffsetEntries      = context.ReadUInt32(br);
            if (header.Version > 2)
            {
                header.Checksum = context.ReadUInt32(br);
            }

            if (header.Version > 3)
            {
                header.OffsetUnknownOffsets = context.ReadUInt32(br);
                header.OffsetUnknownLengths = context.ReadUInt32(br);
                header.OffsetUnknownData    = context.ReadUInt32(br);
            }

            //var checksumStartPosition = bw.BaseStream.Position;
            bw.Write(header.HeaderLength);
            bw.Write(header.OffsetNames);
            bw.Write(header.OffsetStrings);
            bw.Write(header.OffsetStringsData);
            bw.Write(header.OffsetChunkOffsets);
            bw.Write(header.OffsetChunkLengths);
            bw.Write(header.OffsetChunkData);
            bw.Write(header.OffsetEntries);
            //var checksumPosition = bw.BaseStream.Position;

            if (header.Version > 2)
            {
                int checkLength = 32;
                bw.BaseStream.Seek(-checkLength, SeekOrigin.Current);
                var checkBuffer = new byte[checkLength];
                bw.BaseStream.Read(checkBuffer, 0, checkLength);
                Adler32 adler32 = new Adler32();
                adler32.Update(checkBuffer);
                header.Checksum = (uint)adler32.Checksum;
                if (header.Version == 3)
                {
                    bw.Write(header.Checksum);
                }
                else //PSBv4
                {
                    checkBuffer = BitConverter.GetBytes(header.OffsetUnknownOffsets)
                                  .Concat(BitConverter.GetBytes(header.OffsetUnknownLengths))
                                  .Concat(BitConverter.GetBytes(header.OffsetUnknownData)).ToArray();
                    adler32.Update(checkBuffer);
                    header.Checksum = (uint)adler32.Checksum;
                    bw.Write(header.Checksum);
                    bw.Write(header.OffsetUnknownOffsets);
                    bw.Write(header.OffsetUnknownLengths);
                    bw.Write(header.OffsetUnknownData);
                }
            }
        }
Example #7
0
 /// <summary>
 /// Encode a value and write using <see cref="BinaryWriter"/>.
 /// </summary>
 /// <param name="context"></param>
 /// <param name="value"></param>
 /// <param name="bw"></param>
 public static void Write(this PsbStreamContext context, ushort value, BinaryWriter bw)
 {
     bw.Write(context.Encode(BitConverter.GetBytes(value)));
 }
Example #8
0
 /// <summary>
 /// Read a <see cref="ushort"/> from <see cref="BinaryReader"/>, and then encode using <see cref="PsbStreamContext"/>.
 /// </summary>
 /// <param name="context"></param>
 /// <param name="br"></param>
 /// <returns></returns>
 public static ushort ReadUInt16(this PsbStreamContext context, BinaryReader br)
 {
     return(BitConverter.ToUInt16(context.Encode(br.ReadBytes(2)), 0));
 }
Example #9
0
 /// <summary>
 /// Read bytes from <see cref="BinaryReader"/>, and then encode using <see cref="PsbStreamContext"/>.
 /// </summary>
 /// <param name="context"></param>
 /// <param name="br"></param>
 /// <param name="count"></param>
 /// <returns></returns>
 public static byte[] ReadBytes(this PsbStreamContext context, BinaryReader br, int count)
 {
     return(context.Encode(br.ReadBytes(count)));
 }