public void WriteIdxEntry() => Helpers.AssertStream(CreateMockIdxStream(1, 2, 3, 4, 5), stream => { var outStream = new MemoryStream(); Idx.Write(outStream, Idx.Read(stream)); return(outStream); });
protected int OnExecute(CommandLineApplication app) { const long EsitmatedMaximumImgFileSize = 4L * 1024 * 1024 * 1024; // 4GB const int EsitmatedMaximumIdxFileSize = 600 * 1024; // 600KB const int EstimatedMaximumIdxEntryAmountToBeValid = EsitmatedMaximumIdxFileSize / 0x10 - 4; using var isoStream = File.Open(InputIso, FileMode.Open, FileAccess.ReadWrite); if (IdxIsoBlock == -1 || ImgIsoBlock == -1) { const int needleLength = 0x0B; var imgNeedle = new byte[needleLength] { 0x01, 0x09, 0x4B, 0x48, 0x32, 0x2E, 0x49, 0x4D, 0x47, 0x3B, 0x31 }; var idxNeedle = new byte[needleLength] { 0x01, 0x09, 0x4B, 0x48, 0x32, 0x2E, 0x49, 0x44, 0x58, 0x3B, 0x31 }; const uint basePosition = 0x105 * 0x800; for (int i = 0; i < 0x500; i++) { isoStream.Position = basePosition + i; var hayRead = isoStream.ReadBytes(needleLength); var idxCmp = hayRead.SequenceEqual(idxNeedle); var imgCmp = hayRead.SequenceEqual(imgNeedle); if (imgCmp || idxCmp) { isoStream.Position -= 0x24; var blockStack = isoStream.ReadBytes(0x04); var blockCorrect = new byte[0x04] { blockStack[3], blockStack[2], blockStack[1], blockStack[0] }; if (idxCmp && IdxIsoBlock == -1) { IdxIsoBlock = BitConverter.ToInt32(blockCorrect); } else if (imgCmp && ImgIsoBlock == -1) { ImgIsoBlock = BitConverter.ToInt32(blockCorrect); } } } if (IdxIsoBlock == -1 || ImgIsoBlock == -1) { throw new IOException("Could not determine the LBA Offsets of KH2.IDX or KH2.IMG, is this ISO valid?"); } } var idxStream = OpenIsoSubStream(isoStream, IdxIsoBlock, EsitmatedMaximumIdxFileSize); using var imgStream = OpenIsoSubStream(isoStream, ImgIsoBlock, EsitmatedMaximumImgFileSize); var idxEntryCount = idxStream.ReadInt32(); if (idxEntryCount > EstimatedMaximumIdxEntryAmountToBeValid) { throw new CustomException("There is a high chance that the IDX block is not valid, therefore the injection will terminate to avoid corruption."); } var idxEntries = Idx.Read(idxStream.SetPosition(0)); var entry = idxEntries.FirstOrDefault(x => x.Hash32 == Idx.GetHash32(FilePath) && x.Hash16 == Idx.GetHash16(FilePath)); if (entry == null) { idxStream = GetIdxStreamWhichContainsTargetedFile(idxEntries, imgStream, FilePath); if (idxStream == null) { throw new CustomException($"The file {FilePath} has not been found inside the KH2.IDX, therefore the injection will terminate."); } idxEntries = Idx.Read(idxStream.SetPosition(0)); entry = idxEntries.FirstOrDefault(x => x.Hash32 == Idx.GetHash32(FilePath) && x.Hash16 == Idx.GetHash16(FilePath)); } var inputData = File.ReadAllBytes(InputFile); var decompressedLength = inputData.Length; if (Uncompressed == false) { inputData = Img.Compress(inputData); } var blockCountRequired = (inputData.Length + 0x7ff) / 0x800 - 1; if (blockCountRequired > entry.BlockLength) { throw new CustomException($"The file to inject is too big: the actual is {inputData.Length} but the maximum allowed is {GetLength(entry.BlockLength)}."); } imgStream.SetPosition(GetOffset(entry.Offset)); // Clean completely the content of the previous file to not mess up the decompression imgStream.Write(new byte[GetLength(entry.BlockLength)]); imgStream.SetPosition(GetOffset(entry.Offset)); imgStream.Write(inputData); entry.IsCompressed = !Uncompressed; entry.Length = decompressedLength; // we are intentionally not patching entry.BlockLength because it would not allow to insert back bigger files. Idx.Write(idxStream.SetPosition(0), idxEntries); return(0); }
protected int OnExecute(CommandLineApplication app) { const long EsitmatedMaximumImgFileSize = 4L * 1024 * 1024 * 1024; // 4GB const int EsitmatedMaximumIdxFileSize = 600 * 1024; // 600KB const int EstimatedMaximumIdxEntryAmountToBeValid = EsitmatedMaximumIdxFileSize / 0x10 - 4; using var isoStream = File.Open(InputIso, FileMode.Open, FileAccess.ReadWrite); if (IdxIsoBlock == -1 || ImgIsoBlock == -1) { var bufferedStream = new BufferedStream(isoStream); IdxIsoBlock = IsoUtility.GetFileOffset(bufferedStream, "KH2.IDX;1"); ImgIsoBlock = IsoUtility.GetFileOffset(bufferedStream, "KH2.IMG;1"); if (IdxIsoBlock == -1 || ImgIsoBlock == -1) { throw new IOException("Could not determine the LBA Offsets of KH2.IDX or KH2.IMG, is this ISO valid?"); } } var idxStream = OpenIsoSubStream(isoStream, IdxIsoBlock, EsitmatedMaximumIdxFileSize); using var imgStream = OpenIsoSubStream(isoStream, ImgIsoBlock, EsitmatedMaximumImgFileSize); var idxEntryCount = idxStream.ReadInt32(); if (idxEntryCount > EstimatedMaximumIdxEntryAmountToBeValid) { throw new CustomException("There is a high chance that the IDX block is not valid, therefore the injection will terminate to avoid corruption."); } var idxEntries = Idx.Read(idxStream.SetPosition(0)); var entry = idxEntries.FirstOrDefault(x => x.Hash32 == Idx.GetHash32(FilePath) && x.Hash16 == Idx.GetHash16(FilePath)); if (entry == null) { idxStream = GetIdxStreamWhichContainsTargetedFile(idxEntries, imgStream, FilePath); if (idxStream == null) { throw new CustomException($"The file {FilePath} has not been found inside the KH2.IDX, therefore the injection will terminate."); } idxEntries = Idx.Read(idxStream.SetPosition(0)); entry = idxEntries.FirstOrDefault(x => x.Hash32 == Idx.GetHash32(FilePath) && x.Hash16 == Idx.GetHash16(FilePath)); } var inputData = File.ReadAllBytes(InputFile); var decompressedLength = inputData.Length; if (Uncompressed == false) { inputData = Img.Compress(inputData); } var blockCountRequired = (inputData.Length + 0x7ff) / 0x800 - 1; if (blockCountRequired > entry.BlockLength) { throw new CustomException($"The file to inject is too big: the actual is {inputData.Length} but the maximum allowed is {GetLength(entry.BlockLength)}."); } imgStream.SetPosition(GetOffset(entry.Offset)); // Clean completely the content of the previous file to not mess up the decompression imgStream.Write(new byte[GetLength(entry.BlockLength)]); imgStream.SetPosition(GetOffset(entry.Offset)); imgStream.Write(inputData); entry.IsCompressed = !Uncompressed; entry.Length = decompressedLength; // we are intentionally not patching entry.BlockLength because it would not allow to insert back bigger files. Idx.Write(idxStream.SetPosition(0), idxEntries); return(0); }