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