public void Write(Stream stream, IPsbFilter filter = null)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }
            if (!stream.CanSeek)
            {
                throw new ArgumentException("Stream not seekable", nameof(stream));
            }
            if (Version < 1 || Version > 4)
            {
                throw new NotSupportedException("PSB version requested not supported.");
            }
            Prepare();
            BinaryWriter bw = new BinaryWriter(stream);

            WritePrelimHeader(bw);
            WriteKeyNames(bw);
            WriteRoot(bw);
            WriteStrings(bw);
            if (Version >= 4)
            {
                WriteStreamsMeta(bw, true);
                WriteStreams(bw, true);
            }
            WriteStreamsMeta(bw, false);
            WriteStreams(bw, false);
            UpdateHeader(bw);
            if (filter != null)
            {
                ApplyFilter(stream, filter);
            }
        }
        void ApplyFilter(Stream stream, IPsbFilter filter)
        {
            BinaryReader br = new BinaryReader(stream);
            BinaryWriter bw = new BinaryWriter(stream);

            stream.Seek(8, SeekOrigin.Begin);
            if (Version >= 3 && (Flags & PsbFlags.HeaderFiltered) != 0)
            {
                // Filter header
                int headerLength = (8 + 1) * 4;
                if (Version >= 4)
                {
                    headerLength += 3 * 4;
                }
                byte[] headerBytes = br.ReadBytes(headerLength);
                filter.Filter(headerBytes);
                stream.Seek(8, SeekOrigin.Begin);
                bw.Write(headerBytes);
            }

            if (Version <= 2 || (Flags & PsbFlags.BodyFiltered) != 0)
            {
                uint filterStart = keysOffsetsOffset;
                uint filterEnd   = Version >= 4 ? bStreamsOffsetsOffset : streamsOffsetsOffset;
                stream.Seek(filterStart, SeekOrigin.Begin);
                byte[] data = br.ReadBytes((int)(filterEnd - filterStart));
                filter.Filter(data);
                stream.Seek(filterStart, SeekOrigin.Begin);
                bw.Write(data);
            }
        }
        public static void DumpPsb(string psbPath, bool writeDebug, IPsbFilter filter = null)
        {
            using (FileStream fs = File.OpenRead(psbPath))
                using (StreamWriter debugWriter = writeDebug ? File.CreateText(psbPath + ".debug.txt") : null)
                    using (PsbReader psbReader = new PsbReader(fs, filter, debugWriter))
                    {
                        Newtonsoft.Json.Linq.JToken root;
                        try
                        {
                            root = psbReader.Root;
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("Error parsing PSB");
                            Console.WriteLine("Current position: 0x{0:x8}", fs.Position);
                            Console.WriteLine(ex);

                            if (writeDebug && filter != null)
                            {
                                using (FileStream dcStream = File.Create(psbPath + ".decrypted"))
                                {
                                    psbReader.DumpDecryptedStream(dcStream);
                                }
                            }
                            return;
                        }
                        using (StreamWriter sw = File.CreateText(psbPath + ".json"))
                            using (JsonTextWriter jtw = new JsonTextWriter(sw)
                            {
                                Formatting = Formatting.Indented
                            })
                            {
                                root.WriteTo(jtw);
                            }
                        if (psbReader.StreamCache.Count > 0 || psbReader.BStreamCache.Count > 0)
                        {
                            string streamsDirPath = psbPath + ".streams";
                            Directory.CreateDirectory(streamsDirPath);
                            foreach (var js in psbReader.StreamCache)
                            {
                                File.WriteAllBytes(Path.Combine(streamsDirPath, "stream_" + js.Key), js.Value.BinaryData);
                            }
                            foreach (var js in psbReader.BStreamCache)
                            {
                                File.WriteAllBytes(Path.Combine(streamsDirPath, "bstream_" + js.Key), js.Value.BinaryData);
                            }
                        }
                    }
        }
        public PsbReader(Stream stream, IPsbFilter filter = null, TextWriter debugWriter = null,
                         bool lazyStreamLoading           = true)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }
            if (!stream.CanSeek)
            {
                throw new ArgumentException("Stream cannot be seeked.", nameof(stream));
            }
            this.stream            = stream;
            br                     = new BinaryReader(stream);
            this.filter            = filter;
            this.lazyStreamLoading = lazyStreamLoading;

            if (new string(br.ReadChars(4)) != "PSB\0")
            {
                throw new InvalidDataException("File is not a PSB");
            }
            Version = br.ReadUInt16();
            Flags   = (PsbFlags)br.ReadUInt16();

            byte[] headerBytes = VerifyHeader();
            ReadHeader(headerBytes);
            SetupUnfiltering();
            LoadKeyNames();
            LoadStringsOffsets();
            LoadStreamsInfo();
            if (Version >= 4)
            {
                LoadBStreamsInfo();
            }
            // Move this down here so I don't get output while arrays are being read
            if (debugWriter != null)
            {
                this.debugWriter = new IndentedTextWriter(debugWriter);
            }
            DebugWriteHeader();
        }
        public static void SerializePsb(string path, ushort version, PsbFlags flags, IPsbFilter filter, bool optimize, bool readAsFloat)
        {
            string psbPath = Path.ChangeExtension(path, null);

            if (!psbPath.ToLower().EndsWith(".psb"))
            {
                psbPath += ".psb";
            }
            using (StreamReader reader = File.OpenText(path))
                using (Stream writer = File.Create(psbPath))
                {
                    JsonTextReader jReader = new JsonTextReader(reader)
                    {
                        FloatParseHandling = readAsFloat ? FloatParseHandling.Double : FloatParseHandling.Decimal
                    };
                    JToken           root         = JToken.ReadFrom(jReader);
                    IPsbStreamSource streamSource = new CliStreamSource(Path.ChangeExtension(path, ".streams"));
                    PsbWriter        psbWriter    = new PsbWriter(root, streamSource);
                    psbWriter.Version  = version;
                    psbWriter.Flags    = flags;
                    psbWriter.Optimize = optimize;
                    psbWriter.Write(writer, filter);
                }
        }
