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!"); }