예제 #1
0
파일: IdxTests.cs 프로젝트: Fotia13/OpenKh
        public void WriteIdxEntry() => Helpers.AssertStream(CreateMockIdxStream(1, 2, 3, 4, 5), stream =>
        {
            var outStream = new MemoryStream();
            Idx.Write(outStream, Idx.Read(stream));

            return(outStream);
        });
예제 #2
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)
                {
                    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);
            }
예제 #3
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);
                }