示例#1
0
        public ZraCompressionStorageHack(IStorage inStorage, byte compressionLevel, uint frameSize, byte[] metaBuffer = null, string tempPath = null, bool leaveOpen = false)
        {
            _leaveOpen = leaveOpen;
            inStorage.GetSize(out long inSize);

            if (tempPath == null)
            {
                tempPath = Path.GetTempFileName();
            }
            else
            {
                Directory.CreateDirectory(tempPath);
                tempPath = Path.Combine(tempPath, $"temp{new Random().Next()}.tmp");
            }

            FileStream tempFile = new FileStream(tempPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.RandomAccess | FileOptions.DeleteOnClose);

            using (ZraCompressionStream compressionStream = new ZraCompressionStream(tempFile, (ulong)inSize, compressionLevel, frameSize, metaBuffer, true))
            {
                inStorage.CopyToStream(compressionStream, (int)frameSize);
            }

            if (!leaveOpen)
            {
                inStorage.Dispose();
            }

            _baseStorage = new StreamStorage(tempFile, leaveOpen);
            DisposeList.Add(tempFile.Dispose);
        }
示例#2
0
        public static void Main(string[] cmdArgs)
        {
            string outDirectoryPath = null;
            bool   compress         = true;
            bool   showHelp         = false;
            byte   compressionLevel = 9;
            uint   frameSize        = 131072;

            OptionSet optionSet = new OptionSet
            {
                { "h|help", "Show this message and exit", _ => showHelp = true },
                { "d|decompress", "Set the operation mode to decompress.\n(Compress by default)", _ => compress = false },
                { "l|level=", "zStd compression level used to compress the file.", s => compressionLevel = byte.Parse(s) },
                { "f|framesize=", "Size of a frame used to split a file.", s => frameSize = uint.Parse(s) },
                { "o|output=", "The directory to output the compressed file.\n(Defaults to the same dir as input file)", s => outDirectoryPath = s }
            };

            List <string> args = optionSet.Parse(cmdArgs);

            if (showHelp)
            {
                Console.WriteLine("zratoolnet - Copyright (c) 2021 Xpl0itR, ZRA Contributors");
                Console.WriteLine("Usage: zratoolnet(.exe) [options] <path>");
                Console.WriteLine("Options:");
                optionSet.WriteOptionDescriptions(Console.Out);
                return;
            }

            if (args.Count < 1 || !File.Exists(args[0]))
            {
                Console.WriteLine("Input file does not exist!");
                return;
            }

            outDirectoryPath ??= Path.GetDirectoryName(args[0]);

            if (!Directory.Exists(outDirectoryPath))
            {
                Console.WriteLine("Out directory doesn't exist! Attempting to create...");
                Directory.CreateDirectory(outDirectoryPath);
            }

            if (compressionLevel < 1 || compressionLevel > 22)
            {
                Console.WriteLine("You must enter a valid compression level!");
                return;
            }

            string inFileName  = args[0];
            string outFilePath = Path.Join(outDirectoryPath,
                                           compress
                                               ? $"{Path.GetFileName(inFileName)}.zra"
                                               : Path.GetFileNameWithoutExtension(inFileName));

            using FileStream inStream  = File.OpenRead(inFileName);
            using FileStream outStream = File.OpenWrite(outFilePath);

            if (compress)
            {
                using ZraCompressionStream compressionStream = new ZraCompressionStream(outStream, (ulong)inStream.Length, compressionLevel, frameSize);
                inStream.CopyTo(compressionStream, (int)frameSize);
            }
            else
            {
                using ZraFullDecompressionStream decompressionStream = new ZraFullDecompressionStream(inStream);
                decompressionStream.CopyTo(outStream);
            }
        }
