Big merge of my working tree: Added options `--all-methods', new

Packer::getCompressionMethods(), improved Packer::compressWithFilters().

committer: mfx <mfx> 978449945 +0000
This commit is contained in:
Markus F.X.J. Oberhumer
2001-01-02 15:39:05 +00:00
parent 1084d86063
commit aa540f85fa
124 changed files with 796 additions and 712 deletions
+153 -106
View File
@@ -2,8 +2,8 @@
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
Copyright (C) 1996-2001 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2001 Laszlo Molnar
All Rights Reserved.
UPX and the UCL library are free software; you can redistribute them
@@ -571,16 +571,20 @@ void Packer::initPackHeader()
ph.u_file_size = file_size;
}
// this is called directly after canPack() from class PackMaster
void Packer::updatePackHeader()
{
// update our local options
if (opt->level < 0)
opt->level = file_size < 512*1024 ? 8 : 7;
opt->method = getCompressionMethod();
// set ph
assert(opt->cmd == CMD_COMPRESS);
//
const int *m = getCompressionMethods(opt->method, opt->level);
ph.method = m[0];
ph.level = opt->level;
ph.method = opt->method;
if (ph.level < 0)
ph.level = file_size < 512*1024 ? 8 : 7;
//
assert(isValidCompressionMethod(ph.method));
assert(1 <= ph.level && ph.level <= 10);
}
@@ -626,7 +630,7 @@ bool Packer::getPackHeader(void *b, int blen)
throwCantUnpack("header size corrupted");
#endif
}
if (ph.method < M_NRV2B_LE32 || ph.method > M_NRV2D_LE16)
if (!isValidCompressionMethod(ph.method))
throwCantUnpack("unknown compression method");
// Some formats might be able to unpack "subformats". Ask them.
@@ -668,6 +672,12 @@ void Packer::checkAlreadyPacked(void *b, int blen)
}
bool Packer::isValidCompressionMethod(int method)
{
return (method >= M_NRV2B_LE32 && method <= M_NRV2D_LE16);
}
/*************************************************************************
// patch util for loader
**************************************************************************/
@@ -924,12 +934,12 @@ void Packer::initLoader(const void *pdata, int plen, int pinfo)
"\n\0"
"$Info: This file is packed with the UPX executable packer http://upx.tsx.org $"
"\n\0"
"$Id: UPX " UPX_VERSION_STRING " Copyright (C) 1996-2000 the UPX Team. All Rights Reserved. $"
"$Id: UPX " UPX_VERSION_STRING " Copyright (C) 1996-2001 the UPX Team. All Rights Reserved. $"
"\n";
static const char identsmall[] =
"\n"
"$Id: UPX (C) 1996-2000 the UPX Team. All Rights Reserved. http://upx.tsx.org $"
"$Id: UPX (C) 1996-2001 the UPX Team. All Rights Reserved. http://upx.tsx.org $"
"\n";
if (opt->small)
@@ -1059,8 +1069,8 @@ void Packer::addFilter32(int filter_id)
/*************************************************************************
// Try compression with several filters, choose the best or first one.
// Needs buildLoader().
// Try compression with several methods and filters, choose the best
/ or first working one. Needs buildLoader().
//
// Required inputs:
// this->ph
@@ -1072,18 +1082,18 @@ void Packer::addFilter32(int filter_id)
//
// - updates this->ph
// - updates *ft
// - ibuf[] is restored to unfiltered version
// - ibuf[] is restored to the original unfiltered version
// - obuf[] contains the best compressed version
//
// strategy:
// 0: try all filters, use best one
// n: try the first N filters in parm_filters[], use best one
// n: try the first N filters, use best one
// -1: try all filters, use first working one
// -2: try only the opt->filter filter
// -3: use no filter at all
//
// This has been prepared for generalization into class Packer so that
// opt->all_filters is available for all executable formats.
// opt->all_methods and/or opt->all_filters are available for all
// executable formats.
//
// It will replace the tryFilters() / compress() call sequence.
**************************************************************************/
@@ -1114,23 +1124,39 @@ void Packer::compressWithFilters(Filter *parm_ft,
assert(orig_ft.id == 0);
assert(filter_off + filter_len <= compress_buf_off + compress_buf_len);
// setup raw_filters
static const int no_filters[] = { 0, -1 };
int strategy_filters[] = { 0, -1 };
const int *raw_filters = parm_filters;
if (raw_filters == NULL)
raw_filters = getFilters();
if (raw_filters == NULL)
raw_filters = no_filters;
if (strategy == -2)
// setup filter strategy
if (strategy == 0)
{
assert(opt->filter >= 0);
strategy_filters[0] = opt->filter;
raw_filters = strategy_filters;
if (opt->all_filters)
// choose best from all available filters
strategy = INT_MAX;
else if (opt->filter >= 0 && isValidFilter(opt->filter))
// try opt->filter
strategy = -2;
else
// try the first working filter
strategy = -1;
}
assert(strategy != 0);
// setup raw_filters
int tmp_filters[] = { 0, -1 };
const int *raw_filters = NULL;
if (strategy == -3)
raw_filters = tmp_filters;
else if (strategy == -2 && opt->filter >= 0)
{
tmp_filters[0] = opt->filter;
raw_filters = tmp_filters;
}
else
{
raw_filters = parm_filters;
if (raw_filters == NULL)
raw_filters = getFilters();
if (raw_filters == NULL)
raw_filters = tmp_filters;
}
else if (strategy == -3)
raw_filters = no_filters;
// first pass - count number of filters
int raw_nfilters = 0;
@@ -1140,7 +1166,7 @@ void Packer::compressWithFilters(Filter *parm_ft,
raw_nfilters++;
}
// copy filters, eliminate duplicates, add a 0
// copy filters, add a 0
int nfilters = 0;
bool zero_seen = false;
autoheap_array(int, filters, raw_nfilters + 2);
@@ -1148,111 +1174,129 @@ void Packer::compressWithFilters(Filter *parm_ft,
{
if (*f == 0)
zero_seen = true;
bool duplicate = false;
for (int i = 0; i < nfilters; i++)
if (filters[i] == *f)
duplicate = true;
if (!duplicate)
filters[nfilters++] = *f;
filters[nfilters++] = *f;
if (nfilters == strategy)
break;
}
if (!zero_seen)
filters[nfilters++] = 0;
filters[nfilters] = -1;
// methods
int tmp_methods[] = { ph.method, -1 };
const int *methods = NULL;
if (opt->all_methods)
methods = getCompressionMethods(-1, ph.level);
if (methods == NULL)
methods = tmp_methods;
int nmethods = 0;
while (methods[nmethods] >= 0)
{
assert(isValidCompressionMethod(methods[nmethods]));
nmethods++;
}
assert(nmethods > 0);
// update total_passes
if (strategy < 0)
ui_total_passes += 1;
ui_total_passes += 1 * nmethods;
else
{
if (strategy > nfilters)
nfilters = strategy;
ui_total_passes += nfilters;
}
ui_total_passes += nfilters * nmethods;
// Working buffer for compressed data. Don't waste memory.
upx_byte *otemp = obuf;
MemBuffer otemp_buf;
if (nfilters > 1 && strategy >= 0)
{
otemp_buf.allocForCompression(compress_buf_len);
otemp = otemp_buf;
}
// compress
int nfilters_success = 0;
for (int i = 0; i < nfilters; i++)
for (int m = 0; m < nmethods; m++) // for all methods
{
// get fresh packheader
ph = orig_ph;
ph.filter = filters[i];
// get fresh filter
Filter ft = orig_ft;
ft.init(filters[i], orig_ft.addvalue);
// filter
optimizeFilter(&ft, ibuf + filter_off, filter_len);
bool success = ft.filter(ibuf + filter_off, filter_len);
if (ft.id != 0 && ft.calls == 0)
for (int i = 0; i < nfilters; i++) // for all filters
{
// filter did not do anything - no need to call ft.unfilter()
success = false;
}
if (!success)
{
// filter failed or was usesless
if (strategy >= 0)
ui_total_passes -= 1;
continue;
}
// filter success
nfilters_success++;
ph.filter_cto = ft.cto;
// compress
if (compress(ibuf + compress_buf_off, otemp, max_offset, max_match))
{
unsigned lsize = 0;
if (ph.c_len + lsize < best_ph.c_len + best_ph_lsize)
// get fresh packheader
ph = orig_ph;
ph.method = methods[m];
ph.filter = filters[i];
// get fresh filter
Filter ft = orig_ft;
ft.init(ph.filter, orig_ft.addvalue);
// filter
optimizeFilter(&ft, ibuf + filter_off, filter_len);
bool success = ft.filter(ibuf + filter_off, filter_len);
if (ft.id != 0 && ft.calls == 0)
{
// get results
ph.overlap_overhead = findOverlapOverhead(otemp, overlap_range);
lsize = buildLoader(&ft);
// filter did not do anything - no need to call ft.unfilter()
success = false;
}
if (!success)
{
// filter failed or was usesless
if (strategy > 0)
ui_total_passes -= 1;
continue;
}
// filter success
if (nfilters_success > 0 && otemp == obuf)
{
otemp_buf.allocForCompression(compress_buf_len);
otemp = otemp_buf;
}
nfilters_success++;
ph.filter_cto = ft.cto;
// compress
if (compress(ibuf + compress_buf_off, otemp, max_offset, max_match))
{
unsigned lsize = 0;
if (ph.c_len + lsize < best_ph.c_len + best_ph_lsize)
{
// get results
ph.overlap_overhead = findOverlapOverhead(otemp, overlap_range);
lsize = buildLoader(&ft);
}
#if 0
printf("\n%02x: %d + %d = %d (best: %d + %d = %d)\n", ft.id,
printf("\n%2d %02x: %d + %d = %d (best: %d + %d = %d)\n", ph.method, ph.filter,
ph.c_len, getLoaderSize(), ph.c_len + getLoaderSize(),
best_ph.c_len, best_ph_lsize, best_ph.c_len + best_ph_lsize);
#endif
bool update = false;
if (ph.c_len + lsize < best_ph.c_len + best_ph_lsize)
update = true;
else if (ph.c_len + lsize == best_ph.c_len + best_ph_lsize)
{
if (ph.overlap_overhead < best_ph.overlap_overhead)
bool update = false;
if (ph.c_len + lsize < best_ph.c_len + best_ph_lsize)
update = true;
else if (ph.c_len + lsize == best_ph.c_len + best_ph_lsize)
{
// prefer less overlap_overhead
if (ph.overlap_overhead < best_ph.overlap_overhead)
update = true;
else if (ph.overlap_overhead == best_ph.overlap_overhead)
{
// prefer bigger loaders
if (lsize > best_ph_lsize)
update = true;
}
}
if (update)
{
// update obuf[] with best version
if (otemp != obuf)
memcpy(obuf, otemp, ph.c_len);
// save compression results
best_ph = ph;
best_ph_lsize = lsize;
best_ft = ft;
}
}
if (update)
{
// update obuf[] with best version
if (otemp != obuf)
memcpy(obuf, otemp, ph.c_len);
// save compression results
best_ph = ph;
best_ph_lsize = lsize;
best_ft = ft;
}
// restore ibuf[] - unfilter with verify
ft.unfilter(ibuf + filter_off, filter_len, true);
//
if (strategy < 0)
break;
}
// restore ibuf[] - unfilter with verify
ft.unfilter(ibuf + filter_off, filter_len, true);
//
if (strategy < 0)
break;
}
// postconditions
// postconditions 1)
assert(nfilters_success > 0);
assert(best_ph.u_len == orig_ph.u_len);
assert(best_ph.filter == best_ft.id);
assert(best_ph.filter_cto == best_ft.cto);
assert(best_ph.overlap_overhead > 0);
// copy back results
this->ph = best_ph;
@@ -1264,6 +1308,9 @@ void Packer::compressWithFilters(Filter *parm_ft,
if (!checkCompressionRatio(best_ph.u_len, best_ph.c_len))
throwNotCompressible();
// postconditions 2)
assert(best_ph.overlap_overhead > 0);
// convenience
buildLoader(&best_ft);
}