예제 #1
0
        static void VerifyArgs(string[] args)
        {
            string currentArg;
            int    argcounter = 1;

            bool fullVerify = true;

            while ((currentArg = args[argcounter++]).StartsWith("-"))
            {
                currentArg = currentArg.ToLower();

                if (currentArg == "-fullverify")
                {
                    fullVerify = args[argcounter++].ToLower() == "on";
                }
                else
                {
                    HaltAndCatchFire($"Unknown command: \"{currentArg}\"", 1);
                    return;
                }
            }

            string filename = args[--argcounter];

            if (!File.Exists(filename))
            {
                HaltAndCatchFire($"Input file does not exist: {filename}", 1);
            }

            ExtendedArchive arc;

            try
            {
                arc = new ExtendedArchive(filename);
            }
            catch (PpexException ex)
            {
                if (ex.ErrorCode == PpexException.PpexErrorCode.FileNotPPXArchive ||
                    ex.ErrorCode == PpexException.PpexErrorCode.IncorrectVersionNumber)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine(ex.Message);
                    Console.ResetColor();
                    return;
                }
                else
                {
                    throw;
                }
            }


            Console.CursorVisible = false;

            Action <int, string> UpdateProgress = (i, x) =>
            {
                Console.SetCursorPosition(0, Console.CursorTop);

                string message = $"Verification {i}% complete [{x}]";

                message = message.PadRight(Console.BufferWidth - 1);

                Console.Write(message);
            };

            var orderedChunks = arc.Chunks.OrderBy(x => x.Offset).ToArray();

            Console.WriteLine("Archive name: " + arc.Title);
            Console.WriteLine("File count: " + arc.Files.Count);

            long currentOffset = 0;
            long totalOffset   = orderedChunks.Sum(x => (long)x.CompressedLength);

            HashSet <(Md5Hash, ulong, ulong)> verifiedHashes = new HashSet <(Md5Hash, ulong, ulong)>();

            for (int i = 0; i < orderedChunks.Length; i++)
            {
                ExtendedArchiveChunk chunk = orderedChunks[i];

                using var compressedBuffer = MemoryPool <byte> .Shared.Rent((int) chunk.CompressedLength);

                var compressedMemory = compressedBuffer.Memory.Slice(0, (int)chunk.CompressedLength);

                using (var rawStream = chunk.GetRawStream())
                {
                    rawStream.Read(compressedMemory.Span);
                }

                if (chunk.CRC32 != CRC32.Compute(compressedMemory.Span))
                {
                    HaltAndCatchFire($"Chunk hash mismatch; id: {chunk.ID}, offset: {chunk.Offset}", 8);
                }


                if (fullVerify)
                {
                    using var uncompressedBuffer = MemoryPool <byte> .Shared.Rent((int) chunk.UncompressedLength);

                    var uncompressedMemory = uncompressedBuffer.Memory.Slice(0, (int)chunk.UncompressedLength);

                    chunk.CopyToMemory(uncompressedMemory);

                    foreach (var file in chunk.Files)
                    {
                        var expectedHash = (file.RawSource.Md5, file.RawSource.Offset, file.RawSource.Size);

                        if (verifiedHashes.Contains(expectedHash))
                        {
                            continue;
                        }

                        var actualMd5 =
                            Utility.GetMd5(uncompressedMemory.Span.Slice((int)file.RawSource.Offset,
                                                                         (int)file.RawSource.Size));

                        if ((Md5Hash)file.RawSource.Md5 != (Md5Hash)actualMd5)
                        {
                            HaltAndCatchFire($"File md5 mismatch; chunk id: {chunk.ID}, archive: {file.ArchiveName}, file: {file.Name}", 9);
                        }

                        verifiedHashes.Add((actualMd5, file.RawSource.Offset, file.RawSource.Size));
                    }

                    verifiedHashes.Clear();
                }


                currentOffset += (long)chunk.CompressedLength;

                //int percentage = (int)((float)(100 * i) / (float)orderedChunks.Length);
                int percentage = (int)Math.Round((float)(100 * currentOffset) / (float)totalOffset);

                UpdateProgress(percentage, $"{i + 1}/{orderedChunks.Length} : {ConvertToReadable(currentOffset)}/{ConvertToReadable(totalOffset)}");
            }

            Console.WriteLine();

            Console.WriteLine($"\"{arc.Title}\" successfully verified.");
            Console.CursorVisible = true;
        }