示例#3
0
        public static void Main(string[] cmdArgs)
        {
            OptionSet optionSet = new OptionSet
            {
                { "h|help", "Show this message and exit", _ => ShowHelp = true },
                { "v|dev=", "Load production keys as development keys\n(optional)", _ => IsDev = true },
                { "p|prodkeys=", "Path to a file containing switch production keys.\n(optional)", s => ProdKeyPath = s },
                { "k|titlekeys=", "Path to a file containing switch title keys.\n(optional)", s => TitleKeyPath = s },
                { "l|level=", "zStd compression level used to compress the file.", s => CompressionLevel = byte.Parse(s) },
                { "f|framesize=", "Size of a frame used to split a file.", s => FrameSize = uint.Parse(s) },
                { "t|temp=", "The directory to use for storing temp files.\n(Defaults to OS temp)", s => TempPath = s },
                { "o|output=", "The directory to output the compressed file.\n(Defaults to the same dir as input file)", s => OutDirectoryPath = s }
            };

            List <string> args = optionSet.Parse(cmdArgs);

            if (ShowHelp)
            {
                Console.WriteLine("ZcaTool - Copyright (c) 2020 Xpl0itR");
                Console.WriteLine("Usage: ZcaTool(.exe) [options] <path>");
                Console.WriteLine("Options:");
                optionSet.WriteOptionDescriptions(Console.Out);
                return;
            }

            if (args.Count < 1 || !File.Exists(args[0]))
            {
                throw new Exception("Input file does not exist!");
            }

            if (CompressionLevel < 1 || CompressionLevel > 22)
            {
                throw new Exception("You must enter a valid compression level!");
            }

            KeySet = LoadKeySet();
            OutDirectoryPath ??= Path.GetDirectoryName(args[0]);

            using (IStorage inStorage = new LocalStorage(args[0], FileAccess.Read))
            {
                string fileName = Path.GetFileNameWithoutExtension(args[0]);
                inStorage.GetSize(out long inSize);
                IStorage outStorage = null;

                Stopwatch stopwatch = Stopwatch.StartNew();
                switch (Path.GetExtension(args[0]).ToLower())
                {
                case ".nca":
                    Console.WriteLine($"Compressing {Path.GetFileName(args[0])} [{PrettyFileSize(inSize)}] with ZStandard compression level: {CompressionLevel} and frame size: {FrameSize}");
                    fileName += ".zca";
                    break;

                case ".zca":
                    Console.WriteLine($"Decompressing {Path.GetFileName(args[0])} [{PrettyFileSize(inSize)}]");
                    outStorage = new Nca(KeySet, new ZraDecompressionStream(inStorage.AsStream()).AsStorage()).OpenEncryptedNca();
                    fileName  += ".nca";
                    break;

                case ".nsp":
                    Console.WriteLine($"Compressing {Path.GetFileName(args[0])} [{PrettyFileSize(inSize)}] with ZStandard compression level: {CompressionLevel} and frame size: {FrameSize}");
                    outStorage = ProcessPartitionFileSystem(new PartitionFileSystem(inStorage), PartitionFileSystemType.Standard, true);
                    fileName  += ".zsp";
                    break;

                case ".zsp":
                    Console.WriteLine($"Decompressing {Path.GetFileName(args[0])} [{PrettyFileSize(inSize)}]");
                    outStorage = ProcessPartitionFileSystem(new PartitionFileSystem(inStorage), PartitionFileSystemType.Standard, false);
                    fileName  += ".nsp";
                    break;

                case ".xci":
                    Console.WriteLine($"Compressing {Path.GetFileName(args[0])} [{PrettyFileSize(inSize)}] with ZStandard compression level: {CompressionLevel} and frame size: {FrameSize}");
                    outStorage = ProcessXci(inStorage, true);
                    fileName  += ".zci";
                    break;

                case ".zci":
                    Console.WriteLine($"Decompressing {Path.GetFileName(args[0])} [{PrettyFileSize(inSize)}]");
                    outStorage = ProcessXci(inStorage, false);
                    fileName  += ".xci";
                    break;

                default:
                    throw new Exception("Input file was not of a valid format!");
                }

                long   outSize;
                string filePath = Path.Join(OutDirectoryPath, fileName);
                using (FileStream outStream = File.OpenWrite(filePath))
                {
                    if (Path.GetExtension(args[0]).ToLower() == ".nca")
                    {
                        (IStorage processedNca, byte[] metaBuffer) = ProcessNca(inStorage);
                        processedNca.GetSize(out long ncaLength);

                        using (ZraCompressionStream compressionStream = new ZraCompressionStream(outStream, (ulong)ncaLength, CompressionLevel, FrameSize, metaBuffer, true))
                        {
                            processedNca.CopyToStream(compressionStream, (int)FrameSize);
                        }
                    }
                    else
                    {
                        outStorage.CopyToStream(outStream);
                        outStorage?.Dispose();
                    }

                    outSize = outStream.Length;
                }
                stopwatch.Stop();

                Console.WriteLine($"Out file: {filePath} [{PrettyFileSize(outSize)}]");
                Console.WriteLine($"Time taken: {decimal.Round((decimal)stopwatch.ElapsedMilliseconds / 1000, 2)}s ({stopwatch.ElapsedMilliseconds}ms)");
                Console.WriteLine($"Size Reduction: {decimal.Truncate(100 - (decimal)outSize / inSize * 100)}%");
            }

            Console.WriteLine("Cleaning temp files...");
            ZraCompressionStorageHack.CleanTempFiles();
            Console.WriteLine("Done!");
        }