private bool ReadBND2(BinaryReader2 br) { br.BaseStream.Position += 4; int platform = br.ReadInt32(); if (platform != 1) { platform = Util.ReverseBytes(platform); } Platform = (BundlePlatform)platform; br.BigEndian = Console; br.BaseStream.Position -= 8; Version = br.ReadInt32(); if (Version != 2) { throw new ReadFailedError("Unsupported Bundle Version: " + Version); } br.BaseStream.Position += 4; RSTOffset = br.ReadInt32(); EntryCount = br.ReadInt32(); IDBlockOffset = br.ReadInt32(); uint[] fileBlockOffsets = new uint[3]; fileBlockOffsets[0] = br.ReadUInt32(); fileBlockOffsets[1] = br.ReadUInt32(); fileBlockOffsets[2] = br.ReadUInt32(); Flags = (Flags)br.ReadInt32(); // 8 Bytes Padding br.BaseStream.Position = IDBlockOffset; for (int i = 0; i < EntryCount; i++) { BundleEntry entry = new BundleEntry(this); entry.Index = i; entry.Platform = Platform; entry.ID = br.ReadUInt64(); entry.References = br.ReadUInt64(); entry.EntryBlocks = new EntryBlock[3]; for (int j = 0; j < entry.EntryBlocks.Length; j++) { entry.EntryBlocks[j] = new EntryBlock(); entry.EntryBlocks[j].Compressed = Flags.HasFlag(Flags.Compressed); } //uint[] blockUncompressedSizes = new uint[3]; for (int j = 0; j < entry.EntryBlocks.Length; j++) { uint uncompressedSize = br.ReadUInt32(); //blockUncompressedSizes[j] = uncompressedSize & ~(0xFU << 28); entry.EntryBlocks[j].UncompressedSize = uncompressedSize & ~(0xFU << 28); entry.EntryBlocks[j].UncompressedAlignment = (uint)(1 << ((int)uncompressedSize >> 28)); } //uint[] blockCompressedSizes = new uint[3]; for (int j = 0; j < entry.EntryBlocks.Length; j++) { //blockCompressedSizes[j] = br.ReadUInt32(); entry.EntryBlocks[j].CompressedSize = br.ReadUInt32(); } for (int j = 0; j < entry.EntryBlocks.Length; j++) { uint blockOffset = br.ReadUInt32(); long lastAddr = br.BaseStream.Position; br.BaseStream.Position = blockOffset + fileBlockOffsets[j]; EntryBlock block = entry.EntryBlocks[j]; bool compressed = Flags.HasFlag(Flags.Compressed); //uint readSize = compressed ? blockCompressedSizes[j] : blockUncompressedSizes[j]; uint readSize = compressed ? entry.EntryBlocks[j].CompressedSize : entry.EntryBlocks[j].UncompressedSize; if (readSize == 0) { block.RawData = null; br.BaseStream.Position = lastAddr; continue; } block.RawData = br.ReadBytes((int)readSize); //if (compressed) // block.Data = block.Data.Decompress((int)blockUncompressedSizes[j]); br.BaseStream.Position = lastAddr; } entry.DependenciesListOffset = br.ReadInt32(); entry.Type = (EntryType)br.ReadInt32(); entry.DependencyCount = br.ReadInt16(); br.BaseStream.Position += 2; // Padding entry.Dirty = false; Entries.Add(entry); } if (Flags.HasFlag(Flags.HasResourceStringTable)) { br.BaseStream.Position = RSTOffset; // TODO: Store only the debug info and not the full string ResourceStringTable = br.ReadCStr(); ProcessRST(ResourceStringTable); } return(true); }
public void Write(BinaryWriter bw) { bw.Write(BundleArchive.BND2Magic); bw.Write(this.Version); bw.Write((int)this.Platform); long rstOffset = bw.BaseStream.Position; bw.Write((int)0); bw.Write(this.Entries.Count); long idBlockOffsetPos = bw.BaseStream.Position; bw.Write((int)0); long[] fileBlockOffsetsPos = new long[3]; for (int i = 0; i < fileBlockOffsetsPos.Length; i++) { fileBlockOffsetsPos[i] = bw.BaseStream.Position; bw.BaseStream.Position += 4; } bw.Write((int)this.Flags); bw.Align(16); long currentOffset = bw.BaseStream.Position; bw.BaseStream.Position = rstOffset; bw.Write((uint)currentOffset); bw.BaseStream.Position = currentOffset; if (this.Flags.HasFlag(Flags.HasResourceStringTable)) { // TODO: Rebuild RST from DebugInfo bw.WriteCStr(this.ResourceStringTable); bw.Align(16); } // ID Block currentOffset = bw.BaseStream.Position; bw.Seek((int)idBlockOffsetPos, SeekOrigin.Begin); bw.Write((int)currentOffset); bw.Seek((int)currentOffset, SeekOrigin.Begin); List <long[]> entryDataPointerPos = new List <long[]>(); List <byte[][]> compressedBlocks = new List <byte[][]>(); for (int i = 0; i < this.Entries.Count; i++) { BundleEntry entry = this.Entries[i]; compressedBlocks.Add(new byte[3][]); bw.Write(entry.ID); bw.Write(entry.References); for (int j = 0; j < entry.EntryBlocks.Length; j++) { EntryBlock entryBlock = entry.EntryBlocks[j]; uint uncompressedSize = 0; if (entryBlock.Data != null) { uncompressedSize = (uint)entryBlock.Data.Length; } //self.Write((entryBlock.UncompressedAlignment << 28) | uncompressedSize); bw.Write((uint)(uncompressedSize | (BitScan.BitScanReverse(entryBlock.UncompressedAlignment) << 28))); } for (int j = 0; j < entry.EntryBlocks.Length; j++) { EntryBlock entryBlock = entry.EntryBlocks[j]; if (entryBlock.Data == null) { bw.Write((uint)0); } else { compressedBlocks[i][j] = entryBlock.Data.Compress(); bw.Write(compressedBlocks[i][j].Length); } } entryDataPointerPos.Add(new long[3]); for (int j = 0; j < entryDataPointerPos[i].Length; j++) { entryDataPointerPos[i][j] = bw.BaseStream.Position; bw.BaseStream.Position += 4; } bw.Write(entry.DependenciesListOffset); bw.Write((int)entry.Type); bw.Write(entry.DependencyCount); bw.BaseStream.Position += 2; // Padding } // Data Block for (int i = 0; i < 3; i++) { long blockStart = bw.BaseStream.Position; bw.BaseStream.Position = fileBlockOffsetsPos[i]; bw.Write((uint)blockStart); bw.BaseStream.Position = blockStart; for (int j = 0; j < this.Entries.Count; j++) { BundleEntry entry = this.Entries[j]; EntryBlock entryBlock = entry.EntryBlocks[i]; bool compressed = this.Flags.HasFlag(Flags.Compressed); uint size = compressed ? (compressedBlocks[j][i] == null ? 0 : (uint)compressedBlocks[j][i].Length) : (uint)entryBlock.Data.Length; if (size > 0) { long pos = bw.BaseStream.Position; bw.BaseStream.Position = entryDataPointerPos[j][i]; bw.Write((uint)(pos - blockStart)); bw.BaseStream.Position = pos; if (compressed) { bw.Write(compressedBlocks[j][i]); } else { bw.Write(entryBlock.Data); } bw.Align((i != 0 && j != this.Entries.Count - 1) ? (byte)0x80 : (byte)16); } } if (i != 2) { bw.Align(0x80); } } }
private bool ReadBND1(BinaryReader2 br) { br.BigEndian = true; // Version number? br.ReadUInt32(); uint entryCount = br.ReadUInt32(); uint[] dataBlockSizes = new uint[5]; for (int i = 0; i < dataBlockSizes.Length; i++) { dataBlockSizes[i] = br.ReadUInt32(); br.BaseStream.Position += 4; // Padding } br.BaseStream.Position += 0x14; // Unknown Data uint idListOffset = br.ReadUInt32(); uint idTableOffset = br.ReadUInt32(); br.ReadUInt32(); // dependency block br.ReadUInt32(); // start of data block Platform = BundlePlatform.X360; // Xbox only for now br.ReadUInt32(); // might be platform (2 being X360) uint compressed = br.ReadUInt32(); if (compressed != 0) { Flags = Flags.Compressed; // TODO } else { Flags = 0; } br.ReadUInt32(); // unknown purpose sometimes the same as entryCount uint uncompressedInfoOffset = br.ReadUInt32(); br.ReadUInt32(); // main memory alignment br.ReadUInt32(); // graphics memory alignment Entries.Clear(); br.BaseStream.Position = idListOffset; List <ulong> resourceIds = new List <ulong>(); for (int i = 0; i < entryCount; i++) { resourceIds.Add(br.ReadUInt64()); } br.BaseStream.Position = idTableOffset; foreach (ulong resourceId in resourceIds) { BundleEntry entry = new BundleEntry(this); entry.EntryBlocks = new EntryBlock[3]; entry.ID = resourceId; br.ReadUInt32(); // unknown mem stuff entry.DependenciesListOffset = br.ReadInt32(); entry.Type = (EntryType)br.ReadUInt32(); //uint[] sizes = new uint[2]; if (compressed != 0) { //sizes[0] = br.ReadUInt32(); entry.EntryBlocks[0] = new EntryBlock(); entry.EntryBlocks[0].Compressed = true; entry.EntryBlocks[0].CompressedSize = br.ReadUInt32(); br.ReadUInt32(); // Alignment value, should be 1 br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. br.ReadUInt32(); // Alignment value, should be 1 //sizes[1] = br.ReadUInt32(); entry.EntryBlocks[1] = new EntryBlock(); entry.EntryBlocks[1].Compressed = true; entry.EntryBlocks[1].CompressedSize = br.ReadUInt32(); br.ReadUInt32(); // Alignment value, should be 1 br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. br.ReadUInt32(); // Alignment value, should be 1 br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. br.ReadUInt32(); // Alignment value, should be 1 } else { //sizes[0] = br.ReadUInt32(); entry.EntryBlocks[0] = new EntryBlock(); entry.EntryBlocks[0].Compressed = false; entry.EntryBlocks[0].UncompressedSize = br.ReadUInt32(); entry.EntryBlocks[0].UncompressedAlignment = br.ReadUInt32(); br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. br.ReadUInt32(); // Alignment value //sizes[1] = br.ReadUInt32(); entry.EntryBlocks[1] = new EntryBlock(); entry.EntryBlocks[1].Compressed = false; entry.EntryBlocks[1].UncompressedSize = br.ReadUInt32(); entry.EntryBlocks[1].UncompressedAlignment = br.ReadUInt32(); br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. br.ReadUInt32(); // Alignment value br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. br.ReadUInt32(); // Alignment value } uint dataBlockStartOffset = 0; for (int j = 0; j < dataBlockSizes.Length; j++) { if (j > 0) { dataBlockStartOffset += dataBlockSizes[j - 1]; } uint readOffset = br.ReadUInt32() + dataBlockStartOffset; br.ReadUInt32(); // 1 if (j != 0 && j != 2) { continue; // Not supporting blocks 2, 4 and 5 right now. } int mappedBlock = j; if (j == 2) { mappedBlock = 1; } if (entry.EntryBlocks[mappedBlock] == null) { entry.EntryBlocks[mappedBlock] = new EntryBlock(); } EntryBlock entryBlock = entry.EntryBlocks[mappedBlock]; //uint readSize = sizes[mappedBlock]; uint readSize = compressed != 0 ? entryBlock.CompressedSize : entryBlock.UncompressedSize; if (readSize == 0) { entryBlock.RawData = null; continue; } long pos = br.BaseStream.Position; br.BaseStream.Position = readOffset; entryBlock.RawData = br.ReadBytes((int)readSize); br.BaseStream.Position = pos; } br.BaseStream.Position += 0x14; // unknown mem stuff Entries.Add(entry); } if (compressed != 0) { br.BaseStream.Position = uncompressedInfoOffset; for (int i = 0; i < Entries.Count; i++) { BundleEntry entry = Entries[i]; //uint[] sizes = new uint[2]; //sizes[0] = br.ReadUInt32(); entry.EntryBlocks[0].UncompressedSize = br.ReadUInt32(); entry.EntryBlocks[0].UncompressedAlignment = br.ReadUInt32(); br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. br.ReadUInt32(); // Alignment value //sizes[1] = br.ReadUInt32(); entry.EntryBlocks[1].UncompressedSize = br.ReadUInt32(); entry.EntryBlocks[1].UncompressedAlignment = br.ReadUInt32(); br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. br.ReadUInt32(); // Alignment value br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. br.ReadUInt32(); // Alignment value //for (int j = 0; j < 2; j++) //{ // EntryBlock entryBlock = entry.EntryBlocks[j]; // if (sizes[j] > 0) // entryBlock.Data = entryBlock.Data.Decompress((int)sizes[j]); //} } } for (int i = 0; i < Entries.Count; i++) { BundleEntry entry = Entries[i]; uint depOffset = (uint)entry.DependenciesListOffset; if (depOffset == 0) { continue; } br.BaseStream.Position = depOffset; entry.DependencyCount = (short)br.ReadUInt32(); if (br.ReadUInt32() != 0) { return(false); } for (int j = 0; j < entry.DependencyCount; j++) { Dependency dep = new Dependency(); dep.ID = br.ReadUInt64(); dep.EntryPointerOffset = br.ReadUInt32(); br.ReadUInt32(); // Skip entry.Dependencies.Add(dep); } } BundleEntry rst = GetEntryByID(0xC039284A); if (rst == null) { return(true); } BinaryReader2 br2 = new BinaryReader2(rst.MakeStream()); br2.BigEndian = false; // TODO: Store only the debug info and not the full string ResourceStringTable = br2.ReadLenString(); br2.Close(); // Cover Criterion's broken XML writer. if (ResourceStringTable.StartsWith("</ResourceStringTable>")) { ResourceStringTable = ResourceStringTable.Remove(1, 1); } string badLine = "</ResourceStringTable>\n\t"; int index = ResourceStringTable.IndexOf(badLine); if (index > -1) { ResourceStringTable = ResourceStringTable.Remove(index, badLine.Length); } ProcessRST(ResourceStringTable); Entries.Remove(rst); return(true); }