From 943f300618b5e71d88e6f6060284d8095d52146b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 11 Oct 2015 11:38:26 -0700 Subject: [PATCH] Add --decompress switch. --- cli/cli.cpp | 17 +++++++++++++++-- src/compress.cpp | 1 + src/compress.h | 4 +++- src/output.cpp | 20 ++++++++++++++++++-- 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/cli/cli.cpp b/cli/cli.cpp index cf3f93e0c..6a8193586 100644 --- a/cli/cli.cpp +++ b/cli/cli.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include "../src/compress.h" @@ -20,6 +21,7 @@ void show_help(const char *arg0) { fprintf(stderr, " --quiet Suppress status output\n"); fprintf(stderr, " --crc Log CRC32 checksums, ignore output files and methods\n"); fprintf(stderr, " --fast Use only basic zlib or lz4 for fastest result\n"); + fprintf(stderr, " --decompress Write out to raw ISO, decompressing as needed\n"); fprintf(stderr, " --block=N Specify a block size (default is 2048)\n"); fprintf(stderr, " Most readers only support the 2048 size\n"); fprintf(stderr, " --format=VER Specify cso version (options: cso1, cso2, zso)\n"); @@ -105,6 +107,7 @@ struct Arguments { bool smallest; bool quiet; bool crc; + bool decompress; }; void default_args(Arguments &args) { @@ -124,6 +127,7 @@ void default_args(Arguments &args) { args.smallest = false; args.quiet = false; args.crc = false; + args.decompress = false; } int parse_args(Arguments &args, int argc, char *argv[]) { @@ -166,6 +170,8 @@ int parse_args(Arguments &args, int argc, char *argv[]) { args.fast = true; } else if (has_arg(i, argv, "--smallest")) { args.smallest = true; + } else if (has_arg(i, argv, "--decompress")) { + args.decompress = true; } else if (has_arg_method(i, argv, "--use-", method)) { args.flags_use |= method; } else if (has_arg_method(i, argv, "--no-", method)) { @@ -220,9 +226,13 @@ int validate_args(const char *arg0, Arguments &args) { continue; } - const std::string ext = args.inputs[i].substr(args.inputs[i].size() - 4); - if (ext == ".iso" || ext == ".ISO") { + std::string ext = args.inputs[i].substr(args.inputs[i].size() - 4); + std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower); + + if (!args.decompress && ext == ".iso") { args.outputs.push_back(args.inputs[i].substr(0, args.inputs[i].size() - 4) + ".cso"); + } else if (args.decompress && (ext == ".cso" || ext == ".zso")) { + args.outputs.push_back(args.inputs[i].substr(0, args.inputs[i].size() - 4) + ".iso"); } } @@ -266,6 +276,9 @@ int validate_args(const char *arg0, Arguments &args) { if (args.smallest) { args.flags_final |= maxcso::TASKFLAG_FORCE_ALL; } + if (args.decompress) { + args.flags_final |= maxcso::TASKFLAG_DECOMPRESS; + } args.flags_final |= args.flags_fmt; return 0; diff --git a/src/compress.cpp b/src/compress.cpp index 40867a167..c643a56a9 100644 --- a/src/compress.cpp +++ b/src/compress.cpp @@ -12,6 +12,7 @@ namespace maxcso { // Anything above this is insane. This value is even insane. static const uint32_t MAX_BLOCK_SIZE = 0x40000; +// This actually handles decompression too. They're basically the same. class CompressionTask { public: CompressionTask(uv_loop_t *loop, const Task &t) diff --git a/src/compress.h b/src/compress.h index 21fe50ee9..daee87af4 100644 --- a/src/compress.h +++ b/src/compress.h @@ -7,7 +7,7 @@ namespace maxcso { -static const char *VERSION = "1.4.6"; +static const char *VERSION = "1.5.0"; struct Task; @@ -43,6 +43,8 @@ enum TaskFlags { TASKFLAG_NO_LZ4_HC_BRUTE = 0x200, TASKFLAG_NO_ALL = TASKFLAG_NO_ZLIB | TASKFLAG_NO_ZOPFLI | TASKFLAG_NO_7ZIP | TASKFLAG_NO_LZ4, + + TASKFLAG_DECOMPRESS = 0x400, }; typedef std::function ProgressCallback; diff --git a/src/output.cpp b/src/output.cpp index 2ac985019..c56468e82 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -47,8 +47,14 @@ void Output::SetFile(uv_file file, int64_t srcSize, uint32_t blockSize, CSOForma const uint32_t sectors = static_cast((srcSize + blockSize_ - 1) >> blockShift_); // Start after the header and index, which we'll fill in later. index_ = new uint32_t[sectors + 1]; - // Start after the end of the index data and header. - dstPos_ = sizeof(CSOHeader) + (sectors + 1) * sizeof(uint32_t); + if (flags_ & TASKFLAG_DECOMPRESS) { + // Decompressing, so no header. + // We still track the index for code simplicity, but throw it away. + dstPos_ = 0; + } else { + // Start after the end of the index data and header. + dstPos_ = sizeof(CSOHeader) + (sectors + 1) * sizeof(uint32_t); + } // TODO: We might be able to optimize shift better by running through the data. // That would require either a second pass or keeping the entire result in RAM. @@ -266,6 +272,9 @@ void Output::HandleReadySector(Sector *sector) { } bool Output::ShouldCompress(int64_t pos, uint8_t *buffer) { + if (flags_ & TASKFLAG_DECOMPRESS) { + return false; + } if (flags_ & TASKFLAG_FORCE_ALL) { return true; } @@ -299,6 +308,13 @@ void Output::Flush() { return; } + if (flags_ & TASKFLAG_DECOMPRESS) { + // Okay, we're done. No header or index to write when decompressing. + state_ |= STATE_INDEX_WRITTEN; + CheckFinish(); + return; + } + CSOHeader *header = new CSOHeader; if (fmt_ == CSO_FMT_ZSO) { memcpy(header->magic, ZSO_MAGIC, sizeof(header->magic));