diff --git a/src/help.cpp b/src/help.cpp index 69587ccb..9ccb6ce4 100644 --- a/src/help.cpp +++ b/src/help.cpp @@ -103,17 +103,16 @@ struct PackerNames { size_t names_count; const Options *o; PackerNames() : names_count(0), o(nullptr) {} - void add(const Packer *packer) { + void add(const PackerBase *pb) { assert(names_count < 64); - names[names_count].fname = packer->getFullName(o); - names[names_count].sname = packer->getName(); + names[names_count].fname = pb->getFullName(o); + names[names_count].sname = pb->getName(); names_count++; } - static Packer *visit(Packer *packer, void *user) { + static bool visit(PackerBase *pb, void *user) { PackerNames *self = (PackerNames *) user; - self->add(packer); - delete packer; - return nullptr; + self->add(pb); + return false; } static int __acc_cdecl_qsort cmp_fname(const void *a, const void *b) { return strcmp(((const Entry *) a)->fname, ((const Entry *) b)->fname); @@ -129,7 +128,7 @@ static void list_all_packers(FILE *f, int verbose) { o.reset(); PackerNames pn; pn.o = &o; - PackMaster::visitAllPackers(PackerNames::visit, nullptr, &o, &pn); + (void) PackMaster::visitAllPackers(PackerNames::visit, nullptr, &o, &pn); qsort(pn.names, pn.names_count, sizeof(PackerNames::Entry), PackerNames::cmp_fname); size_t pos = 0; for (size_t i = 0; i < pn.names_count; ++i) { diff --git a/src/packer.cpp b/src/packer.cpp index 1bce1da9..b9cb9e1a 100644 --- a/src/packer.cpp +++ b/src/packer.cpp @@ -36,7 +36,7 @@ // **************************************************************************/ -Packer::Packer(InputFile *f) : fi(f) { +Packer::Packer(InputFile *f) : PackerBase(f) { if (fi != nullptr) file_size = fi->st_size(); mem_size_assert(1, file_size_u); diff --git a/src/packer.h b/src/packer.h index 54f463e6..621638df 100644 --- a/src/packer.h +++ b/src/packer.h @@ -31,6 +31,7 @@ class InputFile; class OutputFile; +class PackerBase; class Packer; class UiPacker; class Filter; @@ -41,9 +42,10 @@ class Filter; **************************************************************************/ class PackHeader final { + friend class PackerBase; friend class Packer; - // these are strictly private to friend Packer + // these are strictly private to friends PackerBase and Packer explicit PackHeader() noexcept; void putPackHeader(SPAN_S(byte) p); bool decodePackHeaderFromBuf(SPAN_S(const byte) b, int blen); @@ -97,21 +99,17 @@ bool ph_testOverlappingDecompression(const PackHeader &ph, SPAN_P(const byte) bu unsigned overlap_overhead); /************************************************************************* -// abstract base class for packers +// purely abstract minimal base class for all packers // -// FIXME later: this class is way too fat and badly needs a decomposition +// clients: PackMaster, UiPacker **************************************************************************/ -class Packer { +class PackerBase { friend class UiPacker; - protected: - explicit Packer(InputFile *f); - + explicit PackerBase(InputFile *f) noexcept : fi(f) {} public: - virtual ~Packer() noexcept; - virtual void assertPacker() const; - + virtual ~PackerBase() noexcept {} // getVersion() enables detecting forward incompatibility of unpack() // by old upx when newer upx changes the format of compressed output. virtual int getVersion() const = 0; @@ -122,14 +120,55 @@ public: virtual const int *getCompressionMethods(int method, int level) const = 0; virtual const int *getFilters() const = 0; + // canPack() should throw a cantPackException eplaining why it + // cannot pack a recognized format. + virtual bool canPack() = 0; + // canUnpack() can return -1 meaning "format recognized, but file + // is definitely not packed". See packmast.cpp try_unpack(). + virtual int canUnpack() = 0; + // PackMaster entries - void initPackHeader(); - void updatePackHeader(); - void doPack(OutputFile *fo); - void doUnpack(OutputFile *fo); - void doTest(); - void doList(); - void doFileInfo(); + virtual void assertPacker() const = 0; + virtual void initPackHeader() = 0; + virtual void updatePackHeader() = 0; + virtual void doPack(OutputFile *fo) = 0; + virtual void doUnpack(OutputFile *fo) = 0; + virtual void doTest() = 0; + virtual void doList() = 0; + virtual void doFileInfo() = 0; + +protected: + InputFile *fi = nullptr; + union { // unnamed union + upx_int64_t file_size = 0; // must get set by constructor + upx_uint64_t file_size_u; // explicitly unsigned + }; + PackHeader ph = PackHeader{}; // must be filled by canUnpack() +}; + +/************************************************************************* +// abstract default implementation class for packers +// +// Packer can be viewed as "PackerDefaultImplV1"; it is grown historically +// and still would benefit from a decomposition +**************************************************************************/ + +class Packer : public PackerBase { +protected: + explicit Packer(InputFile *f); + +public: + virtual ~Packer() noexcept; + + // PackMaster entries + virtual void assertPacker() const override; + virtual void initPackHeader() final override; + virtual void updatePackHeader() final override; + virtual void doPack(OutputFile *fo) final override; + virtual void doUnpack(OutputFile *fo) final override; + virtual void doTest() final override; + virtual void doList() final override; + virtual void doFileInfo() final override; // unpacker capabilities virtual bool canUnpackVersion(int version) const { return (version >= 8); } @@ -148,14 +187,6 @@ protected: virtual void list(); virtual void fileInfo(); -public: - // canPack() should throw a cantPackException eplaining why it - // cannot pack a recognized format. - virtual bool canPack() = 0; - // canUnpack() can return -1 meaning "format recognized, but file - // is definitely not packed". See packmast.cpp try_unpack(). - virtual int canUnpack() = 0; - protected: // main compression drivers bool compress(SPAN_P(byte) i_ptr, unsigned i_len, SPAN_P(byte) o_ptr, @@ -327,14 +358,8 @@ protected: protected: const N_BELE_RTP::AbstractPolicy *bele = nullptr; // target endianness - InputFile *fi = nullptr; - union { // unnamed union - upx_int64_t file_size = 0; // will get set by constructor - upx_uint64_t file_size_u; // explicitly unsigned - }; - - PackHeader ph = PackHeader{}; // must be filled by canUnpack() + // PackHeader int ph_format = -1; int ph_version = -1; diff --git a/src/packmast.cpp b/src/packmast.cpp index c96a7bbd..3ea59a55 100644 --- a/src/packmast.cpp +++ b/src/packmast.cpp @@ -25,6 +25,8 @@ */ +#include "headers.h" +#include #include "conf.h" #include "file.h" #include "packmast.h" @@ -87,35 +89,32 @@ PackMaster::~PackMaster() noexcept { // **************************************************************************/ -static Packer *try_can_pack(Packer *p, void *user) { +static bool try_can_pack(PackerBase *pb, void *user) may_throw { InputFile *f = (InputFile *) user; try { - p->initPackHeader(); + pb->initPackHeader(); f->seek(0, SEEK_SET); - if (p->canPack()) { + if (pb->canPack()) { if (opt->cmd == CMD_COMPRESS) - p->updatePackHeader(); + pb->updatePackHeader(); f->seek(0, SEEK_SET); - return p; + return true; } } catch (const IOException &) { - } catch (...) { - delete p; - throw; + // ignored } - delete p; - return nullptr; + return false; } -static Packer *try_can_unpack(Packer *p, void *user) { +static bool try_can_unpack(PackerBase *pb, void *user) may_throw { InputFile *f = (InputFile *) user; try { - p->initPackHeader(); + pb->initPackHeader(); f->seek(0, SEEK_SET); - int r = p->canUnpack(); + int r = pb->canUnpack(); if (r > 0) { f->seek(0, SEEK_SET); - return p; + return true; } if (r < 0) { // FIXME - could stop testing all other unpackers at this time @@ -123,12 +122,8 @@ static Packer *try_can_unpack(Packer *p, void *user) { } } catch (const IOException &) { // ignored - } catch (...) { - delete p; - throw; } - delete p; - return nullptr; + return false; } /************************************************************************* @@ -136,19 +131,18 @@ static Packer *try_can_unpack(Packer *p, void *user) { **************************************************************************/ /*static*/ -Packer *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const Options *o, void *user) { - +PackerBase *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const Options *o, + void *user) may_throw { #define D(Klass) \ ACC_BLOCK_BEGIN \ COMPILE_TIME_ASSERT(std::is_nothrow_destructible_v) \ - Klass *kp = new Klass(f); \ - kp->assertPacker(); \ + auto pb = std::unique_ptr(new Klass(f)); \ + pb->assertPacker(); \ if (o->debug.debug_level) \ - fprintf(stderr, "visitAllPackers: (ver=%d, fmt=%3d) %s\n", kp->getVersion(), \ - kp->getFormat(), #Klass); \ - Packer *p = func(kp, user); \ - if (p != nullptr) \ - return p; \ + fprintf(stderr, "visitAllPackers: (ver=%d, fmt=%3d) %s\n", pb->getVersion(), \ + pb->getFormat(), #Klass); \ + if (func(pb.get(), user)) \ + return pb.release(); \ ACC_BLOCK_END // NOTE: order of tries is important !!! @@ -235,18 +229,18 @@ Packer *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const Optio #undef D } -/*static*/ Packer *PackMaster::getPacker(InputFile *f) { - Packer *p = visitAllPackers(try_can_pack, f, opt, f); - if (!p) +/*static*/ PackerBase *PackMaster::getPacker(InputFile *f) { + PackerBase *pb = visitAllPackers(try_can_pack, f, opt, f); + if (!pb) throwUnknownExecutableFormat(); - return p; + return pb; } -/*static*/ Packer *PackMaster::getUnpacker(InputFile *f) { - Packer *p = visitAllPackers(try_can_unpack, f, opt, f); - if (!p) +/*static*/ PackerBase *PackMaster::getUnpacker(InputFile *f) { + PackerBase *pb = visitAllPackers(try_can_unpack, f, opt, f); + if (!pb) throwNotPacked(); - return p; + return pb; } /************************************************************************* diff --git a/src/packmast.h b/src/packmast.h index 379cccec..ab7709cf 100644 --- a/src/packmast.h +++ b/src/packmast.h @@ -27,12 +27,12 @@ #pragma once -class Packer; +class PackerBase; class InputFile; class OutputFile; /************************************************************************* -// dispatch to a concrete subclass of class Packer; see work.cpp +// dispatch to a concrete subclass of class PackerBase; see work.cpp **************************************************************************/ class PackMaster final { @@ -46,15 +46,16 @@ public: void list(); void fileInfo(); - typedef Packer *(*visit_func_t)(Packer *p, void *user); - static Packer *visitAllPackers(visit_func_t, InputFile *f, const Options *, void *user); + typedef bool (*visit_func_t)(PackerBase *pb, void *user); + static PackerBase *visitAllPackers(visit_func_t, InputFile *f, const Options *, void *user) + may_throw; private: - OwningPointer(Packer) packer = nullptr; // owner - InputFile *fi = nullptr; // reference + OwningPointer(PackerBase) packer = nullptr; // owner + InputFile *fi = nullptr; // reference - static Packer *getPacker(InputFile *f); - static Packer *getUnpacker(InputFile *f); + static PackerBase *getPacker(InputFile *f); + static PackerBase *getUnpacker(InputFile *f); // setup local options for each file Options local_options; diff --git a/src/ui.cpp b/src/ui.cpp index 2823a15e..9e69309f 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -156,7 +156,7 @@ static const char *mkline(upx_uint64_t fu_len, upx_uint64_t fc_len, upx_uint64_t // **************************************************************************/ -UiPacker::UiPacker(const Packer *p_) : p(p_) { +UiPacker::UiPacker(const PackerBase *pb_) : pb(pb_) { static upx_std_once_flag init_done; upx_std_call_once(init_done, init_global_constants); @@ -195,12 +195,12 @@ UiPacker::~UiPacker() noexcept { void UiPacker::printInfo(int nl) { if (opt->all_methods && s->total_passes > 1) - con_fprintf(stdout, "Compressing %s [%s]%s", p->fi->getName(), p->getName(), + con_fprintf(stdout, "Compressing %s [%s]%s", pb->fi->getName(), pb->getName(), nl ? "\n" : ""); else { char method_name[32 + 1]; - set_method_name(method_name, sizeof(method_name), p->ph.method, p->ph.level); - con_fprintf(stdout, "Compressing %s [%s, %s]%s", p->fi->getName(), p->getName(), + set_method_name(method_name, sizeof(method_name), pb->ph.method, pb->ph.level); + con_fprintf(stdout, "Compressing %s [%s, %s]%s", pb->fi->getName(), pb->getName(), method_name, nl ? "\n" : ""); } } @@ -240,7 +240,7 @@ void UiPacker::startCallback(unsigned u_len, unsigned step, int pass, int total_ cb.user = this; // parameter for static function UiPacker::progress_callback() if (s->mode == M_CB_TERM) { - const char *fname = fn_basename(p->fi->getName()); + const char *fname = fn_basename(pb->fi->getName()); int l = (int) strlen(fname); if (l > 0 && l <= 30) { strcpy(&s->msg_buf[s->bar_pos], fname); @@ -462,13 +462,13 @@ void UiPacker::uiPackEnd(const OutputFile *fo) { printClearLine(stdout); } - const char *name = p->fi->getName(); + const char *name = pb->fi->getName(); if (opt->output_name) name = opt->output_name; else if (opt->to_stdout) name = ""; con_fprintf(stdout, "%s\n", - mkline(p->ph.u_file_size, fo->st_size(), p->ph.u_len, p->ph.c_len, p->getName(), + mkline(pb->ph.u_file_size, fo->st_size(), pb->ph.u_len, pb->ph.c_len, pb->getName(), fn_basename(name))); printSetNl(0); } @@ -493,14 +493,14 @@ void UiPacker::uiUnpackEnd(const OutputFile *fo) { if (s->mode == M_QUIET) return; - const char *name = p->fi->getName(); + const char *name = pb->fi->getName(); if (opt->output_name) name = opt->output_name; else if (opt->to_stdout) name = ""; con_fprintf(stdout, "%s\n", - mkline(fo->getBytesWritten(), p->file_size, p->ph.u_len, p->ph.c_len, p->getName(), - fn_basename(name), true)); + mkline(fo->getBytesWritten(), pb->file_size, pb->ph.u_len, pb->ph.c_len, + pb->getName(), fn_basename(name), true)); printSetNl(0); } @@ -516,10 +516,10 @@ void UiPacker::uiUnpackEnd(const OutputFile *fo) { void UiPacker::uiListStart() { total_files++; } void UiPacker::uiList() { - const char *name = p->fi->getName(); + const char *name = pb->fi->getName(); con_fprintf( stdout, "%s\n", - mkline(p->ph.u_file_size, p->file_size, p->ph.u_len, p->ph.c_len, p->getName(), name)); + mkline(pb->ph.u_file_size, pb->file_size, pb->ph.u_len, pb->ph.c_len, pb->getName(), name)); printSetNl(0); } @@ -545,7 +545,7 @@ void UiPacker::uiTestStart() { total_files++; if (opt->verbose >= 1) { - con_fprintf(stdout, "testing %s ", p->fi->getName()); + con_fprintf(stdout, "testing %s ", pb->fi->getName()); fflush(stdout); printSetNl(1); } @@ -570,16 +570,16 @@ bool UiPacker::uiFileInfoStart() { total_files++; int fg = con_fg(stdout, FG_CYAN); - con_fprintf(stdout, "%s [%s, %s]\n", p->fi->getName(), p->getFullName(opt), p->getName()); + con_fprintf(stdout, "%s [%s, %s]\n", pb->fi->getName(), pb->getFullName(opt), pb->getName()); fg = con_fg(stdout, fg); UNUSED(fg); - if (p->ph.c_len > 0) { - con_fprintf(stdout, " %8llu bytes", p->file_size_u); + if (pb->ph.c_len > 0) { + con_fprintf(stdout, " %8llu bytes", pb->file_size_u); con_fprintf(stdout, ", compressed by UPX %d, method %d, level %d, filter 0x%02x/0x%02x\n", - p->ph.version, p->ph.method, p->ph.level, p->ph.filter, p->ph.filter_cto); + pb->ph.version, pb->ph.method, pb->ph.level, pb->ph.filter, pb->ph.filter_cto); return false; } else { - con_fprintf(stdout, " %8llu bytes", p->file_size_u); + con_fprintf(stdout, " %8llu bytes", pb->file_size_u); con_fprintf(stdout, ", not compressed by UPX\n"); return true; } @@ -624,10 +624,10 @@ void UiPacker::uiFileInfoEnd() { uiUpdate(); } } void UiPacker::uiUpdate(upx_off_t fc_len, upx_off_t fu_len) { - update_fc_len = (fc_len >= 0) ? fc_len : p->file_size_u; - update_fu_len = (fu_len >= 0) ? fu_len : p->ph.u_file_size; - update_c_len = p->ph.c_len; - update_u_len = p->ph.u_len; + update_fc_len = (fc_len >= 0) ? fc_len : pb->file_size_u; + update_fu_len = (fu_len >= 0) ? fu_len : pb->ph.u_file_size; + update_c_len = pb->ph.c_len; + update_u_len = pb->ph.u_len; } /*static*/ void UiPacker::uiConfirmUpdate() { diff --git a/src/ui.h b/src/ui.h index 8bf94f0a..5f0f07b1 100644 --- a/src/ui.h +++ b/src/ui.h @@ -28,7 +28,7 @@ #pragma once class OutputFile; -class Packer; +class PackerBase; /************************************************************************* // @@ -36,7 +36,7 @@ class Packer; class UiPacker final { public: - explicit UiPacker(const Packer *p_); + explicit UiPacker(const PackerBase *); public: virtual ~UiPacker() noexcept; @@ -84,7 +84,7 @@ public: protected: virtual void printInfo(int nl = 0); - const Packer *const p; // reference + const PackerBase *const pb; // reference, required // callback upx_callback_t cb = {}; diff --git a/src/work.cpp b/src/work.cpp index 56cdb037..18f323f4 100644 --- a/src/work.cpp +++ b/src/work.cpp @@ -27,7 +27,7 @@ // This file implements the central loop, and it uses class PackMaster to // dispatch. PackMaster by itself will instantiate a concrete subclass -// of class Packer which then does the actual work. +// of class PackerBase which then does the actual work. // And see p_com.cpp for a simple executable format. #include "conf.h"