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