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); }
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); }
public static void BuildPartition(string partitionBinFilename, string mainDolFilename, string appLoaderImgFilename, string bi2BinFilename, string bootBinFilename, string sourceDirectory, string partitionFilename, bool deleteWhileBuilding) { ulong totalSize = 0; BinaryEndianReader brFst = null; BinaryEndianWriter bwFst = new BinaryEndianWriter(new MemoryStream()); BinaryEndianWriter bwStr = new BinaryEndianWriter(new MemoryStream()); BinaryEndianWriter bwBootBin = null; BinaryEndianWriter bwPartitionBin = null; BinaryEndianWriter bwB12Bin = null; try { DirectoryInfo inputFolder = new DirectoryInfo(sourceDirectory); //DateTime n = DateTime.Now; uint fileCount = recurseFiles(true, inputFolder, bwFst, bwStr, ref totalSize, 0, null, 0, deleteWhileBuilding); //System.Diagnostics.Debug.WriteLine((DateTime.Now - n).Ticks); // get the file sizes we need - apploader and main.dol FileInfo appLoaderImg = new FileInfo(appLoaderImgFilename); FileInfo mainDol = new FileInfo(mainDolFilename); // now calculate the relative offsets uint pad1Size = 0x100 - (((uint)appLoaderImg.Length + 0x2440) % 0x100); uint pad2Size = 0x100 - ((uint)mainDol.Length % 0x100); // just a pad out for no real reason :) uint pad3Size = 0x2000; uint mainDolOffset = 0x2440 + (uint)appLoaderImg.Length + pad1Size; uint fstOffset = mainDolOffset + pad2Size + (uint)mainDol.Length; // modify the data size in partition.bin // read in partition.bin bwPartitionBin = new BinaryEndianWriter(new MemoryStream(File.ReadAllBytes(partitionBinFilename))); // now Actual size = scaled up by sizes totalSize += pad1Size + 0x2440 + pad2Size + pad3Size + (uint)mainDol.Length + (uint)appLoaderImg.Length; ulong dataSize = (totalSize / 0x7c00) * 0x8000; if (dataSize % 0x7c00 != 0) dataSize += 0x8000; bwPartitionBin.Seek(0x2BC, SeekOrigin.Begin); bwPartitionBin.Write((uint)dataSize >> 2, EndianType.Big); // generate a boot.bin bwBootBin = new BinaryEndianWriter(new MemoryStream(File.ReadAllBytes(bootBinFilename))); // now the size offsets bwBootBin.Seek(0x420, SeekOrigin.Begin); bwBootBin.Write(mainDolOffset >> 2, EndianType.Big); bwBootBin.Write(fstOffset >> 2, EndianType.Big); bwBootBin.Write((uint)(bwFst.BaseStream.Length + bwStr.BaseStream.Length) >> 2, EndianType.Big); bwBootBin.Write((uint)(bwFst.BaseStream.Length + bwStr.BaseStream.Length) >> 2, EndianType.Big); // calculate what we need to modify the FST entries by ulong dataOffset = 0x2440 + pad1Size + (uint)appLoaderImg.Length + (uint)mainDol.Length + pad2Size + (uint)bwFst.BaseStream.Length + (uint)bwStr.BaseStream.Length + pad3Size; dataOffset = (dataOffset >> 2); // modify the fst.bin to include all the correct offsets brFst = new BinaryEndianReader(bwFst.BaseStream); brFst.BaseStream.Seek(8, SeekOrigin.Begin); uint fstEntries = brFst.ReadUInt32(EndianType.Big); for (int i = 1; i < fstEntries; i++) //1 as we've already skipped the root { if (brFst.ReadByte() == 0) //file { brFst.BaseStream.Seek(3, SeekOrigin.Current); //skip the rest of the uint uint temp = brFst.ReadUInt32(EndianType.Big); bwFst.BaseStream.Seek(-4, SeekOrigin.Current); //THE STREAMS ARE THE SAME (be careful of bugs when the position moves) bwFst.Write((uint)dataOffset + temp, EndianType.Big); brFst.BaseStream.Seek(4, SeekOrigin.Current); //skip the rest of the file } else brFst.BaseStream.Seek(0xc - 1, SeekOrigin.Current); //skip the rest of the directory } using (FileStream fs = new FileStream(partitionFilename, FileMode.Create)) { copyStream(bwPartitionBin.BaseStream, fs, 4); copyStream(bwBootBin.BaseStream, fs, 4); copyStream(bi2BinFilename, fs, 4); copyStream(appLoaderImgFilename, fs, 4); fs.Write(new byte[pad1Size], 0, (int)pad1Size); copyStream(mainDolFilename, fs, 4); fs.Write(new byte[pad2Size], 0, (int)pad2Size); copyStream(bwFst.BaseStream, fs, 4); copyStream(bwStr.BaseStream, fs, 4); fs.Write(new byte[pad3Size], 0, (int)pad3Size); //copy all the files to the end of the partition totalSize = dataOffset; //will give the offsets the correct value (not that it matters here heh) bwFst.BaseStream.Seek(0, SeekOrigin.Begin); bwStr.BaseStream.Seek(0, SeekOrigin.Begin); recurseFiles(true, inputFolder, bwFst, bwStr, ref totalSize, 0, fs, (ulong)fs.Position - dataOffset, deleteWhileBuilding); if (deleteWhileBuilding) { try { inputFolder.Delete(true); } catch { } } } } finally { if (brFst != null) brFst.Close(); bwFst.Close(); bwStr.Close(); if (bwBootBin != null) bwBootBin.Close(); if (bwPartitionBin != null) bwPartitionBin.Close(); if (bwB12Bin != null) bwB12Bin.Close(); } }