Exemple #6
0
        public OverlayReadStream(Stream baseStream, uint overlayStart, uint overlayEnd, IPsbFilter filter)
        {
            this.baseStream   = baseStream;
            this.overlayStart = overlayStart;
            this.overlayEnd   = overlayEnd;
            long origBasePos = baseStream.Position;

            baseStream.Seek(overlayStart, SeekOrigin.Begin);
            decryptedData = new byte[(int)(overlayEnd - overlayStart)];
            if (baseStream.Read(decryptedData, 0, decryptedData.Length) != decryptedData.Length)
            {
                throw new IOException("Could not read all bytes in overlay region.");
            }
            filter.Filter(decryptedData);
            baseStream.Position = origBasePos;
        }
        public static void Build(string folderPath, string outputPath, MArchivePacker maPacker = null, IPsbFilter filter = null)
        {
            using (FileStream packStream = File.Create(outputPath + ".bin"))
                using (FileStream psbStream = File.Create(outputPath + ".psb"))
                {
                    ArchiveV1 archive = new ArchiveV1();
                    archive.ObjectType = "archive";
                    archive.Version    = 1.0f;
                    archive.FileInfo   = new Dictionary <string, List <int> >();
                    folderPath         = Path.GetFullPath(folderPath);

                    foreach (var file in Directory.GetFiles(folderPath, "*", SearchOption.AllDirectories))
                    {
                        string key = file.Replace(folderPath, string.Empty).TrimStart('/', '\\');
                        Console.WriteLine($"Packing {key}");
                        var    targetLength = (packStream.Position + ALIGNMENT - 1) / ALIGNMENT * ALIGNMENT;
                        byte[] alignBytes   = new byte[targetLength - packStream.Length];
                        packStream.Write(alignBytes, 0, alignBytes.Length);
                        var currPos = packStream.Position;
                        using (FileStream fs = File.OpenRead(file))
                        {
                            fs.CopyTo(packStream);
                            archive.FileInfo.Add(key.Replace('\\', '/'), new List <int>()
                            {
                                (int)currPos, (int)fs.Length
                            });
                        }
                    }

                    JToken    root   = JToken.FromObject(archive);
                    PsbWriter writer = new PsbWriter(root, null)
                    {
                        Version = 3
                    };
                    writer.Write(psbStream, filter);
                }

            if (maPacker != null)
            {
                maPacker.CompressFile(outputPath + ".psb");
            }
        }