예제 #1
0
        public void AlwaysCompressCorrectly()
        {
            using var imgStream = File.OpenRead("G:\\KH2.IMG");
            new Img(imgStream, File.OpenRead("G:\\KH2.IDX").Using(Idx.Read), true)
            .Entries.ToList()
            .Where(x => x.IsCompressed)
            .Where(x => !x.IsStreamed)
            .Select(x => new
            {
                Name  = IdxName.Lookup(x),
                Entry = x,
                Data  = imgStream
                        .SetPosition(x.Offset * 0x800)
                        .ReadBytes((x.BlockLength + 1) * 0x800)
            })
            .ToList()
            .AsParallel()
            .WithDegreeOfParallelism(16)
            .ForAll(x =>
            {
                new MemoryStream(Img.Decompress(x.Data)).Using(stream =>
                {
                    Helpers.AssertStream(stream, inStream =>
                    {
                        var compressedData   = Img.Compress(inStream.ReadAllBytes());
                        var decompressedData = Img.Decompress(compressedData);

                        return(new MemoryStream(decompressedData));
                    });
                });
            });
        }
예제 #2
0
 public void CompressEquallyOrBetter(string fileName, int expectLength) =>
 File.OpenRead($"kh2/res/{fileName}.dec").Using(stream =>
 {
     var compress = Img.Compress(stream.ReadAllBytes());
     if (compress.Length > expectLength)
     {
         throw new XunitException($"Compressed file is {compress.Length} byte, but the official one is {expectLength}.\n" +
                                  "The compression algorithm is not performant enough.");
     }
 });
예제 #3
0
파일: ImgTests.cs 프로젝트: xorllc/OpenKh
        public void CompressAtLEastEquallyOrMore(string fileName) =>
        File.OpenRead($"kh2/res/{fileName}.dec").Using(stream =>
        {
            const int CompressionGrace             = 6;
            const int OriginalCompressedSizeLength = 0x167 + CompressionGrace;

            var compress = Img.Compress(stream.ReadAllBytes());
            if (compress.Length > OriginalCompressedSizeLength)
            {
                throw new XunitException($"Compressed file is {compress.Length} byte, but the official one is {OriginalCompressedSizeLength}.\n" +
                                         "The compression algorithm is not performant enough.");
            }
        });
예제 #4
0
파일: ImgTests.cs 프로젝트: xorllc/OpenKh
        public void CompressChunkSimple()
        {
            const int HeaderSize = 5;
            var       dec        = new byte[0x29];
            var       cmp        = Img.Compress(dec);

            var expected = new byte[]
            {
                0x25, 0x01, 0x01, 0x00
            };

            Assert.Equal(expected.Length, cmp.Length - HeaderSize);
            Assert.Equal(expected, cmp.Take(cmp.Length - HeaderSize));
        }
예제 #5
0
 public void CompressCorrectlyWhenKeyIsFoundInTheData() =>
 new MemoryStream(Enumerable.Range(0, 0x100).Select(x => (byte)x).ToArray()).Using(stream =>
 {
     Helpers.AssertStream(stream, inStream =>
                          new MemoryStream(Img.Decompress(Img.Compress(inStream.ReadAllBytes()))));
 });
예제 #6
0
 public void CompressCorrectly(string fileName) =>
 File.OpenRead($"kh2/res/{fileName}.dec").Using(stream =>
 {
     Helpers.AssertStream(stream, inStream =>
                          new MemoryStream(Img.Decompress(Img.Compress(inStream.ReadAllBytes()))));
 });
예제 #7
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);
            }
예제 #8
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);
                }