mirror of
https://github.com/schnaader/precomp-cpp
synced 2026-08-23 00:23:04 -04:00
- update to preflate v0.3.2 (bug fix)
- add switch -pfverify to force preflate to verify its result and store mishandled deflate streams in files
This commit is contained in:
parent
c48a0b5c4c
commit
78b918dc18
8 changed files with 307 additions and 68 deletions
|
|
@ -9,14 +9,6 @@ Fork note
|
|||
---------
|
||||
This is an experimental fork of precomp, that uses the preflate library for
|
||||
deflate stream recompression.
|
||||
The bitstream format output by the preflate library is not stable yet,
|
||||
so do not use this experimental tool for archiving.
|
||||
|
||||
Also, the build system isn't up to date yet. I'll provide a CMake script
|
||||
in the near future. Also, importing the preflate sources in a GUI, e.g. MSVC,
|
||||
is pretty straight forward.
|
||||
|
||||
For the time being, there are executables for testing.
|
||||
|
||||
|
||||
What is Precomp?
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -125,7 +125,10 @@ int combine(const char* const * const fns, const unsigned fncnt, const std::stri
|
|||
return ok ? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
#include "preflate_seq_chain.h"
|
||||
int main(int argc, const char * const * const argv) {
|
||||
puts("preflate v0.3.2");
|
||||
if (!support_self_tests()) {
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
179
contrib/preflate/main2.cpp
Normal file
179
contrib/preflate/main2.cpp
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
/* Copyright 2018 Dirk Steinke
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. */
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
||||
#include "preflate_checker.h"
|
||||
#include "preflate_decoder.h"
|
||||
#include "preflate_info.h"
|
||||
#include "preflate_reencoder.h"
|
||||
#include "support/support_tests.h"
|
||||
|
||||
bool loadfile(
|
||||
std::vector<unsigned char>& content,
|
||||
const std::string& fn) {
|
||||
FILE* f = fopen(fn.c_str(), "rb");
|
||||
if (!f) {
|
||||
return false;
|
||||
}
|
||||
fseek(f, 0, SEEK_END);
|
||||
long length = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
content.resize(length);
|
||||
long read = fread(content.data(), 1, content.size(), f);
|
||||
fclose(f);
|
||||
return read == length;
|
||||
}
|
||||
bool savefile(
|
||||
const std::vector<unsigned char>& content,
|
||||
const std::string& fn) {
|
||||
FILE* f = fopen(fn.c_str(), "wb");
|
||||
if (!f) {
|
||||
return false;
|
||||
}
|
||||
size_t written = fwrite(content.data(), 1, content.size(), f);
|
||||
fclose(f);
|
||||
return written == content.size();
|
||||
}
|
||||
|
||||
int test(const char* const * const fns, const unsigned fncnt) {
|
||||
bool ok = true;
|
||||
for (unsigned i = 0; i < fncnt; ++i) {
|
||||
std::vector<unsigned char> content;
|
||||
if (!loadfile(content, fns[i])) {
|
||||
printf("loading of %s failed\n", fns[i]);
|
||||
ok = false;
|
||||
} else {
|
||||
std::vector<unsigned char> unpacked;
|
||||
std::vector<unsigned char> recon;
|
||||
bool check_ok = preflate_decode(unpacked, recon, content, 1 << 18);
|
||||
if (check_ok) {
|
||||
std::vector<unsigned char> rebuilt_content;
|
||||
check_ok = preflate_reencode(rebuilt_content, recon, unpacked);
|
||||
if (check_ok) {
|
||||
check_ok = content == rebuilt_content;
|
||||
if (check_ok) {
|
||||
printf("splitting & recombining %s successful (%d -> %d + %d)\n",
|
||||
fns[i], (int)content.size(), (int)unpacked.size(), (int)recon.size());
|
||||
} else {
|
||||
printf("splitting & recombining %s failed: output not bitexact (%d -> %d + %d)\n",
|
||||
fns[i], (int)content.size(), (int)unpacked.size(), (int)recon.size());
|
||||
}
|
||||
} else {
|
||||
printf("recombining %s failed (%d -> %d + %d)\n",
|
||||
fns[i], (int)content.size(), (int)unpacked.size(), (int)recon.size());
|
||||
}
|
||||
} else {
|
||||
printf("splitting %s failed\n", fns[i]);
|
||||
}
|
||||
ok = ok && check_ok;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
printf("All checks ok\n");
|
||||
}
|
||||
return ok ? 0 : -1;
|
||||
}
|
||||
int split(const char* const * const fns, const unsigned fncnt) {
|
||||
bool ok = true;
|
||||
for (unsigned i = 0; i < fncnt; ++i) {
|
||||
std::vector<unsigned char> content;
|
||||
if (!loadfile(content, fns[i])) {
|
||||
printf("loading of %s failed\n", fns[i]);
|
||||
ok = false;
|
||||
} else {
|
||||
std::vector<unsigned char> unpacked;
|
||||
std::vector<unsigned char> recon;
|
||||
bool check_ok = preflate_decode(unpacked, recon, content);
|
||||
if (check_ok) {
|
||||
savefile(unpacked, std::string(fns[i]) + ".u");
|
||||
savefile(recon, std::string(fns[i]) + ".r");
|
||||
printf("splitting %s successful (%d -> %d + %d)\n",
|
||||
fns[i], (int)content.size(), (int)unpacked.size(), (int)recon.size());
|
||||
} else {
|
||||
printf("splitting %s failed\n", fns[i]);
|
||||
}
|
||||
ok = ok && check_ok;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
printf("All ok\n");
|
||||
}
|
||||
return ok ? 0 : -1;
|
||||
}
|
||||
int combine(const char* const * const fns, const unsigned fncnt, const std::string& ext) {
|
||||
bool ok = true;
|
||||
for (unsigned i = 0; i < fncnt; ++i) {
|
||||
std::vector<unsigned char> unpacked;
|
||||
std::vector<unsigned char> recon;
|
||||
if (!loadfile(unpacked, std::string(fns[i]) + ".u")
|
||||
|| !loadfile(recon, std::string(fns[i]) + ".r")) {
|
||||
printf("loading of %s.u/.r failed\n", fns[i]);
|
||||
ok = false;
|
||||
} else {
|
||||
std::vector<unsigned char> content;
|
||||
bool check_ok = preflate_reencode(content, recon, unpacked);
|
||||
if (check_ok) {
|
||||
savefile(content, std::string(fns[i]) + ext);
|
||||
printf("recombining %s%s successful (%d + %d -> %d)\n",
|
||||
fns[i], ext.c_str(), (int)unpacked.size(), (int)recon.size(), (int)content.size());
|
||||
} else {
|
||||
printf("recombining %s%s failed\n", fns[i], ext.c_str());
|
||||
}
|
||||
ok = ok && check_ok;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
printf("All ok\n");
|
||||
}
|
||||
return ok ? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
#include "preflate_seq_chain.h"
|
||||
int main(int argc, const char * const * const argv) {
|
||||
puts("preflate v0.3.2");
|
||||
if (argc >= 3) {
|
||||
if (!strcmp(argv[1], "-t")) {
|
||||
const char* const * fns = argv + 2;
|
||||
size_t fncnt = argc - 2;
|
||||
return test(fns, fncnt);
|
||||
}
|
||||
if (!strcmp(argv[1], "-s")) {
|
||||
return split(argv + 2, argc - 2);
|
||||
}
|
||||
if (!strcmp(argv[1], "-r")) {
|
||||
return combine(argv + 2, argc - 2, "");
|
||||
}
|
||||
if (!strcmp(argv[1], "-x")) {
|
||||
return combine(argv + 2, argc - 2, ".x");
|
||||
}
|
||||
}
|
||||
printf("usage: %s -t FILE [FILE ... FILE]\n", argv[0]);
|
||||
printf(" test uncompression and recompression\n");
|
||||
printf(" %s -s FILE [FILE ... FILE]\n", argv[0]);
|
||||
printf(" split deflate stream (FILE) into uncompressed part\n");
|
||||
printf(" (FILE.u) and reconstruction info (FILE.r)\n");
|
||||
printf(" %s -r FILE [FILE ... FILE]\n", argv[0]);
|
||||
printf(" recombine uncompressed part (FILE.u) and reconstruction\n");
|
||||
printf(" info (FILE.r) into deflate stream (FILE)\n");
|
||||
printf(" %s -x FILE [FILE ... FILE]\n", argv[0]);
|
||||
printf(" recombines into FILE.x instead of FILE\n");
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@
|
|||
#include "support/outputcachestream.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
|
||||
bool preflate_checker(const std::vector<unsigned char>& deflate_raw) {
|
||||
printf("Checking raw deflate file of size %d\n", (int)deflate_raw.size());
|
||||
|
|
@ -35,6 +36,8 @@ bool preflate_checker(const std::vector<unsigned char>& deflate_raw) {
|
|||
BitInputStream decInBits(decIn);
|
||||
OutputCacheStream decOutCache(decUnc);
|
||||
std::vector<PreflateTokenBlock> blocks;
|
||||
|
||||
auto ts_start = std::chrono::steady_clock::now();
|
||||
PreflateBlockDecoder bdec(decInBits, decOutCache);
|
||||
if (bdec.status() != PreflateBlockDecoder::OK) {
|
||||
return false;
|
||||
|
|
@ -55,7 +58,9 @@ bool preflate_checker(const std::vector<unsigned char>& deflate_raw) {
|
|||
uint8_t remaining_bits = decInBits.get(remaining_bit_count);
|
||||
decOutCache.flush();
|
||||
std::vector<unsigned char> unpacked_output = decUnc.extractData();
|
||||
auto ts_end = std::chrono::steady_clock::now();
|
||||
printf("Unpacked data has size %d\n", (int)unpacked_output.size());
|
||||
printf("Unpacking took %g seconds\n", std::chrono::duration<double>(ts_end - ts_start).count());
|
||||
|
||||
// Encode
|
||||
PreflateParameters paramsE = estimatePreflateParameters(unpacked_output, 0, blocks);
|
||||
|
|
@ -65,6 +70,8 @@ bool preflate_checker(const std::vector<unsigned char>& deflate_raw) {
|
|||
paramsE.veryFarMatchesDetected, paramsE.matchesToStartDetected,
|
||||
paramsE.log2OfMaxChainDepthM1);
|
||||
|
||||
|
||||
ts_start = std::chrono::steady_clock::now();
|
||||
PreflateStatisticsCounter counterE;
|
||||
memset(&counterE, 0, sizeof(counterE));
|
||||
PreflateTokenPredictor tokenPredictorE(paramsE, unpacked_output, 0);
|
||||
|
|
@ -84,9 +91,12 @@ bool preflate_checker(const std::vector<unsigned char>& deflate_raw) {
|
|||
treePredictorE.updateCounters(&counterE, i);
|
||||
}
|
||||
counterE.block.incNonZeroPadding(remaining_bits != 0);
|
||||
ts_end = std::chrono::steady_clock::now();
|
||||
printf("Prediction took %g seconds\n", std::chrono::duration<double>(ts_end - ts_start).count());
|
||||
|
||||
counterE.print();
|
||||
|
||||
ts_start = std::chrono::steady_clock::now();
|
||||
PreflateMetaEncoder codecE;
|
||||
if (codecE.error()) {
|
||||
return false;
|
||||
|
|
@ -121,18 +131,53 @@ bool preflate_checker(const std::vector<unsigned char>& deflate_raw) {
|
|||
return false;
|
||||
}
|
||||
std::vector<unsigned char> preflate_diff = codecE.finish();
|
||||
ts_end = std::chrono::steady_clock::now();
|
||||
printf("Prediction diff has size %d\n", (int)preflate_diff.size());
|
||||
printf("Encoding diff took %g seconds\n", std::chrono::duration<double>(ts_end - ts_start).count());
|
||||
|
||||
// Decode
|
||||
ts_start = std::chrono::steady_clock::now();
|
||||
PreflateMetaDecoder codecD(preflate_diff, unpacked_output.size());
|
||||
PreflatePredictionDecoder pcodecD;
|
||||
PreflateParameters paramsD;
|
||||
|
||||
if (codecD.error() || codecD.metaBlockCount() != 1) {
|
||||
return false;
|
||||
}
|
||||
if (!codecD.beginMetaBlock(pcodecD, paramsD, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PreflateTokenPredictor tokenPredictorD(paramsD, unpacked_output, 0);
|
||||
PreflateTreePredictor treePredictorD(unpacked_output, 0);
|
||||
|
||||
MemStream mem;
|
||||
BitOutputStream bos(mem);
|
||||
|
||||
std::vector<PreflateTokenBlock> dblocks;
|
||||
unsigned blockno = 0;
|
||||
bool eof = true;
|
||||
do {
|
||||
PreflateTokenBlock block = tokenPredictorD.decodeBlock(&pcodecD);
|
||||
if (tokenPredictorD.predictionFailure) {
|
||||
printf("block %d: token uncompress failed\n", blockno);
|
||||
return false;
|
||||
}
|
||||
if (!treePredictorD.decodeBlock(block, &pcodecD)) {
|
||||
printf("block %d: tree uncompress failed\n", blockno);
|
||||
return false;
|
||||
}
|
||||
if (treePredictorD.predictionFailure) {
|
||||
printf("block %d: tree uncompress failed\n", blockno);
|
||||
return false;
|
||||
}
|
||||
eof = tokenPredictorD.decodeEOF(&pcodecD);
|
||||
dblocks.push_back(block);
|
||||
++blockno;
|
||||
} while (!eof);
|
||||
ts_end = std::chrono::steady_clock::now();
|
||||
printf("Decoding diff and reprediction took %g seconds\n", std::chrono::duration<double>(ts_end - ts_start).count());
|
||||
|
||||
if (paramsD.windowBits != paramsE.windowBits) {
|
||||
printf("parameter decoding failed: windowBits mismatch\n");
|
||||
return false;
|
||||
|
|
@ -150,10 +195,10 @@ bool preflate_checker(const std::vector<unsigned char>& deflate_raw) {
|
|||
return false;
|
||||
}
|
||||
if (!paramsD.zlibCompatible && (0
|
||||
// || paramsD.farLen3MatchesDetected != paramsE.farLen3MatchesDetected
|
||||
|| paramsD.veryFarMatchesDetected != paramsE.veryFarMatchesDetected
|
||||
|| paramsD.matchesToStartDetected != paramsE.matchesToStartDetected
|
||||
|| paramsD.log2OfMaxChainDepthM1 != paramsE.log2OfMaxChainDepthM1)) {
|
||||
// || paramsD.farLen3MatchesDetected != paramsE.farLen3MatchesDetected
|
||||
|| paramsD.veryFarMatchesDetected != paramsE.veryFarMatchesDetected
|
||||
|| paramsD.matchesToStartDetected != paramsE.matchesToStartDetected
|
||||
|| paramsD.log2OfMaxChainDepthM1 != paramsE.log2OfMaxChainDepthM1)) {
|
||||
printf("parameter decoding failed: non-zlib flag mismatch\n");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -163,77 +208,53 @@ bool preflate_checker(const std::vector<unsigned char>& deflate_raw) {
|
|||
return false;
|
||||
}
|
||||
|
||||
PreflateTokenPredictor tokenPredictorD(paramsD, unpacked_output, 0);
|
||||
PreflateTreePredictor treePredictorD(unpacked_output, 0);
|
||||
|
||||
MemStream mem;
|
||||
BitOutputStream bos(mem);
|
||||
|
||||
PreflateBlockReencoder deflater(bos, unpacked_output, 0);
|
||||
unsigned blockno = 0;
|
||||
bool eof = true;
|
||||
do {
|
||||
if (blockno >= blocks.size()) {
|
||||
printf("block number too big: org %d, new %d\n", (int)blocks.size(), blockno);
|
||||
for (size_t blockno = 0, n = std::min(blocks.size(), dblocks.size()); blockno < n; ++blockno) {
|
||||
if (dblocks[blockno].type != blocks[blockno].type) {
|
||||
printf("block %d: type differs: org %d, new %d\n", blockno, blocks[blockno].type, dblocks[blockno].type);
|
||||
return false;
|
||||
}
|
||||
PreflateTokenBlock block = tokenPredictorD.decodeBlock(&pcodecD);
|
||||
if (tokenPredictorD.predictionFailure) {
|
||||
printf("block %d: token uncompress failed\n", blockno);
|
||||
return false;
|
||||
}
|
||||
if (block.type != blocks[blockno].type) {
|
||||
printf("block %d: type differs: org %d, new %d\n", blockno, blocks[blockno].type, block.type);
|
||||
return false;
|
||||
}
|
||||
for (unsigned i = 0, n = std::min(block.tokens.size(), blocks[blockno].tokens.size()); i < n; ++i) {
|
||||
for (unsigned i = 0, n = std::min(dblocks[blockno].tokens.size(), blocks[blockno].tokens.size()); i < n; ++i) {
|
||||
PreflateToken orgToken = blocks[blockno].tokens[i];
|
||||
PreflateToken newToken = block.tokens[i];
|
||||
PreflateToken newToken = dblocks[blockno].tokens[i];
|
||||
if (newToken.len != orgToken.len || newToken.dist != orgToken.dist) {
|
||||
printf("block %d: generated token %d differs: org(%d,%d), new(%d,%d)\n",
|
||||
blockno, i, orgToken.len, orgToken.dist, newToken.len, newToken.dist);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (block.tokens.size() != blocks[blockno].tokens.size()) {
|
||||
if (dblocks[blockno].tokens.size() != blocks[blockno].tokens.size()) {
|
||||
printf("block %d: differing token count: org %d, new %d\n",
|
||||
blockno, (int)blocks[blockno].tokens.size(), (int)block.tokens.size());
|
||||
blockno, (int)blocks[blockno].tokens.size(), (int)dblocks[blockno].tokens.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!treePredictorD.decodeBlock(block, &pcodecD)) {
|
||||
printf("block %d: tree uncompress failed\n", blockno);
|
||||
return false;
|
||||
}
|
||||
if (treePredictorD.predictionFailure) {
|
||||
printf("block %d: tree uncompress failed\n", blockno);
|
||||
return false;
|
||||
}
|
||||
if (block.type == PreflateTokenBlock::DYNAMIC_HUFF) {
|
||||
if (block.nlen != blocks[blockno].nlen) {
|
||||
if (dblocks[blockno].type == PreflateTokenBlock::DYNAMIC_HUFF) {
|
||||
if (dblocks[blockno].nlen != blocks[blockno].nlen) {
|
||||
printf("block %d: literal/len count differs: org %d, new %d\n",
|
||||
blockno, blocks[blockno].nlen, block.nlen);
|
||||
blockno, blocks[blockno].nlen, dblocks[blockno].nlen);
|
||||
return false;
|
||||
}
|
||||
if (block.ndist != blocks[blockno].ndist) {
|
||||
if (dblocks[blockno].ndist != blocks[blockno].ndist) {
|
||||
printf("block %d: dist count differs: org %d, new %d\n",
|
||||
blockno, blocks[blockno].ndist, block.ndist);
|
||||
blockno, blocks[blockno].ndist, dblocks[blockno].ndist);
|
||||
return false;
|
||||
}
|
||||
if (block.ncode != blocks[blockno].ncode) {
|
||||
if (dblocks[blockno].ncode != blocks[blockno].ncode) {
|
||||
printf("block %d: tree code count differs: org %d, new %d\n",
|
||||
blockno, blocks[blockno].ncode, block.ncode);
|
||||
blockno, blocks[blockno].ncode, dblocks[blockno].ncode);
|
||||
return false;
|
||||
}
|
||||
if (block.treecodes != blocks[blockno].treecodes) {
|
||||
if (dblocks[blockno].treecodes != blocks[blockno].treecodes) {
|
||||
printf("block %d: generated tree codes differs\n", blockno);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
eof = tokenPredictorD.decodeEOF(&pcodecD);
|
||||
deflater.writeBlock(block, eof);
|
||||
++blockno;
|
||||
} while (!eof);
|
||||
}
|
||||
|
||||
ts_start = std::chrono::steady_clock::now();
|
||||
PreflateBlockReencoder deflater(bos, unpacked_output, 0);
|
||||
for (size_t i = 0; i < dblocks.size(); ++i) {
|
||||
deflater.writeBlock(dblocks[i], i + 1 == dblocks.size());
|
||||
}
|
||||
bool non_zero_bits = pcodecD.decodeNonZeroPadding();
|
||||
if (non_zero_bits) {
|
||||
unsigned bitsToLoad = pcodecD.decodeValue(3);
|
||||
|
|
@ -247,8 +268,10 @@ bool preflate_checker(const std::vector<unsigned char>& deflate_raw) {
|
|||
return false;
|
||||
}
|
||||
deflater.flush();
|
||||
|
||||
std::vector<unsigned char> deflate_raw_out = mem.extractData();
|
||||
ts_end = std::chrono::steady_clock::now();
|
||||
printf("Reencoding deflate stream took %g seconds\n", std::chrono::duration<double>(ts_end - ts_start).count());
|
||||
|
||||
for (unsigned i = 0, n = std::min(deflate_raw.size(), deflate_raw_out.size()); i < n; ++i) {
|
||||
if (deflate_raw[i] != deflate_raw_out[i]) {
|
||||
printf("created deflate stream differs at offset %d\n", i);
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ PreflateToken PreflateTokenPredictor::predictToken() {
|
|||
|
||||
if (((hashNext ^ hash) & this->hash.hashMask) == 0) {
|
||||
unsigned maxSize = std::min(state.availableInputSize() - 1, (unsigned)PreflateConstants::MAX_MATCH);
|
||||
unsigned rle = 1;
|
||||
unsigned rle = 0;
|
||||
const unsigned char *c = state.inputCursor();
|
||||
unsigned char b = c[0];
|
||||
while (rle < maxSize && c[1 + rle] == b) {
|
||||
|
|
@ -189,11 +189,14 @@ void PreflateTokenPredictor::analyzeBlock(
|
|||
|
||||
for (unsigned i = 0, n = block.tokens.size(); i < n; ++i) {
|
||||
PreflateToken targetToken = block.tokens[i];
|
||||
|
||||
if (predictEOB()) {
|
||||
analysis.blockSizePredicted = false;
|
||||
}
|
||||
PreflateToken predictedToken = predictToken();
|
||||
// printf("T(%d,%d) -> P(%d,%d)\n", targetToken.len, targetToken.dist, predictedToken.len, predictedToken.dist);
|
||||
#ifdef _DEBUG
|
||||
printf("B%dT%d: TGT(%d,%d) -> PRD(%d,%d)\n", blockno, i, targetToken.len, targetToken.dist, predictedToken.len, predictedToken.dist);
|
||||
#endif
|
||||
|
||||
if (targetToken.len == 1) {
|
||||
if (predictedToken.len > 1) {
|
||||
|
|
|
|||
53
precomp.cpp
53
precomp.cpp
|
|
@ -19,7 +19,7 @@
|
|||
// version information
|
||||
#define V_MAJOR 0
|
||||
#define V_MINOR 4
|
||||
#define V_MINOR2 132
|
||||
#define V_MINOR2 133
|
||||
//#define V_STATE "ALPHA"
|
||||
#define V_STATE "EXPERIMENTAL (w/ preflate support)"
|
||||
#define V_MSG "USE FOR TESTING ONLY"
|
||||
|
|
@ -209,7 +209,8 @@ bool level_switch_used = false;
|
|||
bool non_zlib_was_used;
|
||||
|
||||
// preflate config
|
||||
size_t meta_block_size = 1 << 21; // 2 MB blocks by default
|
||||
size_t preflate_meta_block_size = 1 << 21; // 2 MB blocks by default
|
||||
bool preflate_verify = false;
|
||||
|
||||
// statistics
|
||||
unsigned int recompressed_streams_count = 0;
|
||||
|
|
@ -543,7 +544,7 @@ bool parseSwitch(bool& val, const char* c, const char* ref) {
|
|||
val = true;
|
||||
return true;
|
||||
} else if (c[l] == '-' && !c[l + 1]) {
|
||||
val = true;
|
||||
val = false;
|
||||
return true;
|
||||
}
|
||||
printf("ERROR: Only + or - for this switch (%s) allowed\n", c);
|
||||
|
|
@ -622,7 +623,7 @@ int init(int argc, char* argv[]) {
|
|||
}
|
||||
printf(" - %s\n",V_MSG);
|
||||
printf("Free for non-commercial use - Copyright 2006-2018 by Christian Schneider\n");
|
||||
printf("- experimental preflate v0.3.1 support - Copyright 2018 by Dirk Steinke\n\n");
|
||||
printf("- experimental preflate v0.3.2 support - Copyright 2018 by Dirk Steinke\n\n");
|
||||
|
||||
// init compression and memory level count
|
||||
bool use_zlib_level[81];
|
||||
|
|
@ -857,14 +858,15 @@ int init(int argc, char* argv[]) {
|
|||
case 'P':
|
||||
{
|
||||
if (!parseSwitch(pdf_bmp_mode, argv[i] + 1, "pdfbmp")
|
||||
&& !parseSwitch(prog_only, argv[i] + 1, "progonly")) {
|
||||
&& !parseSwitch(prog_only, argv[i] + 1, "progonly")
|
||||
&& !parseSwitch(preflate_verify, argv[i] + 1, "pfverify")) {
|
||||
if (parsePrefixText(argv[i] + 1, "pfmeta")) {
|
||||
int mbsize = parseIntUntilEnd(argv[i] + 7, "preflate meta block size");
|
||||
if (mbsize >= INT_MAX / 1024) {
|
||||
printf("preflate meta block size set too big\n");
|
||||
exit(1);
|
||||
}
|
||||
meta_block_size = mbsize * 1024;
|
||||
preflate_meta_block_size = mbsize * 1024;
|
||||
} else {
|
||||
printf("ERROR: Unknown switch \"%s\"\n", argv[i]);
|
||||
exit(1);
|
||||
|
|
@ -1192,6 +1194,7 @@ int init(int argc, char* argv[]) {
|
|||
//printf(" zl[1..9][1..9] zLib levels to try for compression (comma separated) <all>\n");
|
||||
if (long_help) {
|
||||
printf(" pfmeta[amount] Split deflate streams into meta blocks of this size in KiB <2048>\n");
|
||||
printf(" pfverify Force preflate to verify its generated reconstruction data\n");
|
||||
}
|
||||
printf(" intense Detect raw zLib headers, too. Slower and more sensitive <off>\n");
|
||||
if (long_help) {
|
||||
|
|
@ -3112,9 +3115,45 @@ recompress_deflate_result try_recompression_deflate(FILE* file) {
|
|||
result.accepted = preflate_decode(uos, result.recon_data,
|
||||
compressed_stream_size, is, []() { print_work_sign(true); },
|
||||
0,
|
||||
meta_block_size); // you can set a minimum deflate stream size here
|
||||
preflate_meta_block_size); // you can set a minimum deflate stream size here
|
||||
result.compressed_stream_size = compressed_stream_size;
|
||||
result.uncompressed_stream_size = uos.written();
|
||||
|
||||
if (preflate_verify && result.accepted) {
|
||||
if (file == fin) {
|
||||
seek_64(file, input_file_pos);
|
||||
} else {
|
||||
seek_64(file, 0);
|
||||
}
|
||||
OwnFileInputStream is2(file);
|
||||
std::vector<uint8_t> orgdata(result.compressed_stream_size);
|
||||
is2.read(orgdata.data(), orgdata.size());
|
||||
|
||||
MemStream reencoded_deflate;
|
||||
MemStream uncompressed_mem(result.uncompressed_in_memory ? std::vector<uint8_t>(decomp_io_buf, decomp_io_buf + result.uncompressed_stream_size) : std::vector<uint8_t>());
|
||||
OwnFileInputStream uncompressed_file(result.uncompressed_in_memory ? NULL : ftempout);
|
||||
if (!preflate_reencode(reencoded_deflate, result.recon_data,
|
||||
result.uncompressed_in_memory ? (InputStream&)uncompressed_mem : (InputStream&)uncompressed_file,
|
||||
result.uncompressed_stream_size,
|
||||
[] {})
|
||||
|| orgdata != reencoded_deflate.data()) {
|
||||
result.accepted = false;
|
||||
static size_t counter = 0;
|
||||
char namebuf[50];
|
||||
while (true) {
|
||||
snprintf(namebuf, 49, "preflate_error_%04d.raw", counter++);
|
||||
FILE* f = fopen(namebuf, "rb");
|
||||
if (f) {
|
||||
fclose(f);
|
||||
continue;
|
||||
}
|
||||
f = fopen(namebuf, "wb");
|
||||
fwrite(orgdata.data(), 1, orgdata.size(), f);
|
||||
fclose(f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::move(result);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue