mirror of
https://github.com/schnaader/precomp-cpp
synced 2026-08-23 00:23:04 -04:00
- They can be useful in slow mode, but in brute mode, there are short false positive that can cause massive slowdown
9773 lines
309 KiB
C++
9773 lines
309 KiB
C++
/* Copyright 2006-2017 Christian Schneider
|
|
|
|
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. */
|
|
|
|
#ifdef PRECOMPDLL
|
|
#define DLL __declspec(dllexport)
|
|
#endif
|
|
|
|
// version information
|
|
#define V_MAJOR 0
|
|
#define V_MINOR 4
|
|
#define V_MINOR2 6
|
|
//#define V_STATE "ALPHA"
|
|
#define V_STATE "DEVELOPMENT"
|
|
//#define V_MSG "USE FOR TESTING ONLY"
|
|
#define V_MSG "USE AT YOUR OWN RISK!"
|
|
#ifdef UNIX
|
|
#define V_OS "Unix"
|
|
#else
|
|
#define V_OS "Windows"
|
|
#endif
|
|
#ifdef BIT64
|
|
#define V_BIT "64-bit"
|
|
#else
|
|
#define V_BIT "32-bit"
|
|
#endif
|
|
|
|
// batch error levels
|
|
#define RETURN_NOTHING_DECOMPRESSED 2
|
|
#define ERR_DISK_FULL 3
|
|
#define ERR_TEMP_FILE_DISAPPEARED 4
|
|
#define ERR_IGNORE_POS_TOO_BIG 5
|
|
#define ERR_IDENTICAL_BYTE_SIZE_TOO_BIG 6
|
|
#define ERR_RECURSION_DEPTH_TOO_BIG 7
|
|
#define ERR_ONLY_SET_RECURSION_DEPTH_ONCE 8
|
|
#define ERR_ONLY_SET_MIN_SIZE_ONCE 9
|
|
#define ERR_DONT_USE_SPACE 10
|
|
#define ERR_MORE_THAN_ONE_OUTPUT_FILE 11
|
|
#define ERR_MORE_THAN_ONE_INPUT_FILE 12
|
|
#define ERR_CTRL_C 13
|
|
#define ERR_INTENSE_MODE_LIMIT_TOO_BIG 14
|
|
#define ERR_BRUTE_MODE_LIMIT_TOO_BIG 15
|
|
#define ERR_ONLY_SET_LZMA_MEMORY_ONCE 16
|
|
#define ERR_ONLY_SET_LZMA_THREAD_ONCE 17
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <signal.h>
|
|
#include <thread>
|
|
#include <set>
|
|
#ifdef MINGW
|
|
#include "contrib\mingw_std_threads\mingw.thread.h"
|
|
#endif
|
|
#ifdef _MSC_VER
|
|
#include <io.h>
|
|
#define ftruncate _chsize
|
|
#else
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#ifndef UNIX
|
|
#include <conio.h>
|
|
#include <windows.h>
|
|
#define PATH_DELIM '\\'
|
|
#else
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
#include <errno.h>
|
|
#define PATH_DELIM '/'
|
|
#endif
|
|
|
|
using namespace std;
|
|
|
|
#include "contrib/bzip2/bzlib.h"
|
|
#include "contrib/giflib/precomp_gif.h"
|
|
#include "contrib/packjpg/precomp_jpg.h"
|
|
#include "contrib/packmp3/precomp_mp3.h"
|
|
#include "contrib/zlib/zlib.h"
|
|
|
|
#define CHUNK 262144 // 256 KB buffersize
|
|
#define DIV3CHUNK 262143 // DIV3CHUNK is a bit smaller/larger than CHUNK, so that DIV3CHUNK mod 3 = 0
|
|
#define CHECKBUF_SIZE 4096
|
|
#define COPY_BUF_SIZE 512
|
|
#define FAST_COPY_WORK_SIGN_DIST 64 // update work sign after (FAST_COPY_WORK_SIGN_DIST * COPY_BUF_SIZE) bytes
|
|
#define COMP_CHUNK 512
|
|
#define IN_BUF_SIZE 65536 //input buffer
|
|
#define PENALTY_BYTES_TOLERANCE 160
|
|
|
|
unsigned char copybuf[COPY_BUF_SIZE];
|
|
|
|
unsigned char in_buf[IN_BUF_SIZE];
|
|
long long in_buf_pos;
|
|
int cb; // "checkbuf"
|
|
|
|
unsigned char in[CHUNK];
|
|
unsigned char out[CHUNK];
|
|
|
|
// name of temporary files
|
|
char metatempfile[18] = "~temp00000000.dat";
|
|
char tempfile0[19] = "~temp000000000.dat";
|
|
char tempfile1[19] = "~temp000000001.dat";
|
|
char tempfile2[19] = "~temp000000002.dat";
|
|
char tempfile3[19] = "~temp000000003.dat";
|
|
char* tempfilelist;
|
|
int tempfilelist_count = 0;
|
|
|
|
#include "precomp.h"
|
|
|
|
static char work_signs[5] = "|/-\\";
|
|
int work_sign_var = 0;
|
|
long long work_sign_start_time = get_time_ms();
|
|
|
|
// recursion
|
|
int recursion_stack_size = 0;
|
|
int recursion_depth = 0;
|
|
int max_recursion_depth = 10;
|
|
int max_recursion_depth_used = 0;
|
|
bool max_recursion_depth_reached = false;
|
|
unsigned char* recursion_stack = NULL;
|
|
void recursion_stack_push(void* var, int var_size);
|
|
void recursion_stack_pop(void* var, int var_size);
|
|
void recursion_push();
|
|
void recursion_pop();
|
|
|
|
float global_min_percent = 0;
|
|
float global_max_percent = 100;
|
|
|
|
// compression-on-the-fly
|
|
unsigned char otf_in[CHUNK];
|
|
unsigned char otf_out[CHUNK];
|
|
|
|
#include "contrib/liblzma/precomp_xz.h"
|
|
lzma_stream otf_xz_stream_c = LZMA_STREAM_INIT, otf_xz_stream_d = LZMA_STREAM_INIT;
|
|
|
|
int compression_otf_method = OTF_XZ_MT;
|
|
uint64_t compression_otf_max_memory = 0;
|
|
int compression_otf_thread_count = 0;
|
|
int conversion_from_method;
|
|
int conversion_to_method;
|
|
bool decompress_otf_end = false;
|
|
bz_stream otf_bz2_stream_c, otf_bz2_stream_d;
|
|
|
|
FILE* fin = NULL;
|
|
FILE* fout = NULL;
|
|
FILE* ftempout = NULL;
|
|
FILE* frecomp = NULL;
|
|
FILE* fdecomp = NULL;
|
|
FILE* fpack = NULL;
|
|
FILE* fpng = NULL;
|
|
FILE* fjpg = NULL;
|
|
FILE* fmp3 = NULL;
|
|
|
|
int retval;
|
|
long long input_file_pos;
|
|
|
|
bool DEBUG_MODE = false;
|
|
|
|
bool compressed_data_found;
|
|
bool uncompressed_data_in_work;
|
|
long long uncompressed_length = -1;
|
|
long long uncompressed_pos;
|
|
long long uncompressed_start;
|
|
|
|
char* input_file_name = NULL;
|
|
char* output_file_name = NULL;
|
|
|
|
long long start_time, sec_time;
|
|
long long fin_length;
|
|
long long uncompressed_bytes_written = 0;
|
|
long long uncompressed_bytes_total = 0;
|
|
bool show_lzma_progress = true;
|
|
char lzma_progress_text[70];
|
|
int old_lzma_progress_text_length = -1;
|
|
int lzma_mib_total = 0, lzma_mib_written = 0;
|
|
|
|
int comp_mem_level_count[81];
|
|
int levels_sorted[81];
|
|
bool zlib_level_was_used[81];
|
|
bool anything_was_used;
|
|
bool level_switch_used = false;
|
|
bool non_zlib_was_used;
|
|
|
|
// statistics
|
|
unsigned int recompressed_streams_count = 0;
|
|
unsigned int recompressed_pdf_count = 0;
|
|
unsigned int recompressed_pdf_count_8_bit = 0;
|
|
unsigned int recompressed_pdf_count_24_bit = 0;
|
|
unsigned int recompressed_zip_count = 0;
|
|
unsigned int recompressed_gzip_count = 0;
|
|
unsigned int recompressed_png_count = 0;
|
|
unsigned int recompressed_png_multi_count = 0;
|
|
unsigned int recompressed_gif_count = 0;
|
|
unsigned int recompressed_jpg_count = 0;
|
|
unsigned int recompressed_jpg_prog_count = 0;
|
|
unsigned int recompressed_mp3_count = 0;
|
|
unsigned int recompressed_swf_count = 0;
|
|
unsigned int recompressed_base64_count = 0;
|
|
unsigned int recompressed_bzip2_count = 0;
|
|
unsigned int recompressed_zlib_count = 0; // intense mode
|
|
unsigned int recompressed_brute_count = 0; // brute mode
|
|
|
|
unsigned int decompressed_streams_count = 0;
|
|
unsigned int decompressed_pdf_count = 0;
|
|
unsigned int decompressed_pdf_count_8_bit = 0;
|
|
unsigned int decompressed_pdf_count_24_bit = 0;
|
|
unsigned int decompressed_zip_count = 0;
|
|
unsigned int decompressed_gzip_count = 0;
|
|
unsigned int decompressed_png_count = 0;
|
|
unsigned int decompressed_png_multi_count = 0;
|
|
unsigned int decompressed_gif_count = 0;
|
|
unsigned int decompressed_jpg_count = 0;
|
|
unsigned int decompressed_jpg_prog_count = 0;
|
|
unsigned int decompressed_mp3_count = 0;
|
|
unsigned int decompressed_swf_count = 0;
|
|
unsigned int decompressed_base64_count = 0;
|
|
unsigned int decompressed_bzip2_count = 0;
|
|
unsigned int decompressed_zlib_count = 0; // intense mode
|
|
unsigned int decompressed_brute_count = 0; // brute mode
|
|
|
|
#define P_NONE 0
|
|
#define P_COMPRESS 1
|
|
#define P_DECOMPRESS 2
|
|
#define P_CONVERT 3
|
|
int comp_decomp_state = P_NONE;
|
|
|
|
// penalty bytes
|
|
#define MAX_PENALTY_BYTES 16384
|
|
#ifndef PRECOMPDLL
|
|
char* penalty_bytes = new char[MAX_PENALTY_BYTES];
|
|
char* local_penalty_bytes = new char[MAX_PENALTY_BYTES];
|
|
char* best_penalty_bytes = new char[MAX_PENALTY_BYTES];
|
|
#else
|
|
char* penalty_bytes;
|
|
char* local_penalty_bytes;
|
|
char* best_penalty_bytes;
|
|
#endif
|
|
int penalty_bytes_len = 0;
|
|
|
|
long long* ignore_list = NULL; // positions to ignore
|
|
int ignore_list_len = 0;
|
|
|
|
long long saved_input_file_pos, saved_cb;
|
|
int min_ident_size = 4;
|
|
int min_ident_size_intense_brute_mode = 64;
|
|
|
|
set<long long>* intense_ignore_offsets = NULL;
|
|
set<long long>* brute_ignore_offsets = NULL;
|
|
|
|
unsigned char zlib_header[2];
|
|
unsigned int* idat_lengths = NULL;
|
|
unsigned int* idat_crcs = NULL;
|
|
int idat_count;
|
|
|
|
long long suppress_jpg_parsing_until;
|
|
long long suppress_mp3_type_until[16];
|
|
long long suppress_mp3_big_value_pairs_sum;
|
|
long long mp3_parsing_cache_second_frame;
|
|
long long mp3_parsing_cache_n;
|
|
long long mp3_parsing_cache_mp3_length;
|
|
|
|
bool fast_mode = false;
|
|
bool intense_mode = false;
|
|
bool brute_mode = false;
|
|
bool pdf_bmp_mode = false;
|
|
bool prog_only = false;
|
|
bool use_mjpeg = true;
|
|
|
|
int intense_mode_depth_limit = -1;
|
|
int brute_mode_depth_limit = -1;
|
|
|
|
// compression type bools
|
|
bool use_pdf = true;
|
|
bool use_zip = true;
|
|
bool use_gzip = true;
|
|
bool use_png = true;
|
|
bool use_gif = true;
|
|
bool use_jpg = true;
|
|
bool use_mp3 = true;
|
|
bool use_swf = true;
|
|
bool use_base64 = true;
|
|
bool use_bzip2 = true;
|
|
|
|
// Precomp DLL things
|
|
#ifdef PRECOMPDLL
|
|
|
|
#include "precomp_dll.h"
|
|
|
|
// get copyright message
|
|
// msg = Buffer for error messages (256 bytes buffer size are enough)
|
|
DLL void get_copyright_msg(char* msg) {
|
|
if (V_MINOR2 == 0) {
|
|
sprintf(msg, "Precomp DLL v%i.%i (c) 2006-2017 by Christian Schneider",V_MAJOR,V_MINOR);
|
|
} else {
|
|
sprintf(msg, "Precomp DLL v%i.%i.%i (c) 2006-2017 by Christian Schneider",V_MAJOR,V_MINOR,V_MINOR2);
|
|
}
|
|
}
|
|
|
|
void setSwitches(Switches switches) {
|
|
compression_otf_method = switches.compression_method;
|
|
show_lzma_progress = (compression_otf_method == OTF_XZ_MT);
|
|
ignore_list = switches.ignore_list;
|
|
ignore_list_len = switches.ignore_list_len;
|
|
intense_mode = switches.intense_mode;
|
|
fast_mode = switches.fast_mode;
|
|
brute_mode = switches.brute_mode;
|
|
pdf_bmp_mode = switches.pdf_bmp_mode;
|
|
prog_only = switches.prog_only;
|
|
DEBUG_MODE = switches.debug_mode;
|
|
min_ident_size = switches.min_ident_size;
|
|
compression_otf_max_memory = switches.compression_otf_max_memory;
|
|
compression_otf_thread_count = switches.compression_otf_thread_count;
|
|
use_pdf = switches.use_pdf;
|
|
use_zip = switches.use_zip;
|
|
use_gzip = switches.use_gzip;
|
|
use_png = switches.use_png;
|
|
use_gif = switches.use_gif;
|
|
use_jpg = switches.use_jpg;
|
|
use_mp3 = switches.use_mp3;
|
|
use_swf = switches.use_swf;
|
|
use_base64 = switches.use_base64;
|
|
use_bzip2 = switches.use_bzip2;
|
|
use_mjpeg = switches.use_mjpeg;
|
|
if (switches.level_switch) {
|
|
|
|
for (int i = 0; i < 81; i++) {
|
|
if (switches.use_zlib_level[i]) {
|
|
comp_mem_level_count[i] = 0;
|
|
} else {
|
|
comp_mem_level_count[i] = -1;
|
|
}
|
|
}
|
|
|
|
level_switch_used = true;
|
|
|
|
}
|
|
}
|
|
|
|
// precompress a file
|
|
// in_file = input filename
|
|
// out_file = output filename
|
|
// msg = Buffer for error messages (256 bytes buffer size are enough)
|
|
DLL bool precompress_file(char* in_file, char* out_file, char* msg, Switches switches) {
|
|
|
|
// init compression and memory level count
|
|
for (int i = 0; i < 81; i++) {
|
|
comp_mem_level_count[i] = 0;
|
|
zlib_level_was_used[i] = false;
|
|
}
|
|
|
|
fin_length = fileSize64(in_file);
|
|
|
|
fin = fopen(in_file, "rb");
|
|
if (fin == NULL) {
|
|
sprintf(msg, "ERROR: Input file \"%s\" doesn't exist", in_file);
|
|
|
|
return false;
|
|
}
|
|
|
|
fout = fopen(out_file, "wb");
|
|
|
|
if (fout == NULL) {
|
|
sprintf(msg, "ERROR: Can't create output file \"%s\"", out_file);
|
|
|
|
return false;
|
|
}
|
|
|
|
setSwitches(switches);
|
|
|
|
input_file_name = new char[strlen(in_file)+1];
|
|
strcpy(input_file_name, in_file);
|
|
output_file_name = new char[strlen(out_file)+1];
|
|
strcpy(output_file_name, out_file);
|
|
|
|
sort_comp_mem_levels();
|
|
|
|
start_time = get_time_ms();
|
|
|
|
penalty_bytes = new char[MAX_PENALTY_BYTES];
|
|
local_penalty_bytes = new char[MAX_PENALTY_BYTES];
|
|
best_penalty_bytes = new char[MAX_PENALTY_BYTES];
|
|
|
|
compress_file();
|
|
|
|
return true;
|
|
}
|
|
|
|
// recompress a file
|
|
// in_file = input filename
|
|
// out_file = output filename
|
|
// msg = Buffer for error messages (256 bytes buffer size are enough)
|
|
DLL bool recompress_file(char* in_file, char* out_file, char* msg, Switches switches) {
|
|
|
|
// init compression and memory level count
|
|
for (int i = 0; i < 81; i++) {
|
|
comp_mem_level_count[i] = 0;
|
|
zlib_level_was_used[i] = false;
|
|
}
|
|
|
|
fin_length = fileSize64(in_file);
|
|
|
|
fin = fopen(in_file, "rb");
|
|
if (fin == NULL) {
|
|
sprintf(msg, "ERROR: Input file \"%s\" doesn't exist", in_file);
|
|
|
|
return false;
|
|
}
|
|
|
|
fout = fopen(out_file, "wb");
|
|
if (fout == NULL) {
|
|
sprintf(msg, "ERROR: Can't create output file \"%s\"", out_file);
|
|
|
|
return false;
|
|
}
|
|
|
|
setSwitches(switches);
|
|
|
|
input_file_name = new char[strlen(in_file)+1];
|
|
strcpy(input_file_name, in_file);
|
|
output_file_name = new char[strlen(out_file)+1];
|
|
strcpy(output_file_name, out_file);
|
|
|
|
sort_comp_mem_levels();
|
|
|
|
start_time = get_time_ms();
|
|
|
|
penalty_bytes = new char[MAX_PENALTY_BYTES];
|
|
local_penalty_bytes = new char[MAX_PENALTY_BYTES];
|
|
best_penalty_bytes = new char[MAX_PENALTY_BYTES];
|
|
|
|
decompress_file();
|
|
|
|
return true;
|
|
}
|
|
|
|
// test if a file contains streams that can be precompressed
|
|
DLL bool file_precompressable(char* in, char* msg) {
|
|
return false;
|
|
}
|
|
|
|
#else
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
int return_errorlevel = 0;
|
|
|
|
// register CTRL-C handler
|
|
(void) signal(SIGINT, ctrl_c_handler);
|
|
|
|
#ifndef COMFORT
|
|
switch (init(argc, argv)) {
|
|
#else
|
|
switch (init_comfort(argc, argv)) {
|
|
#endif
|
|
|
|
case P_COMPRESS:
|
|
{
|
|
start_time = get_time_ms();
|
|
if (!compress_file()) { // none of the streams could be decompressed
|
|
return_errorlevel = RETURN_NOTHING_DECOMPRESSED;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case P_DECOMPRESS:
|
|
{
|
|
start_time = get_time_ms();
|
|
decompress_file();
|
|
break;
|
|
}
|
|
|
|
case P_CONVERT:
|
|
{
|
|
start_time = get_time_ms();
|
|
convert_file();
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifdef COMFORT
|
|
wait_for_key();
|
|
#endif
|
|
|
|
return return_errorlevel;
|
|
}
|
|
|
|
#endif
|
|
#ifndef PRECOMPDLL
|
|
#ifndef COMFORT
|
|
int init(int argc, char* argv[]) {
|
|
int i, j;
|
|
bool appended_pcf = false;
|
|
|
|
printf("\n");
|
|
if (V_MINOR2 == 0) {
|
|
printf("Precomp v%i.%i %s %s - %s version",V_MAJOR,V_MINOR,V_OS,V_BIT,V_STATE);
|
|
} else {
|
|
printf("Precomp v%i.%i.%i %s %s - %s version",V_MAJOR,V_MINOR,V_MINOR2,V_OS,V_BIT,V_STATE);
|
|
}
|
|
printf(" - %s\n",V_MSG);
|
|
printf("Free for non-commercial use - Copyright 2006-2017 by Christian Schneider\n\n");
|
|
|
|
// init compression and memory level count
|
|
bool use_zlib_level[81];
|
|
for (i = 0; i < 81; i++) {
|
|
comp_mem_level_count[i] = 0;
|
|
zlib_level_was_used[i] = false;
|
|
use_zlib_level[i] = true;
|
|
}
|
|
|
|
// init JPG suppression
|
|
suppress_jpg_parsing_until = -1;
|
|
|
|
// init MP3 suppression
|
|
for (i = 0; i < 16; i++) {
|
|
suppress_mp3_type_until[i] = -1;
|
|
}
|
|
suppress_mp3_big_value_pairs_sum = -1;
|
|
mp3_parsing_cache_second_frame = -1;
|
|
|
|
bool valid_syntax = false;
|
|
bool input_file_given = false;
|
|
bool output_file_given = false;
|
|
int operation = P_COMPRESS;
|
|
bool parse_on = true;
|
|
bool level_switch = false;
|
|
bool min_ident_size_set = false;
|
|
bool recursion_depth_set = false;
|
|
bool lzma_max_memory_set = false;
|
|
bool lzma_thread_count_set = false;
|
|
bool long_help = false;
|
|
bool preserve_extension = false;
|
|
|
|
for (i = 1; (i < argc) && (parse_on); i++) {
|
|
if (argv[i][0] == '-') { // switch
|
|
if (input_file_given) {
|
|
valid_syntax = false;
|
|
parse_on = false;
|
|
break;
|
|
}
|
|
switch (toupper(argv[i][1])) {
|
|
case 0:
|
|
{
|
|
valid_syntax = false;
|
|
parse_on = false;
|
|
break;
|
|
}
|
|
case 'I':
|
|
{
|
|
if (toupper(argv[i][2]) == 'N') { // intense mode
|
|
if ((toupper(argv[i][3]) == 'T') && (toupper(argv[i][4]) == 'E')
|
|
&& (toupper(argv[i][5]) == 'N') && (toupper(argv[i][6]) == 'S') && (toupper(argv[i][7]) == 'E')) {
|
|
intense_mode = true;
|
|
if (strlen(argv[i]) > 8) {
|
|
int intense_mode_limit = 0;
|
|
int multiplicator = 1;
|
|
for (j = strlen(argv[i]) - 9; j >= 0; j--) {
|
|
if ((argv[i][j+8] < '0') || (argv[i][j+8] > '9')) {
|
|
printf("ERROR: Only numbers allowed for intense mode level limit\n");
|
|
exit(1);
|
|
}
|
|
intense_mode_limit += ((long long)(argv[i][j+8])-'0') * multiplicator;
|
|
if ((multiplicator * 10) < multiplicator) {
|
|
error(ERR_INTENSE_MODE_LIMIT_TOO_BIG);
|
|
}
|
|
multiplicator *= 10;
|
|
}
|
|
intense_mode_depth_limit = intense_mode_limit;
|
|
}
|
|
} else {
|
|
printf("ERROR: Unknown switch \"%s\"\n", argv[i]);
|
|
exit(1);
|
|
}
|
|
} else {
|
|
long long ignore_pos = 0;
|
|
long long multiplicator = 1;
|
|
for (j = (strlen(argv[i])-3); j >= 0; j--) {
|
|
if ((argv[i][j+2] < '0') || (argv[i][j+2] > '9')) {
|
|
printf("ERROR: Only numbers allowed for ignore position\n");
|
|
exit(1);
|
|
}
|
|
ignore_pos += ((long long)(argv[i][j+2])-'0') * multiplicator;
|
|
if ((multiplicator * 10) < multiplicator) {
|
|
error(ERR_IGNORE_POS_TOO_BIG);
|
|
}
|
|
multiplicator *= 10;
|
|
}
|
|
ignore_list = (long long*)realloc(ignore_list, (ignore_list_len + 1) * sizeof(long long));
|
|
ignore_list[ignore_list_len] = ignore_pos;
|
|
ignore_list_len++;
|
|
}
|
|
break;
|
|
}
|
|
case 'D':
|
|
{
|
|
if (recursion_depth_set) {
|
|
error(ERR_ONLY_SET_RECURSION_DEPTH_ONCE);
|
|
}
|
|
|
|
unsigned int max_recursion_d = 0;
|
|
unsigned int multiplicator = 1;
|
|
for (j = (strlen(argv[i])-3); j >= 0; j--) {
|
|
if ((argv[i][j+2] < '0') || (argv[i][j+2] > '9')) {
|
|
printf("ERROR: Only numbers allowed for maximal recursion depth\n");
|
|
exit(1);
|
|
}
|
|
max_recursion_d += ((unsigned int)(argv[i][j+2])-'0') * multiplicator;
|
|
if ((multiplicator * 10) < multiplicator) {
|
|
error(ERR_RECURSION_DEPTH_TOO_BIG);
|
|
}
|
|
multiplicator *= 10;
|
|
}
|
|
max_recursion_depth = max_recursion_d;
|
|
recursion_depth_set = true;
|
|
break;
|
|
}
|
|
case 'S':
|
|
{
|
|
if (min_ident_size_set) {
|
|
error(ERR_ONLY_SET_MIN_SIZE_ONCE);
|
|
}
|
|
if (strlen(argv[i]) == 2) {
|
|
printf("ERROR: Number needed to set minimal identical byte size\n");
|
|
exit(1);
|
|
}
|
|
unsigned int ident_size = 0;
|
|
unsigned int multiplicator = 1;
|
|
for (j = (strlen(argv[i]) - 3); j >= 0; j--) {
|
|
if ((argv[i][j+2] < '0') || (argv[i][j+2] > '9')) {
|
|
printf("ERROR: Only numbers allowed for minimal identical byte size\n");
|
|
exit(1);
|
|
}
|
|
ident_size += ((unsigned int)(argv[i][j+2])-'0') * multiplicator;
|
|
if ((multiplicator * 10) < multiplicator) {
|
|
error(ERR_IDENTICAL_BYTE_SIZE_TOO_BIG);
|
|
}
|
|
multiplicator *= 10;
|
|
}
|
|
min_ident_size = ident_size;
|
|
min_ident_size_set = true;
|
|
break;
|
|
}
|
|
case 'B':
|
|
{
|
|
if ((toupper(argv[i][2]) == 'R') && (toupper(argv[i][3]) == 'U') && (toupper(argv[i][4]) == 'T') && (toupper(argv[i][5]) == 'E')) {
|
|
brute_mode = true;
|
|
if (strlen(argv[i]) > 6) {
|
|
int brute_mode_limit = 0;
|
|
int multiplicator = 1;
|
|
for (j = strlen(argv[i]) - 7; j >= 0; j--) {
|
|
if ((argv[i][j+6] < '0') || (argv[i][j+6] > '9')) {
|
|
printf("ERROR: Only numbers allowed for brute mode level limit\n");
|
|
exit(1);
|
|
}
|
|
brute_mode_limit += ((long long)(argv[i][j+6])-'0') * multiplicator;
|
|
if ((multiplicator * 10) < multiplicator) {
|
|
error(ERR_INTENSE_MODE_LIMIT_TOO_BIG);
|
|
}
|
|
multiplicator *= 10;
|
|
}
|
|
brute_mode_depth_limit = brute_mode_limit;
|
|
}
|
|
} else {
|
|
printf("ERROR: Unknown switch \"%s\"\n", argv[i]);
|
|
exit(1);
|
|
}
|
|
break;
|
|
}
|
|
case 'L':
|
|
{
|
|
if ((toupper(argv[i][2]) == 'O') && (toupper(argv[i][3]) == 'N') && (toupper(argv[i][4]) == 'G')
|
|
&& (toupper(argv[i][5]) == 'H') && (toupper(argv[i][6]) == 'E') && (toupper(argv[i][7]) == 'L')
|
|
&& (toupper(argv[i][8]) == 'P')) {
|
|
long_help = true;
|
|
} else if (toupper(argv[i][2]) == 'M') { // LZMA max. memory
|
|
if (lzma_max_memory_set) {
|
|
error(ERR_ONLY_SET_LZMA_MEMORY_ONCE);
|
|
}
|
|
int multiplicator = 1;
|
|
for (j = (strlen(argv[i]) - 4); j >= 0; j--) {
|
|
if ((argv[i][j+3] < '0') || (argv[i][j+3] > '9')) {
|
|
printf("ERROR: Only numbers allowed for LZMA maximal memory\n");
|
|
exit(1);
|
|
}
|
|
compression_otf_max_memory += ((unsigned int)(argv[i][j+3])-'0') * multiplicator;
|
|
if ((multiplicator * 10) < multiplicator) {
|
|
exit(1);
|
|
}
|
|
multiplicator *= 10;
|
|
}
|
|
lzma_max_memory_set = true;
|
|
} else if (toupper(argv[i][2]) == 'T') { // LZMA thread count
|
|
if (lzma_thread_count_set) {
|
|
error(ERR_ONLY_SET_LZMA_THREAD_ONCE);
|
|
}
|
|
int multiplicator = 1;
|
|
for (j = (strlen(argv[i]) - 4); j >= 0; j--) {
|
|
if ((argv[i][j+3] < '0') || (argv[i][j+3] > '9')) {
|
|
printf("ERROR: Only numbers allowed for LZMA thread count\n");
|
|
exit(1);
|
|
}
|
|
compression_otf_thread_count += ((unsigned int)(argv[i][j+3])-'0') * multiplicator;
|
|
if ((multiplicator * 10) < multiplicator) {
|
|
exit(1);
|
|
}
|
|
multiplicator *= 10;
|
|
}
|
|
lzma_thread_count_set = true;
|
|
} else {
|
|
printf("ERROR: Unknown switch \"%s\"\n", argv[i]);
|
|
exit(1);
|
|
}
|
|
break;
|
|
}
|
|
case 'P':
|
|
{
|
|
if ((toupper(argv[i][2]) == 'D') && (toupper(argv[i][3]) == 'F') && (toupper(argv[i][4]) == 'B') && (toupper(argv[i][5]) == 'M') && (toupper(argv[i][6]) == 'P')) {
|
|
switch (argv[i][7]) {
|
|
case '+':
|
|
pdf_bmp_mode = true;
|
|
break;
|
|
case '-':
|
|
pdf_bmp_mode = false;
|
|
break;
|
|
default:
|
|
printf("ERROR: Only + or - for this switch allowed\n");
|
|
exit(1);
|
|
break;
|
|
}
|
|
} else if ((toupper(argv[i][2]) == 'R') && (toupper(argv[i][3]) == 'O') && (toupper(argv[i][4]) == 'G') && (toupper(argv[i][5]) == 'O') && (toupper(argv[i][6]) == 'N') && (toupper(argv[i][7]) == 'L') && (toupper(argv[i][8]) == 'Y')) {
|
|
switch (argv[i][9]) {
|
|
case '+':
|
|
prog_only = true;
|
|
break;
|
|
case '-':
|
|
prog_only = false;
|
|
break;
|
|
default:
|
|
printf("ERROR: Only + or - for this switch allowed\n");
|
|
exit(1);
|
|
break;
|
|
}
|
|
} else {
|
|
printf("ERROR: Unknown switch \"%s\"\n", argv[i]);
|
|
exit(1);
|
|
}
|
|
break;
|
|
}
|
|
case 'T':
|
|
{
|
|
bool set_to;
|
|
switch (argv[i][2]) {
|
|
case '+':
|
|
use_pdf = false;
|
|
use_zip = false;
|
|
use_gzip = false;
|
|
use_png = false;
|
|
use_gif = false;
|
|
use_jpg = false;
|
|
use_mp3 = false;
|
|
use_swf = false;
|
|
use_base64 = false;
|
|
use_bzip2 = false;
|
|
set_to = true;
|
|
break;
|
|
case '-':
|
|
use_pdf = true;
|
|
use_zip = true;
|
|
use_gzip = true;
|
|
use_png = true;
|
|
use_gif = true;
|
|
use_jpg = true;
|
|
use_mp3 = true;
|
|
use_swf = true;
|
|
use_base64 = true;
|
|
use_bzip2 = true;
|
|
set_to = false;
|
|
break;
|
|
default:
|
|
printf("ERROR: Only + or - for type switch allowed\n");
|
|
exit(1);
|
|
break;
|
|
}
|
|
for (j = 3; j < (int)strlen(argv[i]); j++) {
|
|
switch (toupper(argv[i][j])) {
|
|
case 'P': // PDF
|
|
use_pdf = set_to;
|
|
break;
|
|
case 'Z': // ZIP
|
|
use_zip = set_to;
|
|
break;
|
|
case 'G': // GZip
|
|
use_gzip = set_to;
|
|
break;
|
|
case 'N': // PNG
|
|
use_png = set_to;
|
|
break;
|
|
case 'F': // GIF
|
|
use_gif = set_to;
|
|
break;
|
|
case 'J': // JPG
|
|
use_jpg = set_to;
|
|
break;
|
|
case '3': // MP3
|
|
use_mp3 = set_to;
|
|
break;
|
|
case 'S': // SWF
|
|
use_swf = set_to;
|
|
break;
|
|
case 'M': // MIME Base64
|
|
use_base64 = set_to;
|
|
break;
|
|
case 'B': // bZip2
|
|
use_bzip2 = set_to;
|
|
break;
|
|
default:
|
|
printf("ERROR: Invalid compression type %c\n", argv[i][j]);
|
|
exit(1);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'C':
|
|
{
|
|
switch (toupper(argv[i][2])) {
|
|
case 'N': // no compression
|
|
compression_otf_method = OTF_NONE;
|
|
break;
|
|
case 'B': // bZip2
|
|
compression_otf_method = OTF_BZIP2;
|
|
break;
|
|
case 'L': // lzma2 multithreaded
|
|
compression_otf_method = OTF_XZ_MT;
|
|
break;
|
|
default:
|
|
printf("ERROR: Invalid compression method %c\n", argv[i][2]);
|
|
exit(1);
|
|
break;
|
|
}
|
|
show_lzma_progress = (compression_otf_method == OTF_XZ_MT);
|
|
break;
|
|
}
|
|
case 'N':
|
|
{
|
|
switch (toupper(argv[i][2])) {
|
|
case 'N': // no compression
|
|
conversion_to_method = OTF_NONE;
|
|
break;
|
|
case 'B': // bZip2
|
|
conversion_to_method = OTF_BZIP2;
|
|
break;
|
|
case 'L': // lzma2 multithreaded
|
|
conversion_to_method = OTF_XZ_MT;
|
|
break;
|
|
default:
|
|
printf("ERROR: Invalid conversion method %c\n", argv[i][2]);
|
|
exit(1);
|
|
break;
|
|
}
|
|
operation = P_CONVERT;
|
|
break;
|
|
}
|
|
case 'V':
|
|
{
|
|
DEBUG_MODE = true;
|
|
break;
|
|
}
|
|
case 'R':
|
|
{
|
|
operation = P_DECOMPRESS;
|
|
break;
|
|
}
|
|
case 'Z':
|
|
{
|
|
if (toupper(argv[i][2]) == 'L') {
|
|
for (j = 0; j < 81; j++) {
|
|
use_zlib_level[j] = false;
|
|
}
|
|
|
|
level_switch = true;
|
|
|
|
for (j = 0; j < ((int)strlen(argv[i])-3); j += 3) {
|
|
if ((j+5) < (int)strlen(argv[i])) {
|
|
if (argv[i][j+5] != ',') {
|
|
printf("ERROR: zLib levels have to be separated with commas\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
if ((j+4) >= (int)strlen(argv[i])) {
|
|
printf("ERROR: Last zLib level is incomplete\n");
|
|
exit(1);
|
|
}
|
|
int comp_level_to_use = (char(argv[i][j+3]) - '1');
|
|
int mem_level_to_use = (char(argv[i][j+4]) - '1');
|
|
if ( ((comp_level_to_use >= 0) && (comp_level_to_use <= 8))
|
|
&& ((mem_level_to_use >= 0) && (mem_level_to_use <= 8))) {
|
|
use_zlib_level[comp_level_to_use + mem_level_to_use * 9] = true;
|
|
} else {
|
|
printf("ERROR: Invalid zlib level %c%c\n", argv[i][j+3], argv[i][j+4]);
|
|
exit(1);
|
|
}
|
|
}
|
|
break;
|
|
} else {
|
|
printf("ERROR: Unknown switch \"%s\"\n", argv[i]);
|
|
exit(1);
|
|
}
|
|
}
|
|
case 'O':
|
|
{
|
|
if (output_file_given) {
|
|
error(ERR_MORE_THAN_ONE_OUTPUT_FILE);
|
|
}
|
|
|
|
if (strlen(argv[i]) == 2) {
|
|
error(ERR_DONT_USE_SPACE);
|
|
}
|
|
|
|
output_file_given = true;
|
|
output_file_name = new char[strlen(argv[i]) + 5];
|
|
strcpy(output_file_name, argv[i] + 2);
|
|
|
|
// check for backslash in file name
|
|
char* backslash_at_pos = strrchr(output_file_name, PATH_DELIM);
|
|
|
|
// dot in output file name? If not, use .pcf extension
|
|
char* dot_at_pos = strrchr(output_file_name, '.');
|
|
if ((dot_at_pos == NULL) || ((backslash_at_pos != NULL) && (backslash_at_pos > dot_at_pos))) {
|
|
strcpy(output_file_name + strlen(argv[i]) - 2, ".pcf");
|
|
appended_pcf = true;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 'M':
|
|
{
|
|
if (toupper(argv[i][2]) == 'J') {
|
|
if ((toupper(argv[i][3]) == 'P') && (toupper(argv[i][4]) == 'E') && (toupper(argv[i][5]) == 'G')) {
|
|
switch (argv[i][6]) {
|
|
case '+':
|
|
use_mjpeg = true;
|
|
break;
|
|
case '-':
|
|
use_mjpeg = false;
|
|
break;
|
|
default:
|
|
printf("ERROR: Only + or - for this switch allowed\n");
|
|
exit(1);
|
|
break;
|
|
}
|
|
} else {
|
|
printf("ERROR: Unknown switch \"%s\"\n", argv[i]);
|
|
exit(1);
|
|
}
|
|
} else {
|
|
printf("ERROR: Unknown switch \"%s\"\n", argv[i]);
|
|
exit(1);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 'F':
|
|
{
|
|
fast_mode = true;
|
|
break;
|
|
}
|
|
case 'E':
|
|
{
|
|
preserve_extension = true;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
printf("ERROR: Unknown switch \"%s\"\n", argv[i]);
|
|
exit(1);
|
|
}
|
|
}
|
|
} else { // no switch
|
|
if (input_file_given) {
|
|
error(ERR_MORE_THAN_ONE_INPUT_FILE);
|
|
}
|
|
|
|
input_file_given = true;
|
|
input_file_name = argv[i];
|
|
|
|
fin_length = fileSize64(argv[i]);
|
|
|
|
fin = fopen(argv[i],"rb");
|
|
if (fin == NULL) {
|
|
printf("ERROR: Input file \"%s\" doesn't exist\n", input_file_name);
|
|
|
|
exit(1);
|
|
}
|
|
|
|
// output file given? If not, use input filename with .pcf extension
|
|
if ((!output_file_given) && (operation == P_COMPRESS)) {
|
|
if(!preserve_extension) {
|
|
output_file_name = new char[strlen(input_file_name) + 9];
|
|
strcpy(output_file_name, input_file_name);
|
|
char* backslash_at_pos = strrchr(output_file_name, PATH_DELIM);
|
|
char* dot_at_pos = strrchr(output_file_name, '.');
|
|
if ((dot_at_pos == NULL) || ((backslash_at_pos != NULL) && (dot_at_pos < backslash_at_pos))) {
|
|
strcpy(output_file_name + strlen(input_file_name), ".pcf");
|
|
} else {
|
|
strcpy(dot_at_pos, ".pcf");
|
|
// same as output file because input file had .pcf extension?
|
|
if (strcmp(input_file_name, output_file_name) == 0) {
|
|
strcpy(dot_at_pos, "_pcf.pcf");
|
|
}
|
|
}
|
|
} else {
|
|
output_file_name = new char[strlen(input_file_name) + 9];
|
|
strcpy(output_file_name,input_file_name);
|
|
strcat(output_file_name,".pcf");
|
|
}
|
|
output_file_given = true;
|
|
} else if ((!output_file_given) && (operation == P_CONVERT)) {
|
|
printf("ERROR: Please specify an output file for conversion\n");
|
|
exit(1);
|
|
}
|
|
|
|
valid_syntax = true;
|
|
}
|
|
|
|
}
|
|
|
|
if (!valid_syntax) {
|
|
printf("Usage: precomp [-switches] input_file\n\n");
|
|
if (long_help) {
|
|
printf("Switches (and their <default values>):\n");
|
|
} else {
|
|
printf("Common switches (and their <default values>):\n");
|
|
}
|
|
printf(" r \"Recompress\" PCF file (restore original file)\n");
|
|
printf(" o[filename] Write output to [filename] <[input_file].pcf or file in header>\n");
|
|
printf(" e preserve original extension of input name for output name \n");
|
|
printf(" c[lbn] Compression method to use, l = lzma2, b = bZip2, n = none <l>\n");
|
|
printf(" lm[amount] Set maximal LZMA memory in MiB <%i>\n", lzma_max_memory_default());
|
|
printf(" lt[count] Set LZMA thread count <auto-detect: %i>\n", auto_detected_thread_count());
|
|
printf(" n[lbn] Convert a PCF file to this compression (same as above) <off>\n");
|
|
printf(" v Verbose (debug) mode <off>\n");
|
|
printf(" d[depth] Set maximal recursion depth <10>\n");
|
|
printf(" zl[1..9][1..9] zLib levels to try for compression (comma separated) <all>\n");
|
|
printf(" intense Detect raw zLib headers, too. Slower and more sensitive <off>\n");
|
|
if (long_help) {
|
|
printf(" brute Brute force zLib detection. VERY Slow and most sensitive <off>\n");
|
|
}
|
|
printf(" t[+-][pzgnfjsmb3] Compression type switch <all enabled>\n");
|
|
printf(" t+ = enable these types only, t- = enable all types except these\n");
|
|
printf(" P = PDF, Z = ZIP, G = GZip, N = PNG, F = GIF, J = JPG\n");
|
|
printf(" S = SWF, M = MIME Base64, B = bZip2, 3 = MP3\n");
|
|
|
|
if (!long_help) {
|
|
printf(" longhelp Show long help\n");
|
|
} else {
|
|
printf(" f Fast mode, use first found compression lvl for all streams <off>\n");
|
|
printf(" i[pos] Ignore stream at input file position [pos] <none>\n");
|
|
printf(" s[size] Set minimal identical byte size to [size] <4 (64 intense mode)>\n");
|
|
printf(" pdfbmp[+-] Wrap a BMP header around PDF images <off>\n");
|
|
printf(" progonly[+-] Recompress progressive JPGs only (useful for PAQ) <off>\n");
|
|
printf(" mjpeg[+-] Insert huffman table for MJPEG recompression <on>\n");
|
|
printf("\n");
|
|
printf(" You can use an optional number following -intense and -brute to set a\n");
|
|
printf(" limit for how deep in recursion they should be used. E.g. -intense0 means\n");
|
|
printf(" that intense mode will be used but not in recursion, -intense2 that only\n");
|
|
printf(" streams up to recursion depth 2 will be treated intense (3 or higher in\n");
|
|
printf(" this case won't). Using a sensible setting here can save you some time.\n");
|
|
}
|
|
|
|
exit(1);
|
|
} else {
|
|
if (operation == P_DECOMPRESS) {
|
|
// if .pcf was appended, remove it
|
|
if (appended_pcf) {
|
|
output_file_name[strlen(output_file_name)-4] = 0;
|
|
}
|
|
read_header();
|
|
}
|
|
|
|
if (file_exists(output_file_name)) {
|
|
printf("Output file \"%s\" exists. Overwrite (y/n)? ", output_file_name);
|
|
char ch = get_char_with_echo();
|
|
if ((ch != 'Y') && (ch != 'y')) {
|
|
printf("\n");
|
|
exit(0);
|
|
} else {
|
|
#ifndef UNIX
|
|
printf("\n\n");
|
|
#else
|
|
printf("\n");
|
|
#endif
|
|
}
|
|
}
|
|
fout = fopen(output_file_name,"wb");
|
|
if (fout == NULL) {
|
|
printf("ERROR: Can't create output file \"%s\"\n", output_file_name);
|
|
exit(1);
|
|
}
|
|
|
|
printf("Input file: %s\n",input_file_name);
|
|
printf("Output file: %s\n\n",output_file_name);
|
|
if (DEBUG_MODE) {
|
|
if (min_ident_size_set) {
|
|
printf("\n");
|
|
printf("Minimal ident size set to %i bytes\n", min_ident_size);
|
|
}
|
|
if (ignore_list_len > 0) {
|
|
printf("\n");
|
|
printf("Ignore position list:\n");
|
|
for (j = 0; j < ignore_list_len; j++) {
|
|
print64(ignore_list[j]);
|
|
printf("\n");
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
if (operation == P_CONVERT) convert_header();
|
|
}
|
|
|
|
if (level_switch) {
|
|
|
|
for (i = 0; i < 81; i++) {
|
|
if (use_zlib_level[i]) {
|
|
comp_mem_level_count[i] = 0;
|
|
} else {
|
|
comp_mem_level_count[i] = -1;
|
|
}
|
|
}
|
|
|
|
level_switch_used = true;
|
|
|
|
}
|
|
|
|
sort_comp_mem_levels();
|
|
|
|
packjpg_mp3_dll_msg();
|
|
|
|
return operation;
|
|
}
|
|
#else
|
|
int init_comfort(int argc, char* argv[]) {
|
|
int i, j;
|
|
int operation = P_COMPRESS;
|
|
bool parse_ini_file = true;
|
|
bool min_ident_size_set = false;
|
|
bool recursion_depth_set = false;
|
|
bool level_switch = false;
|
|
bool lzma_max_memory_set = false;
|
|
bool lzma_thread_count_set = false;
|
|
bool preserve_extension = false;
|
|
|
|
printf("\n");
|
|
if (V_MINOR2 == 0) {
|
|
printf("Precomp Comfort v%i.%i %s %s - %s version",V_MAJOR,V_MINOR,V_OS,V_BIT,V_STATE);
|
|
} else {
|
|
printf("Precomp Comfort v%i.%i.%i %s %s - %s version",V_MAJOR,V_MINOR,V_MINOR2,V_OS,V_BIT,V_STATE);
|
|
}
|
|
printf(" - %s\n",V_MSG);
|
|
printf("Free for non-commercial use - Copyright 2006-2017 by Christian Schneider\n\n");
|
|
|
|
// init compression and memory level count
|
|
bool use_zlib_level[81];
|
|
for (i = 0; i < 81; i++) {
|
|
comp_mem_level_count[i] = 0;
|
|
zlib_level_was_used[i] = false;
|
|
use_zlib_level[i] = true;
|
|
}
|
|
|
|
// init JPG suppression
|
|
suppress_jpg_parsing_until = -1;
|
|
|
|
// init MP3 suppression
|
|
for (i = 0; i < 16; i++) {
|
|
suppress_mp3_type_until[i] = -1;
|
|
}
|
|
suppress_mp3_big_value_pairs_sum = -1;
|
|
mp3_parsing_cache_second_frame = -1;
|
|
|
|
// parse parameters (should be input file only)
|
|
if (argc == 1) {
|
|
printf("Usage:\n");
|
|
printf("Drag and drop a file on the executable to precompress/restore it.\n");
|
|
printf("Edit INI file for parameters.\n");
|
|
wait_for_key();
|
|
exit(1);
|
|
}
|
|
if (argc > 2) {
|
|
error(ERR_MORE_THAN_ONE_INPUT_FILE);
|
|
} else {
|
|
input_file_name = argv[1];
|
|
|
|
fin_length = fileSize64(input_file_name);
|
|
|
|
fin = fopen(input_file_name,"rb");
|
|
if (fin == NULL) {
|
|
printf("ERROR: Input file \"%s\" doesn't exist\n", input_file_name);
|
|
wait_for_key();
|
|
exit(1);
|
|
}
|
|
|
|
if (fin_length > 6) {
|
|
if (check_for_pcf_file()) {
|
|
operation = P_DECOMPRESS;
|
|
}
|
|
}
|
|
}
|
|
|
|
// precomf.ini in EXE directory?
|
|
char precomf_ini[1024];
|
|
#ifdef _MSC_VER
|
|
#ifdef UNICODE
|
|
#define GetModuleFileName GetModuleFileNameA
|
|
#endif // UNICODE
|
|
#endif // _MSC_VER
|
|
GetModuleFileName(NULL, precomf_ini, 1024);
|
|
// truncate to get directory of executable only
|
|
char* lastslash = strrchr(precomf_ini, PATH_DELIM) + 1;
|
|
strcpy(lastslash, "precomf.ini");
|
|
printf("INI file: %s\n", precomf_ini);
|
|
|
|
if (!file_exists(precomf_ini)) {
|
|
printf("INI file not found. Create it (y/n)?");
|
|
char ch = getche();
|
|
printf("\n");
|
|
if ((ch != 'Y') && (ch != 'y')) {
|
|
wait_for_key();
|
|
exit(1);
|
|
} else {
|
|
FILE* fnewini = fopen(precomf_ini,"w");
|
|
fprintf(fnewini,";; Precomp Comfort v%i.%i.%i %s %s - %s version - INI file\n",V_MAJOR,V_MINOR,V_MINOR2,V_OS,V_BIT,V_STATE);
|
|
fprintf(fnewini,";; Use a semicolon (;) for comments\n\n");
|
|
fprintf(fnewini,";; Compression method to use\n");
|
|
fprintf(fnewini,";; 0 = none, 1 = bZip2, 2 = lzma2 multi-threaded\n");
|
|
fprintf(fnewini,"Compression_Method=2\n");
|
|
fprintf(fnewini,";; Maximal memory (in MiB) for LZMA compression method\n");
|
|
fprintf(fnewini,"LZMA_Maximal_Memory=2048\n");
|
|
fprintf(fnewini,";; Thread count for LZMA compression method\n");
|
|
fprintf(fnewini,";; 0 = auto-detect\n");
|
|
fprintf(fnewini,"LZMA_Thread_Count=0\n");
|
|
fprintf(fnewini,";; Fast mode (on/off)\n");
|
|
fprintf(fnewini,"Fast_Mode=off\n\n");
|
|
fprintf(fnewini,";; Intense mode (on/off)\n");
|
|
fprintf(fnewini,"Intense_Mode=off\n\n");
|
|
fprintf(fnewini,";; Brute mode (on/off)\n");
|
|
fprintf(fnewini,"Brute_Mode=off\n\n");
|
|
fprintf(fnewini,";; Preserve Input's file extension (on/off)\n");
|
|
fprintf(fnewini,"Preserve_Extension=off\n\n");
|
|
fprintf(fnewini,";; Wrap BMP header around PDF images (on/off)\n");
|
|
fprintf(fnewini,"PDF_BMP_Mode=off\n\n");
|
|
fprintf(fnewini,";; Recompress progressive JPGs only (on/off)\n");
|
|
fprintf(fnewini,"JPG_progressive_only=off\n\n");
|
|
fprintf(fnewini,";; MJPEG recompression (on/off)\n");
|
|
fprintf(fnewini,"MJPEG_recompression=on\n\n");
|
|
fprintf(fnewini,";; Minimal identical byte size\n");
|
|
fprintf(fnewini,"Minimal_Size=4\n\n");
|
|
fprintf(fnewini,";; Verbose mode (on/off)\n");
|
|
fprintf(fnewini,"Verbose=off\n\n");
|
|
fprintf(fnewini,";; Compression types to use\n");
|
|
fprintf(fnewini,";; P = PDF, Z = ZIP, G = GZip, N = PNG, F = GIF, J = JPG, S = SWF\n");
|
|
fprintf(fnewini,";; M = MIME Base64, B = bZip2, 3 = MP3\n");
|
|
fprintf(fnewini,"; Compression_Types_Enable=PZGNFJSMB3\n");
|
|
fprintf(fnewini,"; Compression_Types_Disable=PZGNFJSMB3\n\n");
|
|
fprintf(fnewini,";; zLib levels to use\n");
|
|
fprintf(fnewini,"; zLib_Levels=\n");
|
|
fprintf(fnewini,";; Maximal recursion depth to use\n");
|
|
fprintf(fnewini,"Maximal_Recursion_Depth=10\n\n");
|
|
fprintf(fnewini,";; Use this to ignore streams at certain positions in the file\n");
|
|
fprintf(fnewini,";; Separate positions with commas (,) or use multiple Ignore_Positions\n");
|
|
fprintf(fnewini,"; Ignore_Positions=0\n");
|
|
safe_fclose(&fnewini);
|
|
min_ident_size = 4;
|
|
min_ident_size_set = true;
|
|
compression_otf_max_memory = 2048;
|
|
lzma_max_memory_set = true;
|
|
lzma_thread_count_set = true;
|
|
parse_ini_file = false;
|
|
}
|
|
}
|
|
|
|
if (parse_ini_file) {
|
|
// parse INI file
|
|
bool print_ignore_positions_message = true;
|
|
bool compression_type_line_used = false;
|
|
|
|
ifstream ini_file(precomf_ini);
|
|
string line;
|
|
string parName, valuestr;
|
|
string::iterator it;
|
|
char param[256], value[256];
|
|
|
|
while (getline(ini_file, line)) {
|
|
string::size_type semicolon_at_pos = line.find(";", 0);
|
|
if (semicolon_at_pos != string::npos) {
|
|
line.erase(semicolon_at_pos, line.length() - semicolon_at_pos);
|
|
}
|
|
|
|
// valid line must contain an equal sign (=)
|
|
string::size_type equal_at_pos = line.find("=", 0);
|
|
if (line.empty()) {
|
|
equal_at_pos = string::npos;
|
|
}
|
|
if (equal_at_pos != string::npos) {
|
|
|
|
stringstream ss;
|
|
ss << line;
|
|
// get parameter name
|
|
getline(ss, parName, '=');
|
|
// remove spaces
|
|
for (it = parName.begin(); it != parName.end(); it++) {
|
|
if (*it == ' ') {
|
|
parName.erase(it);
|
|
if (parName.empty()) break;
|
|
it = parName.begin();
|
|
} else {
|
|
*it = tolower(*it);
|
|
}
|
|
}
|
|
if (!parName.empty()) {
|
|
it = parName.begin();
|
|
if (*it == ' ') {
|
|
parName.erase(it);
|
|
} else {
|
|
*it = tolower(*it);
|
|
}
|
|
}
|
|
memset(param, '\0', 256);
|
|
parName.copy(param, 256);
|
|
|
|
// get value
|
|
getline(ss, valuestr);
|
|
// remove spaces
|
|
for (it = valuestr.begin(); it != valuestr.end(); it++) {
|
|
if (*it == ' ') {
|
|
valuestr.erase(it);
|
|
if (valuestr.empty()) break;
|
|
it = valuestr.begin();
|
|
} else {
|
|
*it = tolower(*it);
|
|
}
|
|
}
|
|
if (!valuestr.empty()) {
|
|
it = valuestr.begin();
|
|
if (*it == ' ') {
|
|
valuestr.erase(it);
|
|
} else {
|
|
*it = tolower(*it);
|
|
}
|
|
}
|
|
memset(value, '\0', 256);
|
|
valuestr.copy(value, 256);
|
|
|
|
if (strcmp(param, "") != 0) {
|
|
bool valid_param = false;
|
|
|
|
if (strcmp(param, "minimal_size") == 0) {
|
|
if (min_ident_size_set) {
|
|
error(ERR_ONLY_SET_MIN_SIZE_ONCE);
|
|
}
|
|
unsigned int ident_size = 0;
|
|
unsigned int multiplicator = 1;
|
|
for (j = (strlen(value)-1); j >= 0; j--) {
|
|
ident_size += ((unsigned int)(value[j])-'0') * multiplicator;
|
|
if ((multiplicator * 10) < multiplicator) {
|
|
error(ERR_IDENTICAL_BYTE_SIZE_TOO_BIG);
|
|
}
|
|
multiplicator *= 10;
|
|
}
|
|
min_ident_size = ident_size;
|
|
min_ident_size_set = true;
|
|
|
|
printf("INI: Set minimal identical byte size to %i\n", min_ident_size);
|
|
|
|
valid_param = true;
|
|
}
|
|
|
|
if (strcmp(param, "verbose") == 0) {
|
|
if (strcmp(value, "off") == 0) {
|
|
printf("INI: Disabled verbose mode\n");
|
|
valid_param = true;
|
|
}
|
|
|
|
if (strcmp(value, "on") == 0) {
|
|
printf("INI: Enabled verbose mode\n");
|
|
DEBUG_MODE = true;
|
|
valid_param = true;
|
|
}
|
|
|
|
if (!valid_param) {
|
|
printf("ERROR: Invalid verbose value: %s\n", value);
|
|
wait_for_key();
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (strcmp(param, "compression_method") == 0) {
|
|
if (strcmp(value, "0") == 0) {
|
|
printf("INI: Using no compression method\n");
|
|
compression_otf_method = OTF_NONE;
|
|
valid_param = true;
|
|
}
|
|
|
|
if (strcmp(value, "1") == 0) {
|
|
printf("INI: Using bZip2 compression method\n");
|
|
compression_otf_method = OTF_BZIP2;
|
|
valid_param = true;
|
|
}
|
|
|
|
if (strcmp(value, "2") == 0) {
|
|
printf("INI: Using lzma2 multithreaded compression method\n");
|
|
compression_otf_method = OTF_XZ_MT;
|
|
valid_param = true;
|
|
}
|
|
|
|
show_lzma_progress = (compression_otf_method == OTF_XZ_MT);
|
|
|
|
if (!valid_param) {
|
|
printf("ERROR: Invalid compression method value: %s\n", value);
|
|
wait_for_key();
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (strcmp(param, "lzma_maximal_memory") == 0) {
|
|
if (lzma_max_memory_set) {
|
|
error(ERR_ONLY_SET_LZMA_MEMORY_ONCE);
|
|
}
|
|
unsigned int multiplicator = 1;
|
|
for (j = (strlen(value)-1); j >= 0; j--) {
|
|
compression_otf_max_memory += ((unsigned int)(value[j])-'0') * multiplicator;
|
|
if ((multiplicator * 10) < multiplicator) {
|
|
exit(1);
|
|
}
|
|
multiplicator *= 10;
|
|
}
|
|
lzma_max_memory_set = true;
|
|
|
|
if (compression_otf_max_memory > 0) {
|
|
printf("INI: Set LZMA maximal memory to %i MiB\n", (int)compression_otf_max_memory);
|
|
}
|
|
|
|
valid_param = true;
|
|
}
|
|
|
|
if (strcmp(param, "lzma_thread_count") == 0) {
|
|
if (lzma_thread_count_set) {
|
|
error(ERR_ONLY_SET_LZMA_THREAD_ONCE);
|
|
}
|
|
unsigned int multiplicator = 1;
|
|
for (j = (strlen(value)-1); j >= 0; j--) {
|
|
compression_otf_thread_count += ((unsigned int)(value[j])-'0') * multiplicator;
|
|
if ((multiplicator * 10) < multiplicator) {
|
|
exit(1);
|
|
}
|
|
multiplicator *= 10;
|
|
}
|
|
lzma_thread_count_set = true;
|
|
|
|
if (compression_otf_thread_count > 0) {
|
|
printf("INI: Set LZMA thread count to %i\n", compression_otf_thread_count);
|
|
}
|
|
|
|
valid_param = true;
|
|
}
|
|
|
|
if (strcmp(param, "fast_mode") == 0) {
|
|
if (strcmp(value, "off") == 0) {
|
|
printf("INI: Disabled fast mode\n");
|
|
valid_param = true;
|
|
}
|
|
|
|
if (strcmp(value, "on") == 0) {
|
|
printf("INI: Enabled fast mode\n");
|
|
fast_mode = true;
|
|
valid_param = true;
|
|
}
|
|
|
|
if (!valid_param) {
|
|
printf("ERROR: Invalid fast mode value: %s\n", value);
|
|
wait_for_key();
|
|
exit(1);
|
|
}
|
|
}
|
|
// future note: params should be in lowercase for comparisons here only
|
|
if (strcmp(param,"preserve_extension") == 0) {
|
|
if (strcmp(value,"off") == 0) {
|
|
printf("INI: Not preserve extension\n");
|
|
preserve_extension = false;
|
|
} else if (strcmp(value,"on") == 0) {
|
|
printf("INI: Preserve extension\n");
|
|
preserve_extension = true;
|
|
} else {
|
|
printf("ERROR: Invalid Preserve extension mode: %s\n",value);
|
|
wait_for_key();
|
|
exit(1);
|
|
}
|
|
valid_param = true;
|
|
}
|
|
|
|
if (strcmp(param, "intense_mode") == 0) {
|
|
if (strcmp(value, "off") == 0) {
|
|
printf("INI: Disabled intense mode\n");
|
|
valid_param = true;
|
|
}
|
|
|
|
if (strcmp(value, "on") == 0) {
|
|
printf("INI: Enabled intense mode\n");
|
|
intense_mode = true;
|
|
valid_param = true;
|
|
}
|
|
|
|
if (!valid_param) {
|
|
printf("ERROR: Invalid intense mode value: %s\n", value);
|
|
wait_for_key();
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (strcmp(param, "brute_mode") == 0) {
|
|
if (strcmp(value, "off") == 0) {
|
|
printf("INI: Disabled brute mode\n");
|
|
valid_param = true;
|
|
}
|
|
|
|
if (strcmp(value, "on") == 0) {
|
|
printf("INI: Enabled brute mode\n");
|
|
brute_mode = true;
|
|
valid_param = true;
|
|
}
|
|
|
|
if (!valid_param) {
|
|
printf("ERROR: Invalid brute mode value: %s\n", value);
|
|
wait_for_key();
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (strcmp(param, "pdf_bmp_mode") == 0) {
|
|
if (strcmp(value, "off") == 0) {
|
|
printf("INI: Disabled PDF BMP mode\n");
|
|
pdf_bmp_mode = false;
|
|
valid_param = true;
|
|
}
|
|
|
|
if (strcmp(value, "on") == 0) {
|
|
printf("INI: Enabled PDF BMP mode\n");
|
|
pdf_bmp_mode = true;
|
|
valid_param = true;
|
|
}
|
|
|
|
if (!valid_param) {
|
|
printf("ERROR: Invalid PDF BMP mode value: %s\n", value);
|
|
wait_for_key();
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (strcmp(param, "jpg_progressive_only") == 0) {
|
|
if (strcmp(value, "off") == 0) {
|
|
printf("INI: Disabled progressive only JPG mode\n");
|
|
prog_only = false;
|
|
valid_param = true;
|
|
}
|
|
|
|
if (strcmp(value, "on") == 0) {
|
|
printf("INI: Enabled progressive only JPG mode\n");
|
|
prog_only = true;
|
|
valid_param = true;
|
|
}
|
|
|
|
if (!valid_param) {
|
|
printf("ERROR: Invalid progressive only JPG mode value: %s\n", value);
|
|
wait_for_key();
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (strcmp(param, "mjpeg_recompression") == 0) {
|
|
if (strcmp(value, "off") == 0) {
|
|
printf("INI: Disabled MJPEG recompression\n");
|
|
use_mjpeg = false;
|
|
valid_param = true;
|
|
}
|
|
|
|
if (strcmp(value, "on") == 0) {
|
|
printf("INI: Enabled MJPEG recompression\n");
|
|
use_mjpeg = true;
|
|
valid_param = true;
|
|
}
|
|
|
|
if (!valid_param) {
|
|
printf("ERROR: Invalid MJPEG recompression value: %s\n", value);
|
|
wait_for_key();
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (strcmp(param, "compression_types_enable") == 0) {
|
|
if (compression_type_line_used) {
|
|
printf("ERROR: Both Compression_types_enable and Compression_types_disable used.\n");
|
|
wait_for_key();
|
|
exit(1);
|
|
}
|
|
compression_type_line_used = true;
|
|
|
|
use_pdf = false;
|
|
use_zip = false;
|
|
use_gzip = false;
|
|
use_png = false;
|
|
use_gif = false;
|
|
use_jpg = false;
|
|
use_mp3 = false;
|
|
use_swf = false;
|
|
use_base64 = false;
|
|
use_bzip2 = false;
|
|
|
|
for (j = 0; j < (int)strlen(value); j++) {
|
|
switch (toupper(value[j])) {
|
|
case 'P': // PDF
|
|
use_pdf = true;
|
|
break;
|
|
case 'Z': // ZIP
|
|
use_zip = true;
|
|
break;
|
|
case 'G': // GZip
|
|
use_gzip = true;
|
|
break;
|
|
case 'N': // PNG
|
|
use_png = true;
|
|
break;
|
|
case 'F': // GIF
|
|
use_gif = true;
|
|
break;
|
|
case 'J': // JPG
|
|
use_jpg = true;
|
|
break;
|
|
case '3': // MP3
|
|
use_mp3 = true;
|
|
break;
|
|
case 'S': // SWF
|
|
use_swf = true;
|
|
break;
|
|
case 'M': // MIME Base64
|
|
use_base64 = true;
|
|
break;
|
|
case 'B': // bZip2
|
|
use_bzip2 = true;
|
|
break;
|
|
default:
|
|
printf("ERROR: Invalid compression type %c\n", value[j]);
|
|
exit(1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (use_pdf) {
|
|
printf("INI: PDF compression enabled\n");
|
|
} else {
|
|
printf("INI: PDF compression disabled\n");
|
|
}
|
|
|
|
if (use_zip) {
|
|
printf("INI: ZIP compression enabled\n");
|
|
} else {
|
|
printf("INI: ZIP compression disabled\n");
|
|
}
|
|
|
|
if (use_gzip) {
|
|
printf("INI: GZip compression enabled\n");
|
|
} else {
|
|
printf("INI: GZip compression disabled\n");
|
|
}
|
|
|
|
if (use_png) {
|
|
printf("INI: PNG compression enabled\n");
|
|
} else {
|
|
printf("INI: PNG compression disabled\n");
|
|
}
|
|
|
|
if (use_gif) {
|
|
printf("INI: GIF compression enabled\n");
|
|
} else {
|
|
printf("INI: GIF compression disabled\n");
|
|
}
|
|
|
|
if (use_jpg) {
|
|
printf("INI: JPG compression enabled\n");
|
|
} else {
|
|
printf("INI: JPG compression disabled\n");
|
|
}
|
|
|
|
if (use_mp3) {
|
|
printf("INI: MP3 compression enabled\n");
|
|
} else {
|
|
printf("INI: MP3 compression disabled\n");
|
|
}
|
|
|
|
if (use_swf) {
|
|
printf("INI: SWF compression enabled\n");
|
|
} else {
|
|
printf("INI: SWF compression disabled\n");
|
|
}
|
|
|
|
if (use_base64) {
|
|
printf("INI: Base64 compression enabled\n");
|
|
} else {
|
|
printf("INI: Base64 compression disabled\n");
|
|
}
|
|
|
|
if (use_bzip2) {
|
|
printf("INI: bZip2 compression enabled\n");
|
|
} else {
|
|
printf("INI: bZip2 compression disabled\n");
|
|
}
|
|
|
|
valid_param = true;
|
|
}
|
|
|
|
if (strcmp(param, "compression_types_disable") == 0) {
|
|
if (compression_type_line_used) {
|
|
printf("ERROR: Both Compression_types_enable and Compression_types_disable used.\n");
|
|
wait_for_key();
|
|
exit(1);
|
|
}
|
|
compression_type_line_used = true;
|
|
|
|
use_pdf = true;
|
|
use_zip = true;
|
|
use_gzip = true;
|
|
use_png = true;
|
|
use_gif = true;
|
|
use_jpg = true;
|
|
use_mp3 = true;
|
|
use_swf = true;
|
|
use_base64 = true;
|
|
use_bzip2 = true;
|
|
|
|
for (j = 0; j < (int)strlen(value); j++) {
|
|
switch (toupper(value[j])) {
|
|
case 'P': // PDF
|
|
use_pdf = false;
|
|
break;
|
|
case 'Z': // ZIP
|
|
use_zip = false;
|
|
break;
|
|
case 'G': // GZip
|
|
use_gzip = false;
|
|
break;
|
|
case 'N': // PNG
|
|
use_png = false;
|
|
break;
|
|
case 'F': // GIF
|
|
use_gif = false;
|
|
break;
|
|
case 'J': // JPG
|
|
use_jpg = false;
|
|
break;
|
|
case '3': // MP3
|
|
use_mp3 = false;
|
|
break;
|
|
case 'S': // SWF
|
|
use_swf = false;
|
|
break;
|
|
case 'M': // MIME Base64
|
|
use_base64 = false;
|
|
break;
|
|
case 'B': // bZip2
|
|
use_bzip2 = false;
|
|
break;
|
|
default:
|
|
printf("ERROR: Invalid compression type %c\n", value[j]);
|
|
exit(1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (use_pdf) {
|
|
printf("INI: PDF compression enabled\n");
|
|
} else {
|
|
printf("INI: PDF compression disabled\n");
|
|
}
|
|
|
|
if (use_zip) {
|
|
printf("INI: ZIP compression enabled\n");
|
|
} else {
|
|
printf("INI: ZIP compression disabled\n");
|
|
}
|
|
|
|
if (use_gzip) {
|
|
printf("INI: GZip compression enabled\n");
|
|
} else {
|
|
printf("INI: GZip compression disabled\n");
|
|
}
|
|
|
|
if (use_png) {
|
|
printf("INI: PNG compression enabled\n");
|
|
} else {
|
|
printf("INI: PNG compression disabled\n");
|
|
}
|
|
|
|
if (use_gif) {
|
|
printf("INI: GIF compression enabled\n");
|
|
} else {
|
|
printf("INI: GIF compression disabled\n");
|
|
}
|
|
|
|
if (use_jpg) {
|
|
printf("INI: JPG compression enabled\n");
|
|
} else {
|
|
printf("INI: JPG compression disabled\n");
|
|
}
|
|
|
|
if (use_mp3) {
|
|
printf("INI: MP3 compression enabled\n");
|
|
} else {
|
|
printf("INI: MP3 compression disabled\n");
|
|
}
|
|
|
|
if (use_swf) {
|
|
printf("INI: SWF compression enabled\n");
|
|
} else {
|
|
printf("INI: SWF compression disabled\n");
|
|
}
|
|
|
|
if (use_base64) {
|
|
printf("INI: Base64 compression enabled\n");
|
|
} else {
|
|
printf("INI: Base64 compression disabled\n");
|
|
}
|
|
|
|
if (use_bzip2) {
|
|
printf("INI: bZip2 compression enabled\n");
|
|
} else {
|
|
printf("INI: bZip2 compression disabled\n");
|
|
}
|
|
|
|
valid_param = true;
|
|
}
|
|
|
|
// zLib levels
|
|
if (strcmp(param, "zlib_levels") == 0) {
|
|
for (j = 0; j < 81; j++) {
|
|
use_zlib_level[j] = false;
|
|
}
|
|
|
|
level_switch = true;
|
|
|
|
for (j = 0; j < ((int)strlen(value)); j += 3) {
|
|
if ((j+2) < (int)strlen(value)) {
|
|
if (value[j+2] != ',') {
|
|
printf("ERROR: zLib levels have to be separated with commas\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
if ((j+1) >= (int)strlen(value)) {
|
|
printf("ERROR: Last zLib level is incomplete\n");
|
|
exit(1);
|
|
}
|
|
int comp_level_to_use = (char(value[j]) - '1');
|
|
int mem_level_to_use = (char(value[j+1]) - '1');
|
|
if ( ((comp_level_to_use >= 0) && (comp_level_to_use <= 8))
|
|
&& ((mem_level_to_use >= 0) && (mem_level_to_use <= 8))) {
|
|
use_zlib_level[comp_level_to_use + mem_level_to_use * 9] = true;
|
|
} else {
|
|
printf("ERROR: Invalid zlib level %c%c\n", value[j], value[j+1]);
|
|
wait_for_key();
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
printf("INI: Set zLib levels\n");
|
|
|
|
valid_param = true;
|
|
}
|
|
|
|
if (strcmp(param, "maximal_recursion_depth") == 0) {
|
|
if (recursion_depth_set) {
|
|
error(ERR_ONLY_SET_RECURSION_DEPTH_ONCE);
|
|
}
|
|
|
|
unsigned int max_recursion_d = 0;
|
|
unsigned int multiplicator = 1;
|
|
for (j = (strlen(value)-1); j >= 0; j--) {
|
|
max_recursion_d += ((unsigned int)(value[j])-'0') * multiplicator;
|
|
if ((multiplicator * 10) < multiplicator) {
|
|
error(ERR_RECURSION_DEPTH_TOO_BIG);
|
|
}
|
|
multiplicator *= 10;
|
|
}
|
|
max_recursion_depth = max_recursion_d;
|
|
recursion_depth_set = true;
|
|
|
|
printf("INI: Set maximal recursion depth to %i\n", max_recursion_depth);
|
|
|
|
valid_param = true;
|
|
}
|
|
|
|
if (strcmp(param, "ignore_positions") == 0) {
|
|
|
|
long long act_ignore_pos = -1;
|
|
|
|
for (j = 0; j < (int)strlen(value); j++) {
|
|
switch (value[j]) {
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
if (act_ignore_pos == -1) {
|
|
act_ignore_pos = (value[j] - '0');
|
|
} else {
|
|
if ((act_ignore_pos * 10) < act_ignore_pos) {
|
|
error(ERR_IGNORE_POS_TOO_BIG);
|
|
}
|
|
act_ignore_pos = (act_ignore_pos * 10) + (value[j] - '0');
|
|
}
|
|
break;
|
|
case ',':
|
|
if (act_ignore_pos != -1) {
|
|
ignore_list = (long long*)realloc(ignore_list, (ignore_list_len + 1) * sizeof(long long));
|
|
ignore_list[ignore_list_len] = act_ignore_pos;
|
|
ignore_list_len++;
|
|
act_ignore_pos = -1;
|
|
}
|
|
break;
|
|
case ' ':
|
|
break;
|
|
default:
|
|
printf("ERROR: Invalid char in ignore_positions: %c\n", value[j]);
|
|
wait_for_key();
|
|
exit(1);
|
|
}
|
|
}
|
|
if (act_ignore_pos != -1) {
|
|
ignore_list = (long long*)realloc(ignore_list, (ignore_list_len + 1) * sizeof(long long));
|
|
ignore_list[ignore_list_len] = act_ignore_pos;
|
|
ignore_list_len++;
|
|
}
|
|
|
|
if (print_ignore_positions_message) {
|
|
printf("INI: Set ignore positions\n");
|
|
print_ignore_positions_message = false;
|
|
}
|
|
|
|
valid_param = true;
|
|
}
|
|
|
|
if (!valid_param) {
|
|
printf("ERROR: Invalid INI parameter: %s\n", param);
|
|
wait_for_key();
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ini_file.close();
|
|
}
|
|
|
|
if (operation == P_COMPRESS) {
|
|
if(!preserve_extension) {
|
|
output_file_name = new char[strlen(input_file_name) + 9];
|
|
strcpy(output_file_name, input_file_name);
|
|
char* backslash_at_pos = strrchr(output_file_name, PATH_DELIM);
|
|
char* dot_at_pos = strrchr(output_file_name, '.');
|
|
if ((dot_at_pos == NULL) || ((backslash_at_pos != NULL) && (dot_at_pos < backslash_at_pos))) {
|
|
strcpy(output_file_name + strlen(input_file_name), ".pcf");
|
|
} else {
|
|
strcpy(dot_at_pos, ".pcf");
|
|
// same as output file because input file had .pcf extension?
|
|
if (strcmp(input_file_name, output_file_name) == 0) {
|
|
strcpy(dot_at_pos, "_pcf.pcf");
|
|
}
|
|
}
|
|
} else {
|
|
output_file_name = new char[strlen(input_file_name) + 9];
|
|
strcpy(output_file_name,input_file_name);
|
|
strcat(output_file_name,".pcf");
|
|
}
|
|
}
|
|
|
|
if (file_exists(output_file_name)) {
|
|
printf("Output file \"%s\" exists. Overwrite (y/n)? ", output_file_name);
|
|
char ch = getche();
|
|
if ((ch != 'Y') && (ch != 'y')) {
|
|
printf("\n");
|
|
wait_for_key();
|
|
exit(0);
|
|
} else {
|
|
printf("\n\n");
|
|
}
|
|
} else {
|
|
printf("\n");
|
|
}
|
|
fout = fopen(output_file_name,"wb");
|
|
if (fout == NULL) {
|
|
printf("ERROR: Can't create output file \"%s\"\n", output_file_name);
|
|
wait_for_key();
|
|
exit(1);
|
|
}
|
|
|
|
printf("Input file: %s\n",input_file_name);
|
|
printf("Output file: %s\n\n",output_file_name);
|
|
if (DEBUG_MODE) {
|
|
if (min_ident_size_set) {
|
|
printf("\n");
|
|
printf("Minimal ident size set to %i bytes\n", min_ident_size);
|
|
}
|
|
if (ignore_list_len > 0) {
|
|
printf("\n");
|
|
printf("Ignore position list:\n");
|
|
for (i = 0; i < ignore_list_len; i++) {
|
|
print64(ignore_list[i]);
|
|
printf("\n");
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
if (level_switch) {
|
|
|
|
for (i = 0; i < 81; i++) {
|
|
if (use_zlib_level[i]) {
|
|
comp_mem_level_count[i] = 0;
|
|
} else {
|
|
comp_mem_level_count[i] = -1;
|
|
}
|
|
}
|
|
|
|
level_switch_used = true;
|
|
|
|
}
|
|
|
|
sort_comp_mem_levels();
|
|
|
|
packjpg_mp3_dll_msg();
|
|
|
|
return operation;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
void denit_compress() {
|
|
|
|
if (compression_otf_method != OTF_NONE) {
|
|
denit_compress_otf();
|
|
}
|
|
|
|
safe_fclose(&fin);
|
|
safe_fclose(&fout);
|
|
|
|
if ((recursion_depth == 0) && (!DEBUG_MODE) && show_lzma_progress && (old_lzma_progress_text_length > -1)) {
|
|
printf("%s", string(old_lzma_progress_text_length, '\b').c_str()); // backspaces to remove old lzma progress text
|
|
}
|
|
|
|
#ifndef PRECOMPDLL
|
|
long long fout_length = fileSize64(output_file_name);
|
|
if (recursion_depth == 0) {
|
|
if (!DEBUG_MODE) {
|
|
printf(string(14,'\b').c_str());
|
|
printf("100.00%% - New size: ");
|
|
print64(fout_length);
|
|
printf(" instead of ");
|
|
print64(fin_length);
|
|
printf(" \n");
|
|
} else {
|
|
printf("New size: ");
|
|
print64(fout_length);
|
|
printf(" instead of ");
|
|
print64(fin_length);
|
|
printf(" \n");
|
|
}
|
|
}
|
|
#else
|
|
if (recursion_depth == 0) {
|
|
if (!DEBUG_MODE) {
|
|
printf(string(14,'\b').c_str());
|
|
printf("100.00%% - ");
|
|
printf_time(get_time_ms() - start_time);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifndef PRECOMPDLL
|
|
if (recursion_depth == 0) {
|
|
printf("\nDone.\n");
|
|
printf_time(get_time_ms() - start_time);
|
|
|
|
// statistics
|
|
printf("\nRecompressed streams: %i/%i\n", recompressed_streams_count, decompressed_streams_count);
|
|
|
|
if ((recompressed_streams_count > 0) || (decompressed_streams_count > 0)) {
|
|
if ((use_pdf) && ((recompressed_pdf_count > 0) || (decompressed_pdf_count > 0))) printf("PDF streams: %i/%i\n", recompressed_pdf_count, decompressed_pdf_count);
|
|
if (pdf_bmp_mode) {
|
|
if ((use_pdf) && ((recompressed_pdf_count_8_bit > 0) || (decompressed_pdf_count_8_bit > 0))) printf("PDF image streams (8-bit): %i/%i\n", recompressed_pdf_count_8_bit, decompressed_pdf_count_8_bit);
|
|
if ((use_pdf) && ((recompressed_pdf_count_24_bit > 0) || (decompressed_pdf_count_24_bit > 0))) printf("PDF image streams (24-bit): %i/%i\n", recompressed_pdf_count_24_bit, decompressed_pdf_count_24_bit);
|
|
}
|
|
if ((use_zip) && ((recompressed_zip_count > 0) || (decompressed_zip_count > 0))) printf("ZIP streams: %i/%i\n", recompressed_zip_count, decompressed_zip_count);
|
|
if ((use_gzip) && ((recompressed_gzip_count > 0) || (decompressed_gzip_count > 0))) printf("GZip streams: %i/%i\n", recompressed_gzip_count, decompressed_gzip_count);
|
|
if ((use_png) && ((recompressed_png_count > 0) || (decompressed_png_count > 0))) printf("PNG streams: %i/%i\n", recompressed_png_count, decompressed_png_count);
|
|
if ((use_png) && ((recompressed_png_multi_count > 0) || (decompressed_png_multi_count > 0))) printf("PNG streams (multi): %i/%i\n", recompressed_png_multi_count, decompressed_png_multi_count);
|
|
if ((use_gif) && ((recompressed_gif_count > 0) || (decompressed_gif_count > 0))) printf("GIF streams: %i/%i\n", recompressed_gif_count, decompressed_gif_count);
|
|
if ((use_jpg) && ((recompressed_jpg_count > 0) || (decompressed_jpg_count > 0))) printf("JPG streams: %i/%i\n", recompressed_jpg_count, decompressed_jpg_count);
|
|
if ((use_jpg) && ((recompressed_jpg_prog_count > 0) || (decompressed_jpg_prog_count > 0))) printf("JPG streams (progressive): %i/%i\n", recompressed_jpg_prog_count, decompressed_jpg_prog_count);
|
|
if ((use_mp3) && ((recompressed_mp3_count > 0) || (decompressed_mp3_count > 0))) printf("MP3 streams: %i/%i\n", recompressed_mp3_count, decompressed_mp3_count);
|
|
if ((use_swf) && ((recompressed_swf_count > 0) || (decompressed_swf_count > 0))) printf("SWF streams: %i/%i\n", recompressed_swf_count, decompressed_swf_count);
|
|
if ((use_base64) && ((recompressed_base64_count > 0) || (decompressed_base64_count > 0))) printf("Base64 streams: %i/%i\n", recompressed_base64_count, decompressed_base64_count);
|
|
if ((use_bzip2) && ((recompressed_bzip2_count > 0) || (decompressed_bzip2_count > 0))) printf("bZip2 streams: %i/%i\n", recompressed_bzip2_count, decompressed_bzip2_count);
|
|
if ((intense_mode) && ((recompressed_zlib_count > 0) || (decompressed_zlib_count > 0))) printf("zLib streams (intense mode): %i/%i\n", recompressed_zlib_count, decompressed_zlib_count);
|
|
if ((brute_mode) && ((recompressed_brute_count > 0) || (decompressed_brute_count > 0))) printf("Brute mode streams: %i/%i\n", recompressed_brute_count, decompressed_brute_count);
|
|
}
|
|
|
|
if (!level_switch_used) show_used_levels();
|
|
|
|
}
|
|
#endif
|
|
|
|
remove(metatempfile);
|
|
remove(tempfile0);
|
|
remove(tempfile1);
|
|
remove(tempfile2);
|
|
remove(tempfile3);
|
|
|
|
tempfilelist_count -= 8;
|
|
tempfilelist = (char*)realloc(tempfilelist, 20 * tempfilelist_count * sizeof(char));
|
|
|
|
if (recursion_depth == 0) {
|
|
free(ignore_list);
|
|
}
|
|
|
|
denit();
|
|
}
|
|
|
|
void denit_decompress() {
|
|
#ifndef PRECOMPDLL
|
|
if (recursion_depth == 0) {
|
|
if (!DEBUG_MODE) {
|
|
printf(string(14,'\b').c_str());
|
|
printf("100.00%%\n");
|
|
}
|
|
printf("\nDone.\n");
|
|
printf_time(get_time_ms() - start_time);
|
|
}
|
|
#else
|
|
if (recursion_depth == 0) {
|
|
if (!DEBUG_MODE) {
|
|
printf(string(14,'\b').c_str());
|
|
printf("100.00%% - ");
|
|
printf_time(get_time_ms() - start_time);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (compression_otf_method != OTF_NONE) {
|
|
denit_decompress_otf();
|
|
}
|
|
|
|
remove(metatempfile);
|
|
remove(tempfile0);
|
|
remove(tempfile1);
|
|
remove(tempfile2);
|
|
remove(tempfile3);
|
|
|
|
tempfilelist_count -= 8;
|
|
tempfilelist = (char*)realloc(tempfilelist, 20 * tempfilelist_count * sizeof(char));
|
|
|
|
denit();
|
|
}
|
|
|
|
void denit_convert() {
|
|
safe_fclose(&fin);
|
|
safe_fclose(&fout);
|
|
|
|
if ((!DEBUG_MODE) && show_lzma_progress && (conversion_to_method == OTF_XZ_MT) && (old_lzma_progress_text_length > -1)) {
|
|
printf("%s", string(old_lzma_progress_text_length, '\b').c_str()); // backspaces to remove old lzma progress text
|
|
}
|
|
|
|
long long fout_length = fileSize64(output_file_name);
|
|
#ifndef PRECOMPDLL
|
|
if (!DEBUG_MODE) {
|
|
printf(string(14,'\b').c_str());
|
|
printf("100.00%% - New size: ");
|
|
print64(fout_length);
|
|
printf(" instead of ");
|
|
print64(fin_length);
|
|
printf(" \n");
|
|
} else {
|
|
printf("New size: ");
|
|
print64(fout_length);
|
|
printf(" instead of ");
|
|
print64(fin_length);
|
|
printf(" \n");
|
|
}
|
|
printf("\nDone.\n");
|
|
printf_time(get_time_ms() - start_time);
|
|
#else
|
|
if (!DEBUG_MODE) {
|
|
printf(string(14,'\b').c_str());
|
|
printf("100.00%% - New size: ");
|
|
print64(fout_length);
|
|
printf(" instead of ");
|
|
print64(fin_length);
|
|
printf(" \n");
|
|
printf_time(get_time_ms() - start_time);
|
|
}
|
|
#endif
|
|
|
|
denit();
|
|
}
|
|
|
|
void denit() {
|
|
safe_fclose(&fin);
|
|
safe_fclose(&fout);
|
|
|
|
if (output_file_name != NULL) delete[] output_file_name;
|
|
delete[] penalty_bytes;
|
|
delete[] local_penalty_bytes;
|
|
delete[] best_penalty_bytes;
|
|
}
|
|
|
|
int def(FILE *source, FILE *dest, int level, int windowbits, int memlevel) {
|
|
int ret, flush;
|
|
unsigned have;
|
|
z_stream strm;
|
|
|
|
/* allocate deflate state */
|
|
strm.zalloc = Z_NULL;
|
|
strm.zfree = Z_NULL;
|
|
strm.opaque = Z_NULL;
|
|
ret = deflateInit2(&strm, level, Z_DEFLATED, windowbits, memlevel, Z_DEFAULT_STRATEGY);
|
|
if (ret != Z_OK)
|
|
return ret;
|
|
|
|
/* compress until end of file */
|
|
do {
|
|
print_work_sign(true);
|
|
|
|
strm.avail_in = own_fread(in, 1, CHUNK, source);
|
|
if (ferror(source)) {
|
|
(void)deflateEnd(&strm);
|
|
return Z_ERRNO;
|
|
}
|
|
flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
|
|
strm.next_in = in;
|
|
|
|
do {
|
|
strm.avail_out = CHUNK;
|
|
strm.next_out = out;
|
|
|
|
ret = deflate(&strm, flush);
|
|
|
|
have = CHUNK - strm.avail_out;
|
|
|
|
if (own_fwrite(out, 1, have, dest) != have || ferror(dest)) {
|
|
(void)deflateEnd(&strm);
|
|
return Z_ERRNO;
|
|
}
|
|
} while (strm.avail_out == 0);
|
|
|
|
} while (flush != Z_FINISH);
|
|
|
|
(void)deflateEnd(&strm);
|
|
return Z_OK;
|
|
}
|
|
|
|
// Brute mode detects everything that intense mode detects, so it makes no sense
|
|
// having both active. But since both of them can have a level limit, two helper
|
|
// functions make things easier to handle.
|
|
|
|
bool intense_mode_is_active() {
|
|
if ((!intense_mode) || (brute_mode_is_active())) return false;
|
|
if ((intense_mode_depth_limit == -1) || (recursion_depth <= intense_mode_depth_limit)) return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool brute_mode_is_active() {
|
|
if (!brute_mode) return false;
|
|
if ((brute_mode_depth_limit == -1) || (recursion_depth <= brute_mode_depth_limit)) return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
void copy_penalty_bytes(long long& rek_penalty_bytes_len, bool& use_penalty_bytes) {
|
|
if ((rek_penalty_bytes_len > 0) && (use_penalty_bytes)) {
|
|
memcpy(penalty_bytes, local_penalty_bytes, rek_penalty_bytes_len);
|
|
penalty_bytes_len = rek_penalty_bytes_len;
|
|
} else {
|
|
penalty_bytes_len = 0;
|
|
}
|
|
}
|
|
|
|
#define DEF_COMPARE_CHUNK 512
|
|
int def_compare(FILE *source, FILE *compfile, int level, int windowbits, int memlevel, int& decompressed_bytes_used) {
|
|
|
|
int ret, flush;
|
|
unsigned have;
|
|
z_stream strm;
|
|
long long identical_bytes_compare = 0;
|
|
|
|
int comp_pos = 0;
|
|
decompressed_bytes_used = 0;
|
|
|
|
/* allocate deflate state */
|
|
strm.zalloc = Z_NULL;
|
|
strm.zfree = Z_NULL;
|
|
strm.opaque = Z_NULL;
|
|
ret = deflateInit2(&strm, level, Z_DEFLATED, windowbits, memlevel, Z_DEFAULT_STRATEGY);
|
|
if (ret != Z_OK)
|
|
return -1;
|
|
|
|
long long total_same_byte_count = 0;
|
|
long long total_same_byte_count_penalty = 0;
|
|
long long rek_same_byte_count = 0;
|
|
long long rek_same_byte_count_penalty = -1;
|
|
long long rek_penalty_bytes_len = 0;
|
|
long long local_penalty_bytes_len = 0;
|
|
bool use_penalty_bytes = false;
|
|
|
|
/* compress until end of file */
|
|
do {
|
|
print_work_sign(true);
|
|
|
|
strm.avail_in = own_fread(in, 1, DEF_COMPARE_CHUNK, source);
|
|
if (ferror(source)) {
|
|
(void)deflateEnd(&strm);
|
|
return -1;
|
|
}
|
|
flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
|
|
strm.next_in = in;
|
|
decompressed_bytes_used += strm.avail_in;
|
|
|
|
do {
|
|
strm.avail_out = DEF_COMPARE_CHUNK;
|
|
strm.next_out = out;
|
|
|
|
ret = deflate(&strm, flush);
|
|
|
|
have = DEF_COMPARE_CHUNK - strm.avail_out;
|
|
|
|
if (have > 0) {
|
|
if (compfile == fin) {
|
|
identical_bytes_compare = compare_file_mem_penalty(compfile, out, input_file_pos + comp_pos, have, total_same_byte_count, total_same_byte_count_penalty, rek_same_byte_count, rek_same_byte_count_penalty, rek_penalty_bytes_len, local_penalty_bytes_len, use_penalty_bytes);
|
|
} else {
|
|
identical_bytes_compare = compare_file_mem_penalty(compfile, out, comp_pos, have, total_same_byte_count, total_same_byte_count_penalty, rek_same_byte_count, rek_same_byte_count_penalty, rek_penalty_bytes_len, local_penalty_bytes_len, use_penalty_bytes);
|
|
}
|
|
}
|
|
|
|
if (have > 0) {
|
|
if ((unsigned int)identical_bytes_compare < (have >> 1)) {
|
|
(void)deflateEnd(&strm);
|
|
copy_penalty_bytes(rek_penalty_bytes_len, use_penalty_bytes);
|
|
return rek_same_byte_count;
|
|
}
|
|
}
|
|
|
|
comp_pos += have;
|
|
|
|
} while (strm.avail_out == 0);
|
|
|
|
} while (flush != Z_FINISH);
|
|
|
|
(void)deflateEnd(&strm);
|
|
copy_penalty_bytes(rek_penalty_bytes_len, use_penalty_bytes);
|
|
return rek_same_byte_count;
|
|
}
|
|
|
|
int def_compare_bzip2(FILE *source, FILE *compfile, int level, int& decompressed_bytes_used) {
|
|
int ret, flush;
|
|
unsigned have;
|
|
bz_stream strm;
|
|
long long identical_bytes_compare = 0;
|
|
|
|
int comp_pos = 0;
|
|
decompressed_bytes_used = 0;
|
|
|
|
/* allocate deflate state */
|
|
strm.bzalloc = NULL;
|
|
strm.bzfree = NULL;
|
|
strm.opaque = NULL;
|
|
ret = BZ2_bzCompressInit(&strm, level, 0, 0);
|
|
if (ret != BZ_OK)
|
|
return ret;
|
|
|
|
long long total_same_byte_count = 0;
|
|
long long total_same_byte_count_penalty = 0;
|
|
long long rek_same_byte_count = 0;
|
|
long long rek_same_byte_count_penalty = -1;
|
|
long long rek_penalty_bytes_len = 0;
|
|
long long local_penalty_bytes_len = 0;
|
|
bool use_penalty_bytes = false;
|
|
|
|
/* compress until end of file */
|
|
do {
|
|
print_work_sign(true);
|
|
|
|
strm.avail_in = own_fread(in, 1, DEF_COMPARE_CHUNK, source);
|
|
if (ferror(source)) {
|
|
(void)BZ2_bzCompressEnd(&strm);
|
|
return BZ_PARAM_ERROR;
|
|
}
|
|
flush = feof(source) ? BZ_FINISH : BZ_RUN;
|
|
strm.next_in = (char*)in;
|
|
decompressed_bytes_used += strm.avail_in;
|
|
|
|
do {
|
|
strm.avail_out = DEF_COMPARE_CHUNK;
|
|
strm.next_out = (char*)out;
|
|
|
|
ret = BZ2_bzCompress(&strm, flush);
|
|
|
|
have = DEF_COMPARE_CHUNK - strm.avail_out;
|
|
|
|
if (have > 0) {
|
|
if (compfile == fin) {
|
|
identical_bytes_compare = compare_file_mem_penalty(compfile, out, input_file_pos + comp_pos, have, total_same_byte_count, total_same_byte_count_penalty, rek_same_byte_count, rek_same_byte_count_penalty, rek_penalty_bytes_len, local_penalty_bytes_len, use_penalty_bytes);
|
|
} else {
|
|
identical_bytes_compare = compare_file_mem_penalty(compfile, out, comp_pos, have, total_same_byte_count, total_same_byte_count_penalty, rek_same_byte_count, rek_same_byte_count_penalty, rek_penalty_bytes_len, local_penalty_bytes_len, use_penalty_bytes);
|
|
}
|
|
}
|
|
|
|
if (have > 0) {
|
|
if ((unsigned int)identical_bytes_compare < (have >> 1)) {
|
|
(void)BZ2_bzCompressEnd(&strm);
|
|
copy_penalty_bytes(rek_penalty_bytes_len, use_penalty_bytes);
|
|
return rek_same_byte_count;
|
|
}
|
|
}
|
|
|
|
comp_pos += have;
|
|
|
|
} while (strm.avail_out == 0);
|
|
|
|
} while (flush != BZ_FINISH);
|
|
|
|
(void)BZ2_bzCompressEnd(&strm);
|
|
copy_penalty_bytes(rek_penalty_bytes_len, use_penalty_bytes);
|
|
return rek_same_byte_count;
|
|
}
|
|
|
|
int def_part(FILE *source, FILE *dest, int level, int windowbits, int memlevel, int stream_size_in, int stream_size_out) {
|
|
int ret, flush;
|
|
unsigned have;
|
|
z_stream strm;
|
|
|
|
/* allocate deflate state */
|
|
strm.zalloc = Z_NULL;
|
|
strm.zfree = Z_NULL;
|
|
strm.opaque = Z_NULL;
|
|
ret = deflateInit2(&strm, level, Z_DEFLATED, windowbits, memlevel, Z_DEFAULT_STRATEGY);
|
|
if (ret != Z_OK)
|
|
return ret;
|
|
|
|
int pos_in = 0;
|
|
int pos_out = 0;
|
|
|
|
/* compress until end of file */
|
|
do {
|
|
if ((stream_size_in - pos_in) > CHUNK) {
|
|
print_work_sign(true);
|
|
|
|
strm.avail_in = own_fread(in, 1, CHUNK, source);
|
|
pos_in += CHUNK;
|
|
flush = Z_NO_FLUSH;
|
|
} else {
|
|
strm.avail_in = own_fread(in, 1, stream_size_in - pos_in, source);
|
|
flush = Z_FINISH;
|
|
}
|
|
if (ferror(source)) {
|
|
(void)deflateEnd(&strm);
|
|
return Z_ERRNO;
|
|
}
|
|
strm.next_in = in;
|
|
|
|
do {
|
|
strm.avail_out = CHUNK;
|
|
strm.next_out = out;
|
|
|
|
ret = deflate(&strm, flush);
|
|
|
|
have = CHUNK - strm.avail_out;
|
|
|
|
if ((pos_out + (signed)have) > stream_size_out) {
|
|
have = stream_size_out - pos_out;
|
|
}
|
|
pos_out += have;
|
|
|
|
if (own_fwrite(out, 1, have, dest) != have || ferror(dest)) {
|
|
(void)deflateEnd(&strm);
|
|
return Z_ERRNO;
|
|
}
|
|
} while (strm.avail_out == 0);
|
|
|
|
} while (flush != Z_FINISH);
|
|
|
|
(void)deflateEnd(&strm);
|
|
return Z_OK;
|
|
}
|
|
|
|
int def_part_bzip2(FILE *source, FILE *dest, int level, int stream_size_in, int stream_size_out) {
|
|
int ret, flush;
|
|
unsigned have;
|
|
bz_stream strm;
|
|
|
|
/* allocate deflate state */
|
|
strm.bzalloc = NULL;
|
|
strm.bzfree = NULL;
|
|
strm.opaque = NULL;
|
|
ret = BZ2_bzCompressInit(&strm, level, 0, 0);
|
|
if (ret != BZ_OK)
|
|
return ret;
|
|
|
|
int pos_in = 0;
|
|
int pos_out = 0;
|
|
|
|
/* compress until end of file */
|
|
do {
|
|
if ((stream_size_in - pos_in) > CHUNK) {
|
|
print_work_sign(true);
|
|
|
|
strm.avail_in = own_fread(in, 1, CHUNK, source);
|
|
pos_in += CHUNK;
|
|
flush = BZ_RUN;
|
|
} else {
|
|
strm.avail_in = own_fread(in, 1, stream_size_in - pos_in, source);
|
|
flush = BZ_FINISH;
|
|
}
|
|
if (ferror(source)) {
|
|
(void)BZ2_bzCompressEnd(&strm);
|
|
return BZ_PARAM_ERROR;
|
|
}
|
|
strm.next_in = (char*)in;
|
|
|
|
do {
|
|
strm.avail_out = CHUNK;
|
|
strm.next_out = (char*)out;
|
|
|
|
ret = BZ2_bzCompress(&strm, flush);
|
|
|
|
have = CHUNK - strm.avail_out;
|
|
|
|
if ((pos_out + (signed)have) > stream_size_out) {
|
|
have = stream_size_out - pos_out;
|
|
}
|
|
pos_out += have;
|
|
|
|
if (own_fwrite(out, 1, have, dest) != have || ferror(dest)) {
|
|
(void)BZ2_bzCompressEnd(&strm);
|
|
return BZ_DATA_ERROR;
|
|
}
|
|
} while (strm.avail_out == 0);
|
|
|
|
} while (flush != BZ_FINISH);
|
|
|
|
(void)BZ2_bzCompressEnd(&strm);
|
|
return BZ_OK;
|
|
}
|
|
|
|
// fread_skip variables, shared with def_part_skip
|
|
unsigned int frs_offset;
|
|
unsigned int frs_line_len;
|
|
unsigned int frs_skip_len;
|
|
unsigned char frs_skipbuf[4];
|
|
|
|
size_t fread_skip(unsigned char *ptr, size_t size, size_t count, FILE* stream) {
|
|
size_t bytes_read = 0;
|
|
unsigned int read_tmp;
|
|
|
|
do {
|
|
if ((count - bytes_read) >= (frs_line_len - frs_offset)) {
|
|
if ((frs_line_len - frs_offset) > 0) {
|
|
read_tmp = own_fread(ptr + bytes_read, size, frs_line_len - frs_offset, stream);
|
|
if (read_tmp == 0) return bytes_read;
|
|
bytes_read += read_tmp;
|
|
}
|
|
// skip padding bytes
|
|
read_tmp = own_fread(frs_skipbuf, size, frs_skip_len, stream);
|
|
if (read_tmp == 0) return bytes_read;
|
|
frs_offset = 0;
|
|
} else {
|
|
read_tmp = own_fread(ptr + bytes_read, size, count - bytes_read, stream);
|
|
if (read_tmp == 0) return bytes_read;
|
|
bytes_read += read_tmp;
|
|
frs_offset += read_tmp;
|
|
}
|
|
} while (bytes_read < count);
|
|
|
|
return bytes_read;
|
|
}
|
|
|
|
int def_part_skip(FILE *source, FILE *dest, int level, int windowbits, int memlevel, int stream_size_in, int stream_size_out, int bmp_width) {
|
|
|
|
int ret, flush;
|
|
unsigned have;
|
|
z_stream strm;
|
|
|
|
/* allocate deflate state */
|
|
strm.zalloc = Z_NULL;
|
|
strm.zfree = Z_NULL;
|
|
strm.opaque = Z_NULL;
|
|
ret = deflateInit2(&strm, level, Z_DEFLATED, windowbits, memlevel, Z_DEFAULT_STRATEGY);
|
|
if (ret != Z_OK)
|
|
return ret;
|
|
|
|
int pos_in = 0;
|
|
int pos_out = 0;
|
|
frs_offset = 0;
|
|
frs_skip_len = (4 - (bmp_width % 4));
|
|
frs_line_len = bmp_width;
|
|
|
|
/* compress until end of file */
|
|
do {
|
|
if ((stream_size_in - pos_in) >= CHUNK) {
|
|
strm.avail_in = fread_skip(in, 1, CHUNK, source);
|
|
pos_in += strm.avail_in;
|
|
flush = Z_NO_FLUSH;
|
|
} else {
|
|
strm.avail_in = fread_skip(in, 1, stream_size_in - pos_in, source);
|
|
pos_in += strm.avail_in;
|
|
if (pos_in >= stream_size_in) {
|
|
flush = Z_FINISH;
|
|
} else {
|
|
flush = Z_NO_FLUSH;
|
|
}
|
|
}
|
|
if (ferror(source)) {
|
|
(void)deflateEnd(&strm);
|
|
return Z_ERRNO;
|
|
}
|
|
strm.next_in = in;
|
|
|
|
do {
|
|
strm.avail_out = CHUNK;
|
|
strm.next_out = out;
|
|
|
|
ret = deflate(&strm, flush);
|
|
|
|
have = CHUNK - strm.avail_out;
|
|
|
|
if ((pos_out + (signed)have) > stream_size_out) {
|
|
have = stream_size_out - pos_out;
|
|
}
|
|
pos_out += have;
|
|
|
|
if (own_fwrite(out, 1, have, dest) != have || ferror(dest)) {
|
|
(void)deflateEnd(&strm);
|
|
return Z_ERRNO;
|
|
}
|
|
} while (strm.avail_out == 0);
|
|
|
|
} while (flush != Z_FINISH);
|
|
|
|
(void)deflateEnd(&strm);
|
|
return Z_OK;
|
|
}
|
|
|
|
int inf(FILE *source, FILE *dest, int windowbits, int& compressed_stream_size) {
|
|
int ret;
|
|
unsigned have;
|
|
z_stream strm;
|
|
|
|
/* allocate inflate state */
|
|
strm.zalloc = Z_NULL;
|
|
strm.zfree = Z_NULL;
|
|
strm.opaque = Z_NULL;
|
|
strm.avail_in = 0;
|
|
strm.next_in = Z_NULL;
|
|
ret = inflateInit2(&strm, windowbits);
|
|
if (ret != Z_OK)
|
|
return ret;
|
|
|
|
compressed_stream_size = 0;
|
|
int avail_in_before;
|
|
|
|
/* decompress until deflate stream ends or end of file */
|
|
do {
|
|
print_work_sign(true);
|
|
|
|
strm.avail_in = own_fread(in, 1, CHUNK, source);
|
|
avail_in_before = strm.avail_in;
|
|
|
|
if (ferror(source)) {
|
|
(void)inflateEnd(&strm);
|
|
return Z_ERRNO;
|
|
}
|
|
if (strm.avail_in == 0)
|
|
break;
|
|
strm.next_in = in;
|
|
|
|
/* run inflate() on input until output buffer not full */
|
|
do {
|
|
strm.avail_out = CHUNK;
|
|
strm.next_out = out;
|
|
|
|
ret = inflate(&strm, Z_NO_FLUSH);
|
|
switch (ret) {
|
|
case Z_NEED_DICT:
|
|
ret = Z_DATA_ERROR;
|
|
case Z_DATA_ERROR:
|
|
case Z_MEM_ERROR:
|
|
(void)inflateEnd(&strm);
|
|
return ret;
|
|
}
|
|
|
|
compressed_stream_size += (avail_in_before - strm.avail_in);
|
|
avail_in_before = strm.avail_in;
|
|
|
|
have = CHUNK - strm.avail_out;
|
|
if (own_fwrite(out, 1, have, dest) != have || ferror(dest)) {
|
|
(void)inflateEnd(&strm);
|
|
return Z_ERRNO;
|
|
}
|
|
|
|
} while (strm.avail_out == 0);
|
|
|
|
/* done when inflate() says it's done */
|
|
} while (ret != Z_STREAM_END);
|
|
|
|
/* clean up and return */
|
|
(void)inflateEnd(&strm);
|
|
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
|
|
|
|
}
|
|
|
|
bool check_inf_result(int cb_pos, int windowbits, bool use_brute_parameters = false) {
|
|
// first check BTYPE bits, skip 11 ("reserved (error)")
|
|
int btype = (in_buf[cb_pos] & 0x07) >> 1;
|
|
if (btype == 3) return false;
|
|
// skip BTYPE = 00 ("uncompressed") only in brute mode, because these can be useful for recursion
|
|
// and often occur in combination with static/dynamic BTYPE blocks
|
|
if ((use_brute_parameters) && (btype == 0)) return false;
|
|
|
|
int ret;
|
|
unsigned have = 0;
|
|
z_stream strm;
|
|
|
|
/* allocate inflate state */
|
|
strm.zalloc = Z_NULL;
|
|
strm.zfree = Z_NULL;
|
|
strm.opaque = Z_NULL;
|
|
strm.avail_in = 0;
|
|
strm.next_in = Z_NULL;
|
|
ret = inflateInit2(&strm, windowbits);
|
|
if (ret != Z_OK)
|
|
return false;
|
|
|
|
print_work_sign(true);
|
|
|
|
strm.avail_in = 2048;
|
|
strm.next_in = in_buf + cb_pos;
|
|
|
|
/* run inflate() on input until output buffer not full */
|
|
do {
|
|
strm.avail_out = CHUNK;
|
|
strm.next_out = out;
|
|
|
|
ret = inflate(&strm, Z_NO_FLUSH);
|
|
switch (ret) {
|
|
case Z_NEED_DICT:
|
|
ret = Z_DATA_ERROR;
|
|
case Z_DATA_ERROR:
|
|
case Z_MEM_ERROR:
|
|
(void)inflateEnd(&strm);
|
|
return false;
|
|
}
|
|
|
|
have += CHUNK - strm.avail_out;
|
|
} while (strm.avail_out == 0);
|
|
|
|
|
|
/* clean up and return */
|
|
(void)inflateEnd(&strm);
|
|
switch (ret) {
|
|
case Z_OK:
|
|
return true;
|
|
case Z_STREAM_END:
|
|
// Skip short streams - most likely false positives
|
|
unsigned less_than_skip = 32;
|
|
if (use_brute_parameters) less_than_skip = 1024;
|
|
return (have >= less_than_skip);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/* report a zlib or i/o error */
|
|
void zerr(int ret)
|
|
{
|
|
fputs("ERROR: ", stdout);
|
|
switch (ret) {
|
|
case Z_ERRNO:
|
|
if (ferror(stdin))
|
|
fputs("error reading stdin\n", stdout);
|
|
if (ferror(stdout))
|
|
fputs("error writing stdout\n", stdout);
|
|
printf("errno: %i\n", errno);
|
|
break;
|
|
case Z_STREAM_ERROR:
|
|
fputs("invalid compression level\n", stdout);
|
|
break;
|
|
case Z_DATA_ERROR:
|
|
fputs("invalid or incomplete deflate data\n", stdout);
|
|
break;
|
|
case Z_MEM_ERROR:
|
|
fputs("out of memory\n", stdout);
|
|
break;
|
|
case Z_VERSION_ERROR:
|
|
fputs("zlib version mismatch!\n", stdout);
|
|
}
|
|
}
|
|
|
|
int inf_bzip2(FILE *source, FILE *dest) {
|
|
int ret;
|
|
unsigned have;
|
|
bz_stream strm;
|
|
|
|
strm.bzalloc = NULL;
|
|
strm.bzfree = NULL;
|
|
strm.opaque = NULL;
|
|
strm.avail_in = 0;
|
|
strm.next_in = NULL;
|
|
ret = BZ2_bzDecompressInit(&strm, 0, 0);
|
|
if (ret != BZ_OK)
|
|
return ret;
|
|
|
|
do {
|
|
print_work_sign(true);
|
|
|
|
strm.avail_in = own_fread(in, 1, CHUNK, source);
|
|
|
|
if (ferror(source)) {
|
|
(void)BZ2_bzDecompressEnd(&strm);
|
|
return BZ_PARAM_ERROR;
|
|
}
|
|
if (strm.avail_in == 0)
|
|
break;
|
|
strm.next_in = (char*)in;
|
|
|
|
do {
|
|
strm.avail_out = CHUNK;
|
|
strm.next_out = (char*)out;
|
|
|
|
ret = BZ2_bzDecompress(&strm);
|
|
if ((ret != BZ_OK) && (ret != BZ_STREAM_END)) {
|
|
(void)BZ2_bzDecompressEnd(&strm);
|
|
return ret;
|
|
}
|
|
|
|
have = CHUNK - strm.avail_out;
|
|
if (own_fwrite(out, 1, have, dest) != have || ferror(dest)) {
|
|
(void)BZ2_bzDecompressEnd(&strm);
|
|
return BZ_DATA_ERROR;
|
|
}
|
|
|
|
} while (strm.avail_out == 0);
|
|
|
|
/* done when inflate() says it's done */
|
|
} while (ret != BZ_STREAM_END);
|
|
|
|
/* clean up and return */
|
|
|
|
(void)BZ2_bzDecompressEnd(&strm);
|
|
return ret == BZ_STREAM_END ? BZ_OK : BZ_DATA_ERROR;
|
|
|
|
}
|
|
|
|
|
|
int def_bzip2(FILE *source, FILE *dest, int level) {
|
|
int ret, flush;
|
|
unsigned have;
|
|
bz_stream strm;
|
|
|
|
/* allocate deflate state */
|
|
strm.bzalloc = NULL;
|
|
strm.bzfree = NULL;
|
|
strm.opaque = NULL;
|
|
ret = BZ2_bzCompressInit(&strm, level, 0, 0);
|
|
if (ret != BZ_OK)
|
|
return ret;
|
|
|
|
/* compress until end of file */
|
|
do {
|
|
print_work_sign(true);
|
|
|
|
strm.avail_in = own_fread(in, 1, CHUNK, source);
|
|
if (ferror(source)) {
|
|
(void)BZ2_bzCompressEnd(&strm);
|
|
return BZ_PARAM_ERROR;
|
|
}
|
|
flush = feof(source) ? BZ_FINISH : BZ_RUN;
|
|
strm.next_in = (char*)in;
|
|
|
|
do {
|
|
strm.avail_out = CHUNK;
|
|
strm.next_out = (char*)out;
|
|
|
|
ret = BZ2_bzCompress(&strm, flush);
|
|
|
|
have = CHUNK - strm.avail_out;
|
|
|
|
if (own_fwrite(out, 1, have, dest) != have || ferror(dest)) {
|
|
(void)BZ2_bzCompressEnd(&strm);
|
|
return BZ_DATA_ERROR;
|
|
}
|
|
} while (strm.avail_out == 0);
|
|
|
|
} while (flush != BZ_FINISH);
|
|
|
|
(void)BZ2_bzCompressEnd(&strm);
|
|
return BZ_OK;
|
|
}
|
|
|
|
int file_recompress(FILE* origfile, int compression_level, int windowbits, int memlevel, int& decompressed_bytes_used, int& decompressed_bytes_total) {
|
|
int retval;
|
|
|
|
ftempout = fopen(tempfile1,"rb");
|
|
fseek(ftempout, 0, SEEK_END);
|
|
decompressed_bytes_total = ftell(ftempout);
|
|
if (ftempout == NULL) {
|
|
error(ERR_TEMP_FILE_DISAPPEARED);
|
|
}
|
|
|
|
fseek(ftempout, 0, SEEK_SET);
|
|
retval = def_compare(ftempout, origfile, compression_level, windowbits, memlevel, decompressed_bytes_used);
|
|
|
|
safe_fclose(&ftempout);
|
|
|
|
if (retval < 0) return -1;
|
|
|
|
return retval;
|
|
}
|
|
|
|
int file_recompress_bzip2(FILE* origfile, int level, int& decompressed_bytes_used, int& decompressed_bytes_total) {
|
|
int retval;
|
|
|
|
ftempout = fopen(tempfile1,"rb");
|
|
fseek(ftempout, 0, SEEK_END);
|
|
decompressed_bytes_total = ftell(ftempout);
|
|
if (ftempout == NULL) {
|
|
error(ERR_TEMP_FILE_DISAPPEARED);
|
|
}
|
|
|
|
fseek(ftempout, 0, SEEK_SET);
|
|
retval = def_compare_bzip2(ftempout, origfile, level, decompressed_bytes_used);
|
|
|
|
safe_fclose(&ftempout);
|
|
|
|
if (retval < 0) return -1;
|
|
|
|
return retval;
|
|
}
|
|
|
|
void write_decompressed_data(int byte_count, char* decompressed_file_name) {
|
|
ftempout = fopen(decompressed_file_name,"rb");
|
|
if (ftempout == NULL) {
|
|
error(ERR_TEMP_FILE_DISAPPEARED);
|
|
}
|
|
|
|
fseek(ftempout, 0, SEEK_SET);
|
|
|
|
fast_copy(ftempout, fout, byte_count);
|
|
|
|
safe_fclose(&ftempout);
|
|
}
|
|
|
|
unsigned int compare_files(FILE* file1, FILE* file2, unsigned int pos1, unsigned int pos2) {
|
|
unsigned char input_bytes1[COMP_CHUNK];
|
|
unsigned char input_bytes2[COMP_CHUNK];
|
|
int same_byte_count = 0;
|
|
int size1, size2, minsize;
|
|
int i;
|
|
bool endNow = false;
|
|
|
|
seek_64(file1, pos1);
|
|
seek_64(file2, pos2);
|
|
|
|
do {
|
|
print_work_sign(true);
|
|
|
|
size1 = fread(input_bytes1, 1, COMP_CHUNK, file1);
|
|
size2 = fread(input_bytes2, 1, COMP_CHUNK, file2);
|
|
|
|
minsize = min(size1, size2);
|
|
for (i = 0; i < minsize; i++) {
|
|
if (input_bytes1[i] != input_bytes2[i]) {
|
|
endNow = true;
|
|
break;
|
|
}
|
|
same_byte_count++;
|
|
}
|
|
} while ((minsize == COMP_CHUNK) && (!endNow));
|
|
|
|
return same_byte_count;
|
|
}
|
|
|
|
unsigned char input_bytes1[DEF_COMPARE_CHUNK];
|
|
|
|
long long compare_file_mem_penalty(FILE* file1, unsigned char* input_bytes2, long long pos1, long long bytecount, long long& total_same_byte_count, long long& total_same_byte_count_penalty, long long& rek_same_byte_count, long long& rek_same_byte_count_penalty, long long& rek_penalty_bytes_len, long long& local_penalty_bytes_len, bool& use_penalty_bytes) {
|
|
int same_byte_count = 0;
|
|
int size1;
|
|
int i;
|
|
|
|
unsigned long long old_pos;
|
|
old_pos = tell_64(file1);
|
|
seek_64(file1, pos1);
|
|
|
|
size1 = fread(input_bytes1, 1, bytecount, file1);
|
|
|
|
for (i = 0; i < size1; i++) {
|
|
if (input_bytes1[i] == input_bytes2[i]) {
|
|
same_byte_count++;
|
|
total_same_byte_count_penalty++;
|
|
} else {
|
|
total_same_byte_count_penalty -= 5; // 4 bytes = position, 1 byte = new byte
|
|
|
|
// stop, if local_penalty_bytes_len gets too big
|
|
if ((local_penalty_bytes_len + 5) >= MAX_PENALTY_BYTES) {
|
|
break;
|
|
}
|
|
|
|
local_penalty_bytes_len += 5;
|
|
// position
|
|
local_penalty_bytes[local_penalty_bytes_len-5] = (total_same_byte_count >> 24) % 256;
|
|
local_penalty_bytes[local_penalty_bytes_len-4] = (total_same_byte_count >> 16) % 256;
|
|
local_penalty_bytes[local_penalty_bytes_len-3] = (total_same_byte_count >> 8) % 256;
|
|
local_penalty_bytes[local_penalty_bytes_len-2] = total_same_byte_count % 256;
|
|
// new byte
|
|
local_penalty_bytes[local_penalty_bytes_len-1] = input_bytes1[i];
|
|
}
|
|
total_same_byte_count++;
|
|
|
|
if (total_same_byte_count_penalty > rek_same_byte_count_penalty) {
|
|
use_penalty_bytes = true;
|
|
rek_penalty_bytes_len = local_penalty_bytes_len;
|
|
|
|
rek_same_byte_count = total_same_byte_count;
|
|
rek_same_byte_count_penalty = total_same_byte_count_penalty;
|
|
}
|
|
}
|
|
|
|
seek_64(file1, old_pos);
|
|
|
|
return same_byte_count;
|
|
}
|
|
|
|
void start_uncompressed_data() {
|
|
uncompressed_length = 0;
|
|
uncompressed_pos = input_file_pos;
|
|
|
|
// uncompressed data
|
|
fout_fputc(0);
|
|
|
|
uncompressed_data_in_work = true;
|
|
}
|
|
|
|
void end_uncompressed_data() {
|
|
|
|
if (!uncompressed_data_in_work) return;
|
|
|
|
fout_fput64(uncompressed_length);
|
|
|
|
// fast copy of uncompressed data
|
|
seek_64(fin, uncompressed_pos);
|
|
fast_copy(fin, fout, uncompressed_length, true);
|
|
|
|
uncompressed_length = -1;
|
|
|
|
uncompressed_data_in_work = false;
|
|
}
|
|
|
|
int identical_bytes = -1;
|
|
int best_identical_bytes = -1;
|
|
int best_identical_bytes_decomp = -1;
|
|
int best_compression = -1;
|
|
int best_mem_level = -1;
|
|
int best_windowbits = -1;
|
|
int best_penalty_bytes_len = 0;
|
|
int identical_bytes_decomp = -1;
|
|
bool final_compression_found = false;
|
|
|
|
void init_decompression_variables() {
|
|
identical_bytes = -1;
|
|
best_identical_bytes = -1;
|
|
best_compression = -1;
|
|
best_mem_level = -1;
|
|
best_penalty_bytes_len = 0;
|
|
best_identical_bytes_decomp = -1;
|
|
identical_bytes_decomp = -1;
|
|
final_compression_found = false;
|
|
}
|
|
|
|
void try_decompression_pdf(int windowbits, int pdf_header_length, int img_width, int img_height, int img_bpc) {
|
|
init_decompression_variables();
|
|
|
|
int bmp_header_type = 0; // 0 = none, 1 = 8-bit, 2 = 24-bit
|
|
|
|
// try to decompress at current position
|
|
int compressed_stream_size = -1;
|
|
retval = try_to_decompress(fin, windowbits, compressed_stream_size);
|
|
|
|
if (retval > 0) { // seems to be a zLib-Stream
|
|
|
|
decompressed_streams_count++;
|
|
if (img_bpc == 8) {
|
|
decompressed_pdf_count_8_bit++;
|
|
} else {
|
|
decompressed_pdf_count++;
|
|
}
|
|
|
|
if (DEBUG_MODE) {
|
|
print_debug_percent();
|
|
printf ("Possible zLib-Stream in PDF found at position ");
|
|
print64(saved_input_file_pos);
|
|
printf(", windowbits = %i\n", -windowbits);
|
|
printf("Compressed size: %i\n", compressed_stream_size);
|
|
|
|
ftempout = tryOpen(tempfile1, "rb");
|
|
|
|
fseek(ftempout, 0, SEEK_END);
|
|
printf ("Can be decompressed to %li bytes\n", ftell(ftempout));
|
|
safe_fclose(&ftempout);
|
|
}
|
|
|
|
for (int index = 0; index < 81; index++) {
|
|
if (levels_sorted[index] == -1) break;
|
|
int comp_level = (levels_sorted[index] % 9) + 1;
|
|
int mem_level = (levels_sorted[index] / 9) + 1;
|
|
|
|
try_recompress(fin, comp_level, mem_level, windowbits, compressed_stream_size);
|
|
|
|
if (final_compression_found) break;
|
|
}
|
|
|
|
if ((best_identical_bytes > min_ident_size) && (best_identical_bytes < best_identical_bytes_decomp)) {
|
|
recompressed_streams_count++;
|
|
recompressed_pdf_count++;
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Best match with level combination %i%i: %i bytes, decompressed to %i bytes\n", best_compression, best_mem_level, best_identical_bytes, best_identical_bytes_decomp);
|
|
}
|
|
|
|
if (img_bpc == 8) {
|
|
if (best_identical_bytes_decomp == (img_width * img_height)) {
|
|
bmp_header_type = 1;
|
|
if (DEBUG_MODE) {
|
|
printf("Image size did match (8 bit)\n");
|
|
}
|
|
recompressed_pdf_count_8_bit++;
|
|
recompressed_pdf_count--;
|
|
} else if (best_identical_bytes_decomp == (img_width * img_height * 3)) {
|
|
bmp_header_type = 2;
|
|
if (DEBUG_MODE) {
|
|
printf("Image size did match (24 bit)\n");
|
|
}
|
|
decompressed_pdf_count_8_bit--;
|
|
decompressed_pdf_count_24_bit++;
|
|
recompressed_pdf_count_24_bit++;
|
|
recompressed_pdf_count--;
|
|
} else {
|
|
if (DEBUG_MODE) {
|
|
printf("Image size didn't match with stream size\n");
|
|
}
|
|
recompressed_pdf_count--;
|
|
}
|
|
}
|
|
|
|
if (!(comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9] == -1)) {
|
|
if (fast_mode) {
|
|
comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++;
|
|
zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true;
|
|
for (int i = 0; i < 81; i++) {
|
|
if (i != ((best_compression - 1) + (best_mem_level - 1) * 9)) {
|
|
comp_mem_level_count[i] = -1;
|
|
}
|
|
}
|
|
anything_was_used = true;
|
|
sort_comp_mem_levels();
|
|
} else {
|
|
comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++;
|
|
zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true;
|
|
anything_was_used = true;
|
|
sort_comp_mem_levels();
|
|
}
|
|
}
|
|
|
|
// end uncompressed data
|
|
|
|
compressed_data_found = true;
|
|
end_uncompressed_data();
|
|
|
|
// write compressed data header (PDF) without 12 first bytes
|
|
// (/FlateDecode)
|
|
|
|
unsigned char bmp_c = 0;
|
|
|
|
if (bmp_header_type == 1) {
|
|
// 8 Bit, Bit 7,6 = 01
|
|
bmp_c = 64;
|
|
} else if (bmp_header_type == 2) {
|
|
// 24 Bit, Bit 7,6 = 10
|
|
bmp_c = 128;
|
|
}
|
|
|
|
if (best_penalty_bytes_len == 0) {
|
|
fout_fputc(1 + (best_compression << 2) + bmp_c);
|
|
} else {
|
|
fout_fputc(1 + 2 + (best_compression << 2) + bmp_c);
|
|
}
|
|
fout_fputc(0); // PDF
|
|
fout_fputc((((-windowbits) - 8) << 4) + best_mem_level);
|
|
|
|
pdf_header_length -= 12;
|
|
|
|
fout_fput24(pdf_header_length);
|
|
|
|
own_fwrite(in_buf + cb + 12, 1, pdf_header_length, fout);
|
|
|
|
// store penalty bytes, if any
|
|
if (best_penalty_bytes_len != 0) {
|
|
if (DEBUG_MODE) {
|
|
printf("Penalty bytes were used: %i bytes\n", best_penalty_bytes_len);
|
|
}
|
|
fout_fput32(best_penalty_bytes_len);
|
|
for (int pbc = 0; pbc < best_penalty_bytes_len; pbc++) {
|
|
fout_fputc(best_penalty_bytes[pbc]);
|
|
}
|
|
}
|
|
|
|
fout_fput32(best_identical_bytes);
|
|
fout_fput32(best_identical_bytes_decomp);
|
|
|
|
// eventually write BMP header
|
|
|
|
if (bmp_header_type > 0) {
|
|
|
|
int i;
|
|
|
|
fout_fputc('B');
|
|
fout_fputc('M');
|
|
// BMP size in bytes
|
|
int bmp_size = ((img_width+3) & -4) * img_height;
|
|
if (bmp_header_type == 2) bmp_size *= 3;
|
|
if (bmp_header_type == 1) {
|
|
bmp_size += 54 + 1024;
|
|
} else {
|
|
bmp_size += 54;
|
|
}
|
|
fout_fput32_little_endian(bmp_size);
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
fout_fputc(0);
|
|
}
|
|
fout_fputc(54);
|
|
if (bmp_header_type == 1) {
|
|
fout_fputc(4);
|
|
} else {
|
|
fout_fputc(0);
|
|
}
|
|
fout_fputc(0);
|
|
fout_fputc(0);
|
|
fout_fputc(40);
|
|
fout_fputc(0);
|
|
fout_fputc(0);
|
|
fout_fputc(0);
|
|
|
|
fout_fput32_little_endian(img_width);
|
|
fout_fput32_little_endian(img_height);
|
|
|
|
fout_fputc(1);
|
|
fout_fputc(0);
|
|
|
|
if (bmp_header_type == 1) {
|
|
fout_fputc(8);
|
|
} else {
|
|
fout_fputc(24);
|
|
}
|
|
fout_fputc(0);
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
fout_fputc(0);
|
|
}
|
|
|
|
if (bmp_header_type == 2) img_width *= 3;
|
|
|
|
int datasize = ((img_width+3) & -4) * img_height;
|
|
if (bmp_header_type == 2) datasize *= 3;
|
|
fout_fput32_little_endian(datasize);
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
fout_fputc(0);
|
|
}
|
|
|
|
if (bmp_header_type == 1) {
|
|
// write BMP palette
|
|
for (i = 0; i < 1024; i++) {
|
|
fout_fputc(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// write decompressed data
|
|
|
|
if ((bmp_header_type == 0) || ((img_width % 4) == 0)) {
|
|
write_decompressed_data(best_identical_bytes_decomp);
|
|
} else {
|
|
|
|
ftempout = fopen(tempfile1,"rb");
|
|
if (ftempout == NULL) {
|
|
error(ERR_TEMP_FILE_DISAPPEARED);
|
|
}
|
|
|
|
fseek(ftempout, 0, SEEK_SET);
|
|
|
|
for (int y = 0; y < img_height; y++) {
|
|
|
|
fast_copy(ftempout, fout, img_width);
|
|
|
|
for (int i = 0; i < (4 - (img_width % 4)); i++) {
|
|
fout_fputc(0);
|
|
}
|
|
|
|
}
|
|
|
|
safe_fclose(&ftempout);
|
|
}
|
|
|
|
// start new uncompressed data
|
|
|
|
// set input file pointer after recompressed data
|
|
input_file_pos += best_identical_bytes - 1;
|
|
cb += best_identical_bytes - 1;
|
|
|
|
} else {
|
|
if (intense_mode_is_active()) intense_ignore_offsets->insert(input_file_pos - 2);
|
|
if (brute_mode_is_active()) brute_ignore_offsets->insert(input_file_pos);
|
|
if (DEBUG_MODE) {
|
|
printf("No matches\n");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void try_decompression_zip(int zip_header_length) {
|
|
init_decompression_variables();
|
|
|
|
int windowbits;
|
|
|
|
// try to decompress at current position
|
|
int compressed_stream_size = -1;
|
|
retval = try_to_decompress(fin, -15, compressed_stream_size);
|
|
|
|
if (retval > 0) { // seems to be a zLib-Stream
|
|
|
|
decompressed_streams_count++;
|
|
decompressed_zip_count++;
|
|
|
|
if (DEBUG_MODE) {
|
|
print_debug_percent();
|
|
printf ("Possible zLib-Stream in ZIP found at position ");
|
|
print64(saved_input_file_pos);
|
|
printf("\n");
|
|
printf("Compressed size: %i\n", compressed_stream_size);
|
|
|
|
ftempout = tryOpen(tempfile1, "rb");
|
|
fseek(ftempout, 0, SEEK_END);
|
|
printf ("Can be decompressed to %li bytes\n", ftell(ftempout));
|
|
safe_fclose(&ftempout);
|
|
}
|
|
|
|
for (windowbits = -15; windowbits < -7; windowbits++) {
|
|
for (int index = 0; index < 81; index++) {
|
|
if (levels_sorted[index] == -1) break;
|
|
int comp_level = (levels_sorted[index] % 9) + 1;
|
|
int mem_level = (levels_sorted[index] / 9) + 1;
|
|
|
|
try_recompress(fin, comp_level, mem_level, windowbits, compressed_stream_size);
|
|
|
|
if (final_compression_found) break;
|
|
}
|
|
if (final_compression_found) break;
|
|
}
|
|
|
|
if ((best_identical_bytes > min_ident_size) && (best_identical_bytes < best_identical_bytes_decomp)) {
|
|
recompressed_streams_count++;
|
|
recompressed_zip_count++;
|
|
|
|
windowbits = best_windowbits;
|
|
if (DEBUG_MODE) {
|
|
printf("Best match with level combination %i%i, windowbits = %i: %i bytes, decompressed to %i bytes\n", best_compression, best_mem_level, -windowbits, best_identical_bytes, best_identical_bytes_decomp);
|
|
}
|
|
|
|
if (!(comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9] == -1)) {
|
|
if (fast_mode) {
|
|
comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++;
|
|
zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true;
|
|
for (int i = 0; i < 81; i++) {
|
|
if (i != ((best_compression - 1) + (best_mem_level - 1) * 9)) {
|
|
comp_mem_level_count[i] = -1;
|
|
}
|
|
}
|
|
anything_was_used = true;
|
|
sort_comp_mem_levels();
|
|
} else {
|
|
comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++;
|
|
zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true;
|
|
anything_was_used = true;
|
|
sort_comp_mem_levels();
|
|
}
|
|
}
|
|
|
|
// end uncompressed data
|
|
|
|
compressed_data_found = true;
|
|
end_uncompressed_data();
|
|
|
|
// check recursion
|
|
recursion_result r = recursion_compress(best_identical_bytes, best_identical_bytes_decomp);
|
|
|
|
// write compressed data header (ZIP) without 4 first bytes (PK..)
|
|
|
|
int header_byte = 1 + (best_compression << 2);
|
|
if (best_penalty_bytes_len != 0) {
|
|
header_byte += 2;
|
|
}
|
|
if (r.success) {
|
|
header_byte += 128;
|
|
}
|
|
fout_fputc(header_byte);
|
|
fout_fputc(1); // ZIP
|
|
fout_fputc((((-windowbits) - 8) << 4) + best_mem_level);
|
|
|
|
zip_header_length -= 4;
|
|
|
|
fout_fput24(zip_header_length);
|
|
|
|
own_fwrite(in_buf + cb + 4, 1, zip_header_length, fout);
|
|
|
|
// store penalty bytes, if any
|
|
if (best_penalty_bytes_len != 0) {
|
|
if (DEBUG_MODE) {
|
|
printf("Penalty bytes were used: %i bytes\n", best_penalty_bytes_len);
|
|
}
|
|
fout_fput32(best_penalty_bytes_len);
|
|
for (int pbc = 0; pbc < best_penalty_bytes_len; pbc++) {
|
|
fout_fputc(best_penalty_bytes[pbc]);
|
|
}
|
|
}
|
|
|
|
fout_fput32(best_identical_bytes);
|
|
fout_fput32(best_identical_bytes_decomp);
|
|
|
|
if (r.success) {
|
|
fout_fput64(r.file_length);
|
|
}
|
|
|
|
// write decompressed data
|
|
if (r.success) {
|
|
write_decompressed_data(r.file_length, r.file_name);
|
|
remove(r.file_name);
|
|
delete[] r.file_name;
|
|
} else {
|
|
write_decompressed_data(best_identical_bytes_decomp);
|
|
}
|
|
|
|
// set input file pointer after recompressed data
|
|
input_file_pos += best_identical_bytes - 1;
|
|
cb += best_identical_bytes - 1;
|
|
|
|
} else {
|
|
if (brute_mode_is_active()) brute_ignore_offsets->insert(input_file_pos);
|
|
if (DEBUG_MODE) {
|
|
printf("No matches\n");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void sort_comp_mem_levels() {
|
|
int i,j;
|
|
int comp_mem_level_count_copy[81];
|
|
|
|
for (i = 0; i < 81; i++) {
|
|
comp_mem_level_count_copy[i] = comp_mem_level_count[i];
|
|
}
|
|
|
|
int rekcount, reki = -1;
|
|
|
|
for (j = 0; j < 81; j++) {
|
|
rekcount = -2;
|
|
for (i = 0; i < 81; i++) {
|
|
if (comp_mem_level_count_copy[i] > rekcount) {
|
|
rekcount = comp_mem_level_count_copy[i];
|
|
reki = i;
|
|
}
|
|
}
|
|
if (rekcount == -1) {
|
|
levels_sorted[j] = -1;
|
|
} else {
|
|
levels_sorted[j] = reki;
|
|
}
|
|
comp_mem_level_count_copy[reki] = -1;
|
|
}
|
|
|
|
}
|
|
|
|
void show_used_levels() {
|
|
if (!anything_was_used) {
|
|
if (!non_zlib_was_used) {
|
|
if (compression_otf_method == OTF_NONE) {
|
|
printf("\nNone of the given compression and memory levels could be used.\n");
|
|
printf("There will be no gain compressing the output file.\n");
|
|
}
|
|
} else {
|
|
if ((!max_recursion_depth_reached) && (max_recursion_depth_used != max_recursion_depth)) {
|
|
#ifdef COMFORT
|
|
printf("\nYou can speed up Precomp for THIS FILE with these INI parameters:\n");
|
|
printf("Maximal_Recursion_Depth=");
|
|
#else
|
|
printf("\nYou can speed up Precomp for THIS FILE with these parameters:\n");
|
|
printf("-d");
|
|
#endif
|
|
printf("%i\n", max_recursion_depth_used);
|
|
}
|
|
}
|
|
if (max_recursion_depth_reached) {
|
|
printf("\nMaximal recursion depth %i reached, increasing it could give better results.\n", max_recursion_depth);
|
|
}
|
|
return;
|
|
}
|
|
|
|
int i, i_sort;
|
|
int level_count = 0;
|
|
#ifdef COMFORT
|
|
printf("\nYou can speed up Precomp for THIS FILE with these INI parameters:\n");
|
|
printf("zLib_Levels=");
|
|
#else
|
|
printf("\nYou can speed up Precomp for THIS FILE with these parameters:\n");
|
|
printf("-zl");
|
|
#endif
|
|
|
|
bool first_one = true;
|
|
for (i = 0; i < 81; i++) {
|
|
i_sort = (i % 9) * 9 + (i / 9); // to get the displayed levels sorted
|
|
if (zlib_level_was_used[i_sort]) {
|
|
if (!first_one) {
|
|
printf(",");
|
|
} else {
|
|
first_one = false;
|
|
}
|
|
printf("%i%i", (i_sort%9) + 1, (i_sort/9) + 1);
|
|
level_count++;
|
|
}
|
|
}
|
|
|
|
string disable_methods("");
|
|
if (((use_pdf) && ((recompressed_pdf_count == 0) && (decompressed_pdf_count > 0)))) disable_methods += 'p';
|
|
if (((use_zip) && ((recompressed_zip_count == 0) && (decompressed_zip_count > 0)))) disable_methods += 'z';
|
|
if (((use_gzip) && ((recompressed_gzip_count == 0) && (decompressed_gzip_count > 0)))) disable_methods += 'g';
|
|
if ((((use_png) && (((recompressed_png_count + recompressed_png_multi_count) == 0) && (decompressed_png_count + decompressed_png_multi_count > 0))))) disable_methods += 'n';
|
|
if (((use_gif) && ((recompressed_gif_count == 0) && (decompressed_gif_count > 0)))) disable_methods += 'f';
|
|
if (((use_jpg) && (((recompressed_jpg_count + recompressed_jpg_prog_count) == 0) && (decompressed_jpg_count + decompressed_jpg_prog_count > 0)))) disable_methods += 'j';
|
|
if (((use_swf) && ((recompressed_swf_count == 0) && (decompressed_swf_count > 0)))) disable_methods += 's';
|
|
if (((use_base64) && ((recompressed_base64_count == 0) && (decompressed_base64_count > 0)))) disable_methods += 'm';
|
|
if (((use_bzip2) && ((recompressed_bzip2_count == 0) && (decompressed_bzip2_count > 0)))) disable_methods += 'b';
|
|
if (((use_mp3) && ((recompressed_mp3_count == 0) && (decompressed_mp3_count > 0)))) disable_methods += '3';
|
|
if ( disable_methods.length() > 0 ) {
|
|
#ifdef COMFORT
|
|
printf("\nCompression_Types_Disable=%s",disable_methods.c_str());
|
|
#else
|
|
printf(" -t-%s",disable_methods.c_str());
|
|
#endif
|
|
}
|
|
|
|
if (max_recursion_depth_reached) {
|
|
printf("\n\nMaximal recursion depth %i reached, increasing it could give better results.\n", max_recursion_depth);
|
|
} else if (max_recursion_depth_used != max_recursion_depth) {
|
|
#ifdef COMFORT
|
|
printf("\nMaximal_Recursion_Depth=");
|
|
#else
|
|
printf(" -d");
|
|
#endif
|
|
printf("%i", max_recursion_depth_used);
|
|
}
|
|
|
|
if ((level_count == 1) && (!fast_mode)) {
|
|
printf("\n\nFast mode does exactly the same for this file, only faster.\n");
|
|
}
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
bool compress_file(float min_percent, float max_percent) {
|
|
|
|
comp_decomp_state = P_COMPRESS;
|
|
|
|
init_temp_files();
|
|
intense_ignore_offsets = new set<long long>();
|
|
brute_ignore_offsets = new set<long long>();
|
|
|
|
global_min_percent = min_percent;
|
|
global_max_percent = max_percent;
|
|
|
|
if (recursion_depth == 0) write_header();
|
|
uncompressed_length = -1;
|
|
uncompressed_bytes_total = 0;
|
|
uncompressed_bytes_written = 0;
|
|
|
|
if (!DEBUG_MODE) show_progress(min_percent, (recursion_depth > 0), false);
|
|
|
|
seek_64(fin, 0);
|
|
fread(in_buf, 1, IN_BUF_SIZE, fin);
|
|
in_buf_pos = 0;
|
|
cb = -1;
|
|
|
|
anything_was_used = false;
|
|
non_zlib_was_used = false;
|
|
|
|
for (input_file_pos = 0; input_file_pos < fin_length; input_file_pos++) {
|
|
|
|
compressed_data_found = false;
|
|
|
|
bool ignore_this_pos = false;
|
|
|
|
if ((in_buf_pos + IN_BUF_SIZE) <= (input_file_pos + CHECKBUF_SIZE)) {
|
|
seek_64(fin, input_file_pos);
|
|
fread(in_buf, 1, IN_BUF_SIZE, fin);
|
|
in_buf_pos = input_file_pos;
|
|
cb = 0;
|
|
|
|
if (!DEBUG_MODE) {
|
|
float percent = ((input_file_pos + uncompressed_bytes_written) / ((float)fin_length + uncompressed_bytes_total)) * (max_percent - min_percent) + min_percent;
|
|
show_progress(percent, true, true);
|
|
}
|
|
} else {
|
|
cb++;
|
|
}
|
|
|
|
for (int j = 0; j < ignore_list_len; j++) {
|
|
ignore_this_pos = (ignore_list[j] == input_file_pos);
|
|
if (ignore_this_pos) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!ignore_this_pos) {
|
|
|
|
// ZIP header?
|
|
if (((in_buf[cb] == 'P') && (in_buf[cb + 1] == 'K')) && (use_zip)) {
|
|
// local file header?
|
|
if ((in_buf[cb + 2] == 3) && (in_buf[cb + 3] == 4)) {
|
|
if (DEBUG_MODE) {
|
|
printf("ZIP header detected\n");
|
|
print_debug_percent();
|
|
printf("ZIP header detected at position ");
|
|
print64(input_file_pos);
|
|
printf("\n");
|
|
}
|
|
unsigned int compressed_size = (in_buf[cb + 21] << 24) + (in_buf[cb + 20] << 16) + (in_buf[cb + 19] << 8) + in_buf[cb + 18];
|
|
unsigned int uncompressed_size = (in_buf[cb + 25] << 24) + (in_buf[cb + 24] << 16) + (in_buf[cb + 23] << 8) + in_buf[cb + 22];
|
|
unsigned int filename_length = (in_buf[cb + 27] << 8) + in_buf[cb + 26];
|
|
unsigned int extra_field_length = (in_buf[cb + 29] << 8) + in_buf[cb + 28];
|
|
if (DEBUG_MODE) {
|
|
printf("compressed size: %i\n", compressed_size);
|
|
printf("uncompressed size: %i\n", uncompressed_size);
|
|
printf("file name length: %i\n", filename_length);
|
|
printf("extra field length: %i\n", extra_field_length);
|
|
}
|
|
|
|
if ((filename_length + extra_field_length) <= CHECKBUF_SIZE) {
|
|
|
|
int header_length = 30 + filename_length + extra_field_length;
|
|
|
|
saved_input_file_pos = input_file_pos;
|
|
saved_cb = cb;
|
|
|
|
input_file_pos += header_length;
|
|
|
|
try_decompression_zip(header_length);
|
|
|
|
cb += header_length;
|
|
|
|
if (!compressed_data_found) {
|
|
input_file_pos = saved_input_file_pos;
|
|
cb = saved_cb;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((!compressed_data_found) && (use_gzip)) { // no ZIP header -> GZip header?
|
|
if ((in_buf[cb] == 31) && (in_buf[cb + 1] == 139)) {
|
|
// check zLib header in GZip header
|
|
int compression_method = (in_buf[cb + 2] & 15);
|
|
if ((compression_method == 8) &&
|
|
((in_buf[cb + 3] & 224) == 0) // reserved FLG bits must be zero
|
|
) {
|
|
|
|
//((in_buf[cb + 8] == 2) || (in_buf[cb + 8] == 4)) { //XFL = 2 or 4
|
|
// TODO: Can be 0 also, check if other values are used, too.
|
|
//
|
|
// TODO: compressed data is followed by CRC-32 and uncompressed
|
|
// size. Uncompressed size can be used to check if it is really
|
|
// a GZ stream.
|
|
|
|
bool fhcrc = (in_buf[cb + 3] & 2) == 2;
|
|
bool fextra = (in_buf[cb + 3] & 4) == 4;
|
|
bool fname = (in_buf[cb + 3] & 8) == 8;
|
|
bool fcomment = (in_buf[cb + 3] & 16) == 16;
|
|
|
|
int header_length = 10;
|
|
|
|
saved_input_file_pos = input_file_pos;
|
|
saved_cb = cb;
|
|
|
|
bool dont_compress = false;
|
|
|
|
if (fhcrc || fextra || fname || fcomment) {
|
|
int act_checkbuf_pos = 10;
|
|
|
|
if (fextra) {
|
|
int xlen = in_buf[cb + act_checkbuf_pos] + (in_buf[cb + act_checkbuf_pos + 1] << 8);
|
|
if ((act_checkbuf_pos + xlen) > CHECKBUF_SIZE) {
|
|
dont_compress = true;
|
|
} else {
|
|
act_checkbuf_pos += 2;
|
|
header_length += 2;
|
|
act_checkbuf_pos += xlen;
|
|
header_length += xlen;
|
|
}
|
|
}
|
|
if ((fname) && (!dont_compress)) {
|
|
do {
|
|
act_checkbuf_pos ++;
|
|
dont_compress = (act_checkbuf_pos == CHECKBUF_SIZE);
|
|
header_length++;
|
|
} while ((in_buf[cb + act_checkbuf_pos - 1] != 0) && (!dont_compress));
|
|
}
|
|
if ((fcomment) && (!dont_compress)) {
|
|
do {
|
|
act_checkbuf_pos ++;
|
|
dont_compress = (act_checkbuf_pos == CHECKBUF_SIZE);
|
|
header_length++;
|
|
} while ((in_buf[cb + act_checkbuf_pos - 1] != 0) && (!dont_compress));
|
|
}
|
|
if ((fhcrc) && (!dont_compress)) {
|
|
act_checkbuf_pos += 2;
|
|
dont_compress = (act_checkbuf_pos > CHECKBUF_SIZE);
|
|
header_length += 2;
|
|
}
|
|
}
|
|
|
|
if (!dont_compress) {
|
|
|
|
input_file_pos += header_length; // skip GZip header
|
|
|
|
try_decompression_gzip(header_length);
|
|
|
|
cb += header_length;
|
|
|
|
}
|
|
|
|
if (!compressed_data_found) {
|
|
input_file_pos = saved_input_file_pos;
|
|
cb = saved_cb;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((!compressed_data_found) && (use_pdf)) { // no Gzip header -> PDF FlateDecode?
|
|
if (memcmp(in_buf + cb, "/FlateDecode", 12) == 0) {
|
|
saved_input_file_pos = input_file_pos;
|
|
saved_cb = cb;
|
|
|
|
long long act_search_pos = 12;
|
|
bool found_stream = false;
|
|
do {
|
|
if (in_buf[cb + act_search_pos] == 's') {
|
|
if (memcmp(in_buf + cb + act_search_pos, "stream", 6) == 0) {
|
|
found_stream = true;
|
|
break;
|
|
}
|
|
}
|
|
act_search_pos++;
|
|
} while (act_search_pos < (CHECKBUF_SIZE - 6));
|
|
|
|
if (found_stream) {
|
|
|
|
// check if the stream is an image and width and height are given
|
|
|
|
// read 4096 bytes before stream
|
|
|
|
unsigned char type_buf[4097];
|
|
int type_buf_length;
|
|
|
|
type_buf[4096] = 0;
|
|
|
|
if ((input_file_pos + act_search_pos) >= 4096) {
|
|
seek_64(fin, (input_file_pos + act_search_pos) - 4096);
|
|
fread(type_buf, 1, 4096, fin);
|
|
type_buf_length = 4096;
|
|
} else {
|
|
seek_64(fin, 0);
|
|
fread(type_buf, 1, input_file_pos + act_search_pos, fin);
|
|
type_buf_length = input_file_pos + act_search_pos;
|
|
}
|
|
|
|
// find "<<"
|
|
|
|
int start_pos = -1;
|
|
|
|
for (int i = type_buf_length; i > 0; i--) {
|
|
if ((type_buf[i] == '<') && (type_buf[i-1] == '<')) {
|
|
start_pos = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
int width_val = 0, height_val = 0, bpc_val = 0;
|
|
|
|
if ((start_pos > -1) && (pdf_bmp_mode)) {
|
|
|
|
int width_pos, height_pos, bpc_pos;
|
|
|
|
// find "/Width"
|
|
width_pos = (unsigned char*)strstr((const char*)(type_buf + start_pos), "/Width") - type_buf;
|
|
|
|
if (width_pos > 0)
|
|
for (int i = width_pos + 7; i < type_buf_length; i++) {
|
|
if (((type_buf[i] >= '0') && (type_buf[i] <= '9')) || (type_buf[i] == ' ')) {
|
|
if (type_buf[i] != ' ') {
|
|
width_val = width_val * 10 + (type_buf[i] - '0');
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// find "/Height"
|
|
height_pos = (unsigned char*)strstr((const char*)(type_buf + start_pos), "/Height") - type_buf;
|
|
|
|
if (height_pos > 0)
|
|
for (int i = height_pos + 8; i < type_buf_length; i++) {
|
|
if (((type_buf[i] >= '0') && (type_buf[i] <= '9')) || (type_buf[i] == ' ')) {
|
|
if (type_buf[i] != ' ') {
|
|
height_val = height_val * 10 + (type_buf[i] - '0');
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// find "/BitsPerComponent"
|
|
bpc_pos = (unsigned char*)strstr((const char*)(type_buf + start_pos), "/BitsPerComponent") - type_buf;
|
|
|
|
if (bpc_pos > 0)
|
|
for (int i = bpc_pos + 18; i < type_buf_length; i++) {
|
|
if (((type_buf[i] >= '0') && (type_buf[i] <= '9')) || (type_buf[i] == ' ')) {
|
|
if (type_buf[i] != ' ') {
|
|
bpc_val = bpc_val * 10 + (type_buf[i] - '0');
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((width_val != 0) && (height_val != 0) && (bpc_val != 0)) {
|
|
if (DEBUG_MODE) {
|
|
printf("Possible image in PDF found: %i * %i, %i bit\n", width_val, height_val, bpc_val);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((in_buf[cb + act_search_pos + 6] == 13) || (in_buf[cb + act_search_pos + 6] == 10)) {
|
|
if ((in_buf[cb + act_search_pos + 7] == 13) || (in_buf[cb + act_search_pos + 7] == 10)) {
|
|
// seems to be two byte EOL - zLib Header present?
|
|
if (((((in_buf[cb + act_search_pos + 8] << 8) + in_buf[cb + act_search_pos + 9]) % 31) == 0) &&
|
|
((in_buf[cb + act_search_pos + 9] & 32) == 0)) { // FDICT must not be set
|
|
int compression_method = (in_buf[cb + act_search_pos + 8] & 15);
|
|
if (compression_method == 8) {
|
|
|
|
int windowbits = (in_buf[cb + act_search_pos + 8] >> 4) + 8;
|
|
|
|
input_file_pos += act_search_pos + 10; // skip PDF part
|
|
|
|
try_decompression_pdf(-windowbits, act_search_pos + 10, width_val, height_val, bpc_val);
|
|
|
|
cb += act_search_pos + 10;
|
|
}
|
|
}
|
|
} else {
|
|
// seems to be one byte EOL - zLib Header present?
|
|
if ((((in_buf[cb + act_search_pos + 7] << 8) + in_buf[cb + act_search_pos + 8]) % 31) == 0) {
|
|
int compression_method = (in_buf[cb + act_search_pos + 7] & 15);
|
|
if (compression_method == 8) {
|
|
int windowbits = (in_buf[cb + act_search_pos + 7] >> 4) + 8;
|
|
|
|
input_file_pos += act_search_pos + 9; // skip PDF part
|
|
|
|
try_decompression_pdf(-windowbits, act_search_pos + 9, width_val, height_val, bpc_val);
|
|
|
|
cb += act_search_pos + 9;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!compressed_data_found) {
|
|
input_file_pos = saved_input_file_pos;
|
|
cb = saved_cb;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((!compressed_data_found) && (use_png)) { // no PDF header -> PNG IDAT?
|
|
if (memcmp(in_buf + cb, "IDAT", 4) == 0) {
|
|
|
|
// space for length and crc parts of IDAT chunks
|
|
idat_lengths = (unsigned int*)(realloc(idat_lengths, 100 * sizeof(unsigned int)));
|
|
idat_crcs = (unsigned int*)(realloc(idat_crcs, 100 * sizeof(unsigned int)));
|
|
|
|
saved_input_file_pos = input_file_pos;
|
|
saved_cb = cb;
|
|
|
|
idat_count = 0;
|
|
bool zlib_header_correct = false;
|
|
int windowbits = 0;
|
|
|
|
// get preceding length bytes
|
|
if (input_file_pos >= 4) {
|
|
seek_64(fin, input_file_pos - 4);
|
|
|
|
if (fread(in, 1, 10, fin) == 10) {
|
|
seek_64(fin, tell_64(fin) - 2);
|
|
|
|
idat_lengths[0] = (in[0] << 24) + (in[1] << 16) + (in[2] << 8) + in[3];
|
|
if (idat_lengths[0] > 2) {
|
|
|
|
// check zLib header and get windowbits
|
|
zlib_header[0] = in[8];
|
|
zlib_header[1] = in[9];
|
|
if ((((in[8] << 8) + in[9]) % 31) == 0) {
|
|
if ((in[8] & 15) == 8) {
|
|
if ((in[9] & 32) == 0) { // FDICT must not be set
|
|
windowbits = (in[8] >> 4) + 8;
|
|
zlib_header_correct = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (zlib_header_correct) {
|
|
|
|
idat_count++;
|
|
|
|
// go through additional IDATs
|
|
for (;;) {
|
|
seek_64(fin, tell_64(fin) + idat_lengths[idat_count - 1]);
|
|
if (fread(in, 1, 12, fin) != 12) { // CRC, length, "IDAT"
|
|
idat_count = 0;
|
|
break;
|
|
}
|
|
|
|
if (memcmp(in + 8, "IDAT", 4) == 0) {
|
|
idat_crcs[idat_count] = (in[0] << 24) + (in[1] << 16) + (in[2] << 8) + in[3];
|
|
idat_lengths[idat_count] = (in[4] << 24) + (in[5] << 16) + (in[6] << 8) + in[7];
|
|
idat_count++;
|
|
|
|
if ((idat_count % 100) == 0) {
|
|
idat_lengths = (unsigned int*)realloc(idat_lengths, (idat_count + 100) * sizeof(unsigned int));
|
|
idat_crcs = (unsigned int*)realloc(idat_crcs, (idat_count + 100) * sizeof(unsigned int));
|
|
}
|
|
|
|
if (idat_count > 65535) {
|
|
idat_count = 0;
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (idat_count == 1) {
|
|
|
|
// try to recompress directly
|
|
input_file_pos += 6;
|
|
try_decompression_png(-windowbits);
|
|
cb += 6;
|
|
} else if (idat_count > 1) {
|
|
// copy to temp0.dat before trying to recompress
|
|
remove(tempfile0);
|
|
fpng = tryOpen(tempfile0,"w+b");
|
|
|
|
seek_64(fin, input_file_pos + 6); // start after zLib header
|
|
|
|
idat_lengths[0] -= 2; // zLib header length
|
|
for (int i = 0; i < idat_count; i++) {
|
|
fast_copy(fin, fpng, idat_lengths[i]);
|
|
seek_64(fin, tell_64(fin) + 12);
|
|
}
|
|
idat_lengths[0] += 2;
|
|
|
|
input_file_pos += 6;
|
|
try_decompression_png_multi(-windowbits);
|
|
cb += 6;
|
|
|
|
safe_fclose(&fpng);
|
|
}
|
|
|
|
if (!compressed_data_found) {
|
|
input_file_pos = saved_input_file_pos;
|
|
cb = saved_cb;
|
|
}
|
|
|
|
free(idat_lengths);
|
|
idat_lengths = NULL;
|
|
free(idat_crcs);
|
|
idat_crcs = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
if ((!compressed_data_found) && (use_gif)) { // no PNG header -> GIF header?
|
|
if ((in_buf[cb] == 'G') && (in_buf[cb + 1] == 'I') && (in_buf[cb + 2] == 'F')) {
|
|
if ((in_buf[cb + 3] == '8') && (in_buf[cb + 5] == 'a')) {
|
|
if ((in_buf[cb + 4] == '7') || (in_buf[cb + 4] == '9')) {
|
|
|
|
unsigned char version[5];
|
|
|
|
for (int i = 0; i < 5; i++) {
|
|
version[i] = in_buf[cb + i];
|
|
}
|
|
|
|
saved_input_file_pos = input_file_pos;
|
|
saved_cb = cb;
|
|
|
|
try_decompression_gif(version);
|
|
|
|
if (!compressed_data_found) {
|
|
input_file_pos = saved_input_file_pos;
|
|
cb = saved_cb;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((!compressed_data_found) && (use_jpg) && (input_file_pos > suppress_jpg_parsing_until)) { // no GIF header -> JPG header?
|
|
if ((in_buf[cb] == 0xFF) && (in_buf[cb + 1] == 0xD8)) { // SOI (FF D8)
|
|
if ((in_buf[cb + 2] == 0xFF)) {
|
|
saved_input_file_pos = input_file_pos;
|
|
saved_cb = cb;
|
|
|
|
int eoi_count = 1;
|
|
bool progressive_flag = false;
|
|
|
|
// find SOF
|
|
bool ff_sof_found = false;
|
|
bool sof_found = false;
|
|
long long sof_pos = input_file_pos + 1;
|
|
seek_64(fin, input_file_pos + 2);
|
|
|
|
while (fread(in, 1, 1, fin) == 1) {
|
|
sof_pos++;
|
|
if (ff_sof_found) {
|
|
if (in[0] == 0xD8) { // another SOI (FF D8) - increase EOI count
|
|
eoi_count++;
|
|
}
|
|
sof_found = ((in[0] == 0xC0) // baseline
|
|
|| (in[0] == 0xC2)); // progressive
|
|
if (sof_found) {
|
|
progressive_flag = (in[0] == 0xC2);
|
|
if (fread(in, 1, 3, fin) == 3) {
|
|
if (in[2] == 0x08) {
|
|
break;
|
|
} else {
|
|
sof_found = false;
|
|
break;
|
|
}
|
|
}
|
|
sof_found = false;
|
|
} else {
|
|
ff_sof_found = (in[0] == 0xFF);
|
|
}
|
|
} else {
|
|
ff_sof_found = (in[0] == 0xFF);
|
|
}
|
|
}
|
|
|
|
// find EOI
|
|
bool ff_eoi_found = false;
|
|
long long eoi_pos = 0;
|
|
|
|
if (sof_found) {
|
|
|
|
eoi_pos = sof_pos + 1;
|
|
seek_64(fin, sof_pos + 2);
|
|
while (fread(in, 1, 1, fin) == 1) {
|
|
eoi_pos++;
|
|
if (ff_eoi_found) {
|
|
if (in[0] == 0xD8) { // another SOI (FF D8) - increase EOI count
|
|
eoi_count++;
|
|
}
|
|
if (in[0] == 0xD9) {
|
|
eoi_count--;
|
|
if (eoi_count == 0) break;
|
|
} else {
|
|
ff_eoi_found = (in[0] == 0xFF);
|
|
}
|
|
} else {
|
|
ff_eoi_found = (in[0] == 0xFF);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (eoi_count == 0) {
|
|
|
|
long long jpg_length = (eoi_pos + 1) - input_file_pos;
|
|
|
|
try_decompression_jpg(jpg_length, progressive_flag);
|
|
|
|
if (!compressed_data_found) {
|
|
input_file_pos = saved_input_file_pos;
|
|
cb = saved_cb;
|
|
}
|
|
} else if (eoi_count >= 256) {
|
|
// more than 255 nested images -> seems to be other data
|
|
// skip until eoi_count is guaranteed to be under 16 to speed
|
|
// up the parsing
|
|
suppress_jpg_parsing_until = saved_input_file_pos + (eoi_count - 16) * 2;
|
|
if (DEBUG_MODE) {
|
|
printf("Ignoring following JPG streams until position ");
|
|
print64(suppress_jpg_parsing_until);
|
|
printf(" to avoid slowdown\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((!compressed_data_found) && (use_mp3)) { // no JPG header -> MP3 header?
|
|
if ((in_buf[cb] == 0xFF) && ((in_buf[cb + 1] & 0xE0) == 0xE0)) { // frame start
|
|
int mpeg = -1;
|
|
int layer = -1;
|
|
int samples = -1;
|
|
int channels = -1;
|
|
int protection = -1;
|
|
int type = -1;
|
|
|
|
int bits;
|
|
int padding;
|
|
int frame_size;
|
|
int n = 0;
|
|
long long mp3_parsing_cache_second_frame_candidate = -1;
|
|
long long mp3_parsing_cache_second_frame_candidate_size = -1;
|
|
|
|
long long mp3_length = 0;
|
|
|
|
saved_input_file_pos = input_file_pos;
|
|
saved_cb = cb;
|
|
|
|
long long act_pos = input_file_pos;
|
|
|
|
// parse frames until first invalid frame is found or end-of-file
|
|
seek_64(fin, act_pos);
|
|
while (fread(in, 1, 4, fin) == 4) {
|
|
// check syncword
|
|
if ((in[0] != 0xFF) || ((in[1] & 0xE0) != 0xE0)) break;
|
|
// compare data from header
|
|
if (n == 0) {
|
|
mpeg = (in[1] >> 3) & 0x3;
|
|
layer = (in[1] >> 1) & 0x3;
|
|
protection = (in[1] >> 0) & 0x1;
|
|
samples = (in[2] >> 2) & 0x3;
|
|
channels = (in[3] >> 6) & 0x3;
|
|
type = MBITS( in[1], 5, 1 );
|
|
// avoid slowdown and multiple verbose messages on unsupported types that have already been detected
|
|
if ((type != MPEG1_LAYER_III) && (saved_input_file_pos <= suppress_mp3_type_until[type])) {
|
|
break;
|
|
}
|
|
} else {
|
|
if (n == 1) {
|
|
mp3_parsing_cache_second_frame_candidate = act_pos;
|
|
mp3_parsing_cache_second_frame_candidate_size = act_pos - saved_input_file_pos;
|
|
}
|
|
if (type == MPEG1_LAYER_III) { // supported MP3 type, all header information must be identical to the first frame
|
|
if (
|
|
(mpeg != ((in[1] >> 3) & 0x3)) ||
|
|
(layer != ((in[1] >> 1) & 0x3)) ||
|
|
(protection != ((in[1] >> 0) & 0x1)) ||
|
|
(samples != ((in[2] >> 2) & 0x3)) ||
|
|
(channels != ((in[3] >> 6) & 0x3)) ||
|
|
(type != MBITS( in[1], 5, 1))) break;
|
|
} else { // unsupported type, compare only type, ignore the other header information to get a longer stream
|
|
if (type != MBITS( in[1], 5, 1)) break;
|
|
}
|
|
}
|
|
|
|
bits = (in[2] >> 4) & 0xF;
|
|
padding = (in[2] >> 1) & 0x1;
|
|
// check for problems
|
|
if ((mpeg == 0x1) || (layer == 0x0) ||
|
|
(bits == 0x0) || (bits == 0xF) || (samples == 0x3)) break;
|
|
// find out frame size
|
|
frame_size = frame_size_table[mpeg][layer][samples][bits];
|
|
if (padding) frame_size += (layer == LAYER_I) ? 4 : 1;
|
|
|
|
// if this frame was part of a stream that already has been parsed, skip parsing
|
|
if (n == 0) {
|
|
if (act_pos == mp3_parsing_cache_second_frame) {
|
|
n = mp3_parsing_cache_n;
|
|
mp3_length = mp3_parsing_cache_mp3_length;
|
|
|
|
// update values
|
|
mp3_parsing_cache_second_frame = act_pos + frame_size;
|
|
mp3_parsing_cache_n -= 1;
|
|
mp3_parsing_cache_mp3_length -= frame_size;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
n++;
|
|
mp3_length += frame_size;
|
|
act_pos += frame_size;
|
|
|
|
// if supported MP3 type, validate frames
|
|
if ((type == MPEG1_LAYER_III) && (frame_size > 4)) {
|
|
unsigned char header2 = in[2];
|
|
unsigned char header3 = in[3];
|
|
if (fread(in, 1, frame_size - 4, fin) != (unsigned int)(frame_size - 4)) {
|
|
// discard incomplete frame
|
|
n--;
|
|
mp3_length -= frame_size;
|
|
break;
|
|
}
|
|
if (!is_valid_mp3_frame(in, header2, header3, protection)) {
|
|
n = 0;
|
|
break;
|
|
}
|
|
} else {
|
|
seek_64(fin, act_pos);
|
|
}
|
|
}
|
|
|
|
// conditions for proper first frame: 5 consecutive frames
|
|
if (n >= 5) {
|
|
if (mp3_parsing_cache_second_frame_candidate > -1) {
|
|
mp3_parsing_cache_second_frame = mp3_parsing_cache_second_frame_candidate;
|
|
mp3_parsing_cache_n = n - 1;
|
|
mp3_parsing_cache_mp3_length = mp3_length - mp3_parsing_cache_second_frame_candidate_size;
|
|
}
|
|
|
|
long long position_length_sum = saved_input_file_pos + mp3_length;
|
|
|
|
// type must be MPEG-1, Layer III, packMP3 won't process any other files
|
|
if ( type == MPEG1_LAYER_III ) {
|
|
// sum of position and length of last "big value pairs out of bounds" error is suppressed to avoid slowdowns
|
|
if (suppress_mp3_big_value_pairs_sum != position_length_sum) {
|
|
try_decompression_mp3(mp3_length);
|
|
}
|
|
} else if (type > 0) {
|
|
suppress_mp3_type_until[type] = position_length_sum;
|
|
if (DEBUG_MODE) {
|
|
print_debug_percent();
|
|
printf ("Unsupported MP3 type found at position ");
|
|
print64(saved_input_file_pos);
|
|
printf (", length ");
|
|
print64(mp3_length);
|
|
printf ("\n");
|
|
printf ("Type: %s\n", filetype_description[type]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!compressed_data_found) {
|
|
input_file_pos = saved_input_file_pos;
|
|
cb = saved_cb;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((!compressed_data_found) && (use_swf)) { // no MP3 header -> SWF header?
|
|
// CWS = Compressed SWF file
|
|
if ((in_buf[cb] == 'C') && (in_buf[cb + 1] == 'W') && (in_buf[cb + 2] == 'S')) {
|
|
// check zLib header
|
|
if (((((in_buf[cb + 8] << 8) + in_buf[cb + 9]) % 31) == 0) &&
|
|
((in_buf[cb + 9] & 32) == 0)) { // FDICT must not be set
|
|
int compression_method = (in_buf[cb + 8] & 15);
|
|
if (compression_method == 8) {
|
|
int windowbits = (in_buf[cb + 8] >> 4) + 8;
|
|
|
|
saved_input_file_pos = input_file_pos;
|
|
saved_cb = cb;
|
|
|
|
input_file_pos += 10; // skip CWS and zLib header
|
|
|
|
try_decompression_swf(-windowbits);
|
|
|
|
cb += 10;
|
|
|
|
if (!compressed_data_found) {
|
|
input_file_pos = saved_input_file_pos;
|
|
cb = saved_cb;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((!compressed_data_found) && (use_base64)) { // no SWF header -> Base64?
|
|
if ((in_buf[cb + 1] == 'o') && (in_buf[cb + 2] == 'n') && (in_buf[cb + 3] == 't') && (in_buf[cb + 4] == 'e')) {
|
|
unsigned char cte_detect[33];
|
|
for (int i = 0; i < 33; i++) {
|
|
cte_detect[i] = tolower(in_buf[cb + i]);
|
|
}
|
|
if (memcmp(cte_detect, "content-transfer-encoding: base64", 33) == 0) {
|
|
// search for double CRLF, all between is "header"
|
|
int base64_header_length = 33;
|
|
bool found_double_crlf = false;
|
|
do {
|
|
if ((in_buf[cb + base64_header_length] == 13) && (in_buf[cb + base64_header_length + 1] == 10)) {
|
|
if ((in_buf[cb + base64_header_length + 2] == 13) && (in_buf[cb + base64_header_length + 3] == 10)) {
|
|
found_double_crlf = true;
|
|
base64_header_length += 4;
|
|
// skip additional CRLFs
|
|
while ((in_buf[cb + base64_header_length] == 13) && (in_buf[cb + base64_header_length + 1] == 10)) {
|
|
base64_header_length += 2;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
base64_header_length++;
|
|
} while (base64_header_length < (CHECKBUF_SIZE - 2));
|
|
|
|
if (found_double_crlf) {
|
|
|
|
saved_input_file_pos = input_file_pos;
|
|
saved_cb = cb;
|
|
|
|
input_file_pos += base64_header_length; // skip "header"
|
|
|
|
try_decompression_base64(base64_header_length);
|
|
|
|
cb += base64_header_length;
|
|
|
|
if (!compressed_data_found) {
|
|
input_file_pos = saved_input_file_pos;
|
|
cb = saved_cb;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((!compressed_data_found) && (use_bzip2)) { // no Base64 header -> bZip2?
|
|
// BZhx = header, x = compression level/blocksize (1-9)
|
|
if ((in_buf[cb] == 'B') && (in_buf[cb + 1] == 'Z') && (in_buf[cb + 2] == 'h')) {
|
|
int compression_level = in_buf[cb + 3] - '0';
|
|
if ((compression_level >= 1) && (compression_level <= 9)) {
|
|
saved_input_file_pos = input_file_pos;
|
|
saved_cb = cb;
|
|
|
|
try_decompression_bzip2(compression_level);
|
|
|
|
if (!compressed_data_found) {
|
|
input_file_pos = saved_input_file_pos;
|
|
cb = saved_cb;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// nothing so far -> if intense mode is active, look for raw zLib header
|
|
if (intense_mode_is_active()) {
|
|
if (!compressed_data_found) {
|
|
bool ignore_this_position = false;
|
|
if (intense_ignore_offsets->size() > 0) {
|
|
auto first = intense_ignore_offsets->begin();
|
|
while (*first < input_file_pos) {
|
|
intense_ignore_offsets->erase(first);
|
|
if (intense_ignore_offsets->size() == 0) break;
|
|
first = intense_ignore_offsets->begin();
|
|
}
|
|
|
|
if (intense_ignore_offsets->size() > 0) {
|
|
if (*first == input_file_pos) {
|
|
ignore_this_position = true;
|
|
intense_ignore_offsets->erase(first);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!ignore_this_position) {
|
|
if (((((in_buf[cb] << 8) + in_buf[cb + 1]) % 31) == 0) &&
|
|
((in_buf[cb + 1] & 32) == 0)) { // FDICT must not be set
|
|
int compression_method = (in_buf[cb] & 15);
|
|
if (compression_method == 8) {
|
|
int windowbits = (in_buf[cb] >> 4) + 8;
|
|
|
|
if (check_inf_result(cb + 2, -windowbits)) {
|
|
saved_input_file_pos = input_file_pos;
|
|
saved_cb = cb;
|
|
|
|
input_file_pos += 2; // skip zLib header
|
|
|
|
try_decompression_zlib(-windowbits);
|
|
|
|
cb += 2;
|
|
|
|
if (!compressed_data_found) {
|
|
input_file_pos = saved_input_file_pos;
|
|
cb = saved_cb;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
|
|
// nothing so far -> if brute mode is active, brute force for zLib streams
|
|
if (brute_mode_is_active()) {
|
|
if (!compressed_data_found) {
|
|
bool ignore_this_position = false;
|
|
if (brute_ignore_offsets->size() > 0) {
|
|
auto first = brute_ignore_offsets->begin();
|
|
while (*first < input_file_pos) {
|
|
brute_ignore_offsets->erase(first);
|
|
if (brute_ignore_offsets->size() == 0) break;
|
|
first = brute_ignore_offsets->begin();
|
|
}
|
|
|
|
if (brute_ignore_offsets->size() > 0) {
|
|
if (*first == input_file_pos) {
|
|
ignore_this_position = true;
|
|
brute_ignore_offsets->erase(first);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!ignore_this_position) {
|
|
saved_input_file_pos = input_file_pos;
|
|
saved_cb = cb;
|
|
|
|
if (check_inf_result(cb, -15, true)) {
|
|
try_decompression_brute();
|
|
}
|
|
|
|
if (!compressed_data_found) {
|
|
input_file_pos = saved_input_file_pos;
|
|
cb = saved_cb;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (!compressed_data_found) {
|
|
if (uncompressed_length == -1) {
|
|
start_uncompressed_data();
|
|
}
|
|
uncompressed_length++;
|
|
uncompressed_bytes_total++;
|
|
}
|
|
|
|
}
|
|
|
|
end_uncompressed_data();
|
|
|
|
denit_compress();
|
|
|
|
return (anything_was_used || non_zlib_was_used);
|
|
}
|
|
|
|
void decompress_file() {
|
|
|
|
long long fin_pos;
|
|
|
|
comp_decomp_state = P_DECOMPRESS;
|
|
|
|
init_temp_files();
|
|
if (compression_otf_method != OTF_NONE) {
|
|
init_decompress_otf();
|
|
}
|
|
|
|
if (recursion_depth == 0) {
|
|
if (!DEBUG_MODE) show_progress(0, false, false);
|
|
read_header();
|
|
}
|
|
|
|
fin_pos = tell_64(fin);
|
|
|
|
while (fin_pos < fin_length) {
|
|
|
|
if ((recursion_depth == 0) && (!DEBUG_MODE)) {
|
|
float percent = (fin_pos / (float)fin_length) * 100;
|
|
show_progress(percent, true, true);
|
|
}
|
|
|
|
unsigned char header1 = fin_fgetc();
|
|
if (header1 == 0) { // uncompressed data
|
|
long long uncompressed_data_length;
|
|
uncompressed_data_length = ((long long)fin_fgetc() << 56);
|
|
uncompressed_data_length += ((long long)fin_fgetc() << 48);
|
|
uncompressed_data_length += ((long long)fin_fgetc() << 40);
|
|
uncompressed_data_length += ((long long)fin_fgetc() << 32);
|
|
uncompressed_data_length += ((long long)fin_fgetc() << 24);
|
|
uncompressed_data_length += ((long long)fin_fgetc() << 16);
|
|
uncompressed_data_length += ((long long)fin_fgetc() << 8);
|
|
uncompressed_data_length += (long long)fin_fgetc();
|
|
|
|
if (uncompressed_data_length == 0) break; // end of PCF file, used by bZip2 compress-on-the-fly
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Uncompressed data, length=");
|
|
print64(uncompressed_data_length);
|
|
printf("\n");
|
|
}
|
|
|
|
fast_copy(fin, fout, uncompressed_data_length);
|
|
|
|
} else { // decompressed data, recompress
|
|
|
|
unsigned char headertype = fin_fgetc();
|
|
|
|
if (headertype == 0) { // PDF recompression
|
|
if (DEBUG_MODE) {
|
|
printf("Decompressed data - PDF\n");
|
|
}
|
|
|
|
unsigned char header2 = fin_fgetc();
|
|
|
|
bool penalty_bytes_stored = ((header1 & 2) == 2);
|
|
int compression_level = (header1 >> 2) & 15;
|
|
int bmp_c = (header1 >> 6);
|
|
int windowbits = -(((header2 >> 4) & 15) + 8);
|
|
int memlevel = header2 & 15;
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Compression level: %i\n", compression_level);
|
|
printf("Window size: %i\n", -windowbits);
|
|
printf("Memory level: %i\n", memlevel);
|
|
if (bmp_c == 1) printf("Skipping BMP header (8-Bit)\n");
|
|
if (bmp_c == 2) printf("Skipping BMP header (24-Bit)\n");
|
|
}
|
|
|
|
int pdf_header_length;
|
|
pdf_header_length = (fin_fgetc() << 16);
|
|
pdf_header_length += (fin_fgetc() << 8);
|
|
pdf_header_length += fin_fgetc();
|
|
|
|
// restore PDF header
|
|
fprintf(fout, "/FlateDecode");
|
|
|
|
own_fread(in, 1, pdf_header_length, fin);
|
|
own_fwrite(in, 1, pdf_header_length, fout);
|
|
|
|
// read penalty bytes
|
|
if (penalty_bytes_stored) {
|
|
penalty_bytes_len = (fin_fgetc() << 24);
|
|
penalty_bytes_len += (fin_fgetc() << 16);
|
|
penalty_bytes_len += (fin_fgetc() << 8);
|
|
penalty_bytes_len += fin_fgetc();
|
|
own_fread(penalty_bytes, 1, penalty_bytes_len, fin);
|
|
}
|
|
|
|
int recompressed_data_length;
|
|
recompressed_data_length = (fin_fgetc() << 24);
|
|
recompressed_data_length += (fin_fgetc() << 16);
|
|
recompressed_data_length += (fin_fgetc() << 8);
|
|
recompressed_data_length += fin_fgetc();
|
|
|
|
int decompressed_data_length;
|
|
decompressed_data_length = (fin_fgetc() << 24);
|
|
decompressed_data_length += (fin_fgetc() << 16);
|
|
decompressed_data_length += (fin_fgetc() << 8);
|
|
decompressed_data_length += fin_fgetc();
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Recompressed Length: %i - Decompressed length: %i\n", recompressed_data_length, decompressed_data_length);
|
|
}
|
|
|
|
// keep file position for penalty bytes
|
|
long long old_fout_pos = tell_64(fout);
|
|
|
|
// read BMP header
|
|
|
|
int bmp_width = 0;
|
|
|
|
switch (bmp_c) {
|
|
case 1:
|
|
own_fread(in, 1, 54+1024, fin);
|
|
break;
|
|
case 2:
|
|
own_fread(in, 1, 54, fin);
|
|
break;
|
|
}
|
|
if (bmp_c > 0) {
|
|
bmp_width = in[18] + (in[19] << 8) + (in[20] << 16) + (in[21] << 24);
|
|
if (bmp_c == 2) bmp_width *= 3;
|
|
}
|
|
|
|
if ((bmp_c == 0) || ((bmp_width % 4) == 0)) {
|
|
// recompress directly to fout
|
|
retval = def_part(fin, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length);
|
|
if (retval != Z_OK) {
|
|
printf("Error recompressing data!");
|
|
printf("retval = %i\n", retval);
|
|
exit(0);
|
|
}
|
|
} else { // lines aligned to 4 byte, skip those bytes
|
|
// recompress directly to fout, but skipping bytes
|
|
|
|
retval = def_part_skip(fin, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length, bmp_width);
|
|
|
|
if (retval != Z_OK) {
|
|
printf("Error recompressing data!");
|
|
printf("retval = %i\n", retval);
|
|
exit(0);
|
|
}
|
|
|
|
}
|
|
|
|
if (penalty_bytes_stored) {
|
|
fflush(fout);
|
|
|
|
long long fsave_fout_pos = tell_64(fout);
|
|
|
|
int pb_pos = 0;
|
|
for (int pbc = 0; pbc < penalty_bytes_len; pbc += 5) {
|
|
pb_pos = ((unsigned char)penalty_bytes[pbc]) << 24;
|
|
pb_pos += ((unsigned char)penalty_bytes[pbc + 1]) << 16;
|
|
pb_pos += ((unsigned char)penalty_bytes[pbc + 2]) << 8;
|
|
pb_pos += (unsigned char)penalty_bytes[pbc + 3];
|
|
|
|
seek_64(fout, old_fout_pos + pb_pos);
|
|
own_fwrite(penalty_bytes + pbc + 4, 1, 1, fout);
|
|
}
|
|
|
|
seek_64(fout, fsave_fout_pos);
|
|
}
|
|
|
|
} else if (headertype == 1) { // ZIP recompression
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Decompressed data - ZIP\n");
|
|
}
|
|
|
|
unsigned char header2 = fin_fgetc();
|
|
|
|
bool penalty_bytes_stored = ((header1 & 2) == 2);
|
|
bool recursion_used = ((header1 & 128) == 128);
|
|
int compression_level = (header1 >> 2) & 15;
|
|
int windowbits = -(((header2 >> 4) & 15) + 8);
|
|
int memlevel = header2 & 15;
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Compression level: %i\n", compression_level);
|
|
printf("Window size: %i\n", -windowbits);
|
|
printf("Memory level: %i\n", memlevel);
|
|
}
|
|
|
|
int zip_header_length;
|
|
zip_header_length = (fin_fgetc() << 16);
|
|
zip_header_length += (fin_fgetc() << 8);
|
|
zip_header_length += fin_fgetc();
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("ZIP header length: %i\n", zip_header_length);
|
|
}
|
|
|
|
fputc('P', fout);
|
|
fputc('K', fout);
|
|
fputc(3, fout);
|
|
fputc(4, fout);
|
|
|
|
own_fread(in, 1, zip_header_length, fin);
|
|
own_fwrite(in, 1, zip_header_length, fout);
|
|
|
|
// read penalty bytes
|
|
if (penalty_bytes_stored) {
|
|
penalty_bytes_len = (fin_fgetc() << 24);
|
|
penalty_bytes_len += (fin_fgetc() << 16);
|
|
penalty_bytes_len += (fin_fgetc() << 8);
|
|
penalty_bytes_len += fin_fgetc();
|
|
own_fread(penalty_bytes, 1, penalty_bytes_len, fin);
|
|
}
|
|
|
|
int recompressed_data_length;
|
|
recompressed_data_length = (fin_fgetc() << 24);
|
|
recompressed_data_length += (fin_fgetc() << 16);
|
|
recompressed_data_length += (fin_fgetc() << 8);
|
|
recompressed_data_length += fin_fgetc();
|
|
|
|
int decompressed_data_length;
|
|
decompressed_data_length = (fin_fgetc() << 24);
|
|
decompressed_data_length += (fin_fgetc() << 16);
|
|
decompressed_data_length += (fin_fgetc() << 8);
|
|
decompressed_data_length += fin_fgetc();
|
|
|
|
long long recursion_data_length = 0;
|
|
if (recursion_used) {
|
|
recursion_data_length = ((long long)fin_fgetc() << 56);
|
|
recursion_data_length += ((long long)fin_fgetc() << 48);
|
|
recursion_data_length += ((long long)fin_fgetc() << 40);
|
|
recursion_data_length += ((long long)fin_fgetc() << 32);
|
|
recursion_data_length += ((long long)fin_fgetc() << 24);
|
|
recursion_data_length += ((long long)fin_fgetc() << 16);
|
|
recursion_data_length += ((long long)fin_fgetc() << 8);
|
|
recursion_data_length += (long long)fin_fgetc();
|
|
}
|
|
|
|
if (DEBUG_MODE) {
|
|
if (recursion_used) {
|
|
printf("Recursion data length: ");
|
|
print64(recursion_data_length);
|
|
printf("\n");
|
|
} else {
|
|
printf("Recompressed Length: %i - Decompressed length: %i\n", recompressed_data_length, decompressed_data_length);
|
|
}
|
|
}
|
|
|
|
long long old_fout_pos = tell_64(fout);
|
|
|
|
if (recursion_used) {
|
|
recursion_result r = recursion_decompress(recursion_data_length);
|
|
retval = def_part(r.frecurse, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length);
|
|
safe_fclose(&r.frecurse);
|
|
remove(r.file_name);
|
|
delete[] r.file_name;
|
|
} else {
|
|
retval = def_part(fin, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length);
|
|
}
|
|
|
|
if (retval != Z_OK) {
|
|
printf("Error recompressing data!");
|
|
printf("retval = %i\n", retval);
|
|
exit(0);
|
|
}
|
|
|
|
if (penalty_bytes_stored) {
|
|
fflush(fout);
|
|
|
|
long long fsave_fout_pos = tell_64(fout);
|
|
int pb_pos = 0;
|
|
for (int pbc = 0; pbc < penalty_bytes_len; pbc += 5) {
|
|
pb_pos = ((unsigned char)penalty_bytes[pbc]) << 24;
|
|
pb_pos += ((unsigned char)penalty_bytes[pbc + 1]) << 16;
|
|
pb_pos += ((unsigned char)penalty_bytes[pbc + 2]) << 8;
|
|
pb_pos += (unsigned char)penalty_bytes[pbc + 3];
|
|
|
|
seek_64(fout, old_fout_pos + pb_pos);
|
|
own_fwrite(penalty_bytes + pbc + 4, 1, 1, fout);
|
|
|
|
}
|
|
|
|
seek_64(fout, fsave_fout_pos);
|
|
}
|
|
|
|
} else if (headertype == 2) { // GZip recompression
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Decompressed data - GZip\n");
|
|
}
|
|
|
|
unsigned char header2 = fin_fgetc();
|
|
|
|
bool penalty_bytes_stored = ((header1 & 2) == 2);
|
|
bool recursion_used = ((header1 & 128) == 128);
|
|
int compression_level = (header1 >> 2) & 15;
|
|
int windowbits = -(((header2 >> 4) & 15) + 8);
|
|
int memlevel = header2 & 15;
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Compression level: %i\n", compression_level);
|
|
printf("Window size: %i\n", -windowbits);
|
|
printf("Memory level: %i\n", memlevel);
|
|
}
|
|
|
|
int gzip_header_length;
|
|
gzip_header_length = (fin_fgetc() << 16);
|
|
gzip_header_length += (fin_fgetc() << 8);
|
|
gzip_header_length += fin_fgetc();
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("GZip header length: %i\n", gzip_header_length);
|
|
}
|
|
|
|
fputc(31, fout);
|
|
fputc(139, fout);
|
|
|
|
own_fread(in, 1, gzip_header_length, fin);
|
|
own_fwrite(in, 1, gzip_header_length, fout);
|
|
|
|
// read penalty bytes
|
|
if (penalty_bytes_stored) {
|
|
penalty_bytes_len = (fin_fgetc() << 24);
|
|
penalty_bytes_len += (fin_fgetc() << 16);
|
|
penalty_bytes_len += (fin_fgetc() << 8);
|
|
penalty_bytes_len += fin_fgetc();
|
|
own_fread(penalty_bytes, 1, penalty_bytes_len, fin);
|
|
}
|
|
|
|
int recompressed_data_length;
|
|
recompressed_data_length = (fin_fgetc() << 24);
|
|
recompressed_data_length += (fin_fgetc() << 16);
|
|
recompressed_data_length += (fin_fgetc() << 8);
|
|
recompressed_data_length += fin_fgetc();
|
|
|
|
int decompressed_data_length;
|
|
decompressed_data_length = (fin_fgetc() << 24);
|
|
decompressed_data_length += (fin_fgetc() << 16);
|
|
decompressed_data_length += (fin_fgetc() << 8);
|
|
decompressed_data_length += fin_fgetc();
|
|
|
|
long long recursion_data_length = 0;
|
|
if (recursion_used) {
|
|
recursion_data_length = ((long long)fin_fgetc() << 56);
|
|
recursion_data_length += ((long long)fin_fgetc() << 48);
|
|
recursion_data_length += ((long long)fin_fgetc() << 40);
|
|
recursion_data_length += ((long long)fin_fgetc() << 32);
|
|
recursion_data_length += ((long long)fin_fgetc() << 24);
|
|
recursion_data_length += ((long long)fin_fgetc() << 16);
|
|
recursion_data_length += ((long long)fin_fgetc() << 8);
|
|
recursion_data_length += (long long)fin_fgetc();
|
|
}
|
|
|
|
if (DEBUG_MODE) {
|
|
if (recursion_used) {
|
|
printf("Recursion data length: ");
|
|
print64(recursion_data_length);
|
|
printf("\n");
|
|
} else {
|
|
printf("Recompressed Length: %i - Decompressed length: %i\n", recompressed_data_length, decompressed_data_length);
|
|
}
|
|
}
|
|
|
|
long long old_fout_pos = tell_64(fout);
|
|
|
|
if (recursion_used) {
|
|
recursion_result r = recursion_decompress(recursion_data_length);
|
|
retval = def_part(r.frecurse, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length);
|
|
safe_fclose(&r.frecurse);
|
|
remove(r.file_name);
|
|
delete[] r.file_name;
|
|
} else {
|
|
retval = def_part(fin, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length);
|
|
}
|
|
|
|
if (retval != Z_OK) {
|
|
printf("Error recompressing data!");
|
|
printf("retval = %i\n", retval);
|
|
exit(0);
|
|
}
|
|
|
|
if (penalty_bytes_stored) {
|
|
fflush(fout);
|
|
|
|
long long fsave_fout_pos = tell_64(fout);
|
|
int pb_pos = 0;
|
|
for (int pbc = 0; pbc < penalty_bytes_len; pbc += 5) {
|
|
pb_pos = ((unsigned char)penalty_bytes[pbc]) << 24;
|
|
pb_pos += ((unsigned char)penalty_bytes[pbc + 1]) << 16;
|
|
pb_pos += ((unsigned char)penalty_bytes[pbc + 2]) << 8;
|
|
pb_pos += (unsigned char)penalty_bytes[pbc + 3];
|
|
|
|
seek_64(fout, old_fout_pos + pb_pos);
|
|
own_fwrite(penalty_bytes + pbc + 4, 1, 1, fout);
|
|
}
|
|
|
|
seek_64(fout, fsave_fout_pos);
|
|
}
|
|
|
|
} else if (headertype == 3) { // PNG recompression
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Decompressed data - PNG\n");
|
|
}
|
|
|
|
unsigned char header2 = fin_fgetc();
|
|
|
|
bool penalty_bytes_stored = ((header1 & 2) == 2);
|
|
int compression_level = (header1 >> 2) & 15;
|
|
int windowbits = -(((header2 >> 4) & 15) + 8);
|
|
int memlevel = header2 & 15;
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Compression level: %i\n", compression_level);
|
|
printf("Window size: %i\n", -windowbits);
|
|
printf("Memory level: %i\n", memlevel);
|
|
}
|
|
|
|
// restore IDAT
|
|
fprintf(fout, "IDAT");
|
|
|
|
// restore zLib header (decrease by 1)
|
|
own_fread(in, 1, 2, fin);
|
|
unsigned char decchar = *(in + 1) - 1;
|
|
own_fwrite(in, 1, 1, fout);
|
|
fputc(decchar, fout);
|
|
|
|
// read penalty bytes
|
|
if (penalty_bytes_stored) {
|
|
penalty_bytes_len = (fin_fgetc() << 24);
|
|
penalty_bytes_len += (fin_fgetc() << 16);
|
|
penalty_bytes_len += (fin_fgetc() << 8);
|
|
penalty_bytes_len += fin_fgetc();
|
|
own_fread(penalty_bytes, 1, penalty_bytes_len, fin);
|
|
}
|
|
|
|
int recompressed_data_length;
|
|
recompressed_data_length = (fin_fgetc() << 24);
|
|
recompressed_data_length += (fin_fgetc() << 16);
|
|
recompressed_data_length += (fin_fgetc() << 8);
|
|
recompressed_data_length += fin_fgetc();
|
|
|
|
int decompressed_data_length;
|
|
decompressed_data_length = (fin_fgetc() << 24);
|
|
decompressed_data_length += (fin_fgetc() << 16);
|
|
decompressed_data_length += (fin_fgetc() << 8);
|
|
decompressed_data_length += fin_fgetc();
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Recompressed Length: %i - Decompressed length: %i\n", recompressed_data_length, decompressed_data_length);
|
|
}
|
|
|
|
long long old_fout_pos = tell_64(fout);
|
|
|
|
retval = def_part(fin, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length);
|
|
|
|
if (retval != Z_OK) {
|
|
printf("Error recompressing data!");
|
|
printf("retval = %i\n", retval);
|
|
exit(0);
|
|
}
|
|
|
|
if (penalty_bytes_stored) {
|
|
fflush(fout);
|
|
|
|
long long fsave_fout_pos = tell_64(fout);
|
|
|
|
int pb_pos = 0;
|
|
for (int pbc = 0; pbc < penalty_bytes_len; pbc += 5) {
|
|
pb_pos = ((unsigned char)penalty_bytes[pbc]) << 24;
|
|
pb_pos += ((unsigned char)penalty_bytes[pbc + 1]) << 16;
|
|
pb_pos += ((unsigned char)penalty_bytes[pbc + 2]) << 8;
|
|
pb_pos += (unsigned char)penalty_bytes[pbc + 3];
|
|
|
|
seek_64(fout, old_fout_pos + pb_pos);
|
|
own_fwrite(penalty_bytes + pbc + 4, 1, 1, fout);
|
|
}
|
|
|
|
seek_64(fout, fsave_fout_pos);
|
|
}
|
|
|
|
} else if (headertype == 4) { // PNG multi recompression
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Decompressed data - PNG multi\n");
|
|
}
|
|
|
|
unsigned char header2 = fin_fgetc();
|
|
|
|
bool penalty_bytes_stored = ((header1 & 2) == 2);
|
|
int compression_level = (header1 >> 2) & 15;
|
|
int windowbits = -(((header2 >> 4) & 15) + 8);
|
|
int memlevel = header2 & 15;
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Compression level: %i\n", compression_level);
|
|
printf("Window size: %i\n", -windowbits);
|
|
printf("Memory level: %i\n", memlevel);
|
|
}
|
|
|
|
// restore first IDAT
|
|
fprintf(fout, "IDAT");
|
|
|
|
// restore zLib header (decrease by 1)
|
|
own_fread(in, 1, 2, fin);
|
|
unsigned char decchar = *(in + 1) - 1;
|
|
own_fwrite(in, 1, 1, fout);
|
|
fputc(decchar, fout);
|
|
|
|
// get IDAT count
|
|
own_fread(in, 1, 2, fin);
|
|
idat_count = (in[0] << 8) + in[1];
|
|
idat_count++;
|
|
|
|
idat_crcs = (unsigned int*)(realloc(idat_crcs, idat_count * sizeof(unsigned int)));
|
|
idat_lengths = (unsigned int*)(realloc(idat_lengths, idat_count * sizeof(unsigned int)));
|
|
|
|
// get first IDAT length
|
|
own_fread(in, 1, 4, fin);
|
|
idat_lengths[0] = (in[0] << 24) + (in[1] << 16) + (in[2] << 8) + in[3];
|
|
idat_lengths[0] -= 2; // zLib header length
|
|
|
|
// get IDAT chunk lengths and CRCs
|
|
for (int i = 1; i < idat_count; i++) {
|
|
own_fread(in, 1, 4, fin);
|
|
idat_crcs[i] = (in[0] << 24) + (in[1] << 16) + (in[2] << 8) + in[3];
|
|
own_fread(in, 1, 4, fin);
|
|
idat_lengths[i] = (in[0] << 24) + (in[1] << 16) + (in[2] << 8) + in[3];
|
|
}
|
|
|
|
// read penalty bytes
|
|
if (penalty_bytes_stored) {
|
|
penalty_bytes_len = (fin_fgetc() << 24);
|
|
penalty_bytes_len += (fin_fgetc() << 16);
|
|
penalty_bytes_len += (fin_fgetc() << 8);
|
|
penalty_bytes_len += fin_fgetc();
|
|
own_fread(penalty_bytes, 1, penalty_bytes_len, fin);
|
|
}
|
|
|
|
int recompressed_data_length;
|
|
recompressed_data_length = (fin_fgetc() << 24);
|
|
recompressed_data_length += (fin_fgetc() << 16);
|
|
recompressed_data_length += (fin_fgetc() << 8);
|
|
recompressed_data_length += fin_fgetc();
|
|
|
|
int decompressed_data_length;
|
|
decompressed_data_length = (fin_fgetc() << 24);
|
|
decompressed_data_length += (fin_fgetc() << 16);
|
|
decompressed_data_length += (fin_fgetc() << 8);
|
|
decompressed_data_length += fin_fgetc();
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Recompressed Length: %i - Decompressed length: %i\n", recompressed_data_length, decompressed_data_length);
|
|
}
|
|
|
|
remove(tempfile1);
|
|
ftempout = tryOpen(tempfile1,"wb");
|
|
|
|
fast_copy(fin, ftempout, decompressed_data_length);
|
|
|
|
safe_fclose(&ftempout);
|
|
|
|
remove(tempfile2);
|
|
|
|
ftempout = tryOpen(tempfile1,"rb");
|
|
frecomp = tryOpen(tempfile2,"wb");
|
|
|
|
long long old_frecomp_pos = tell_64(frecomp);
|
|
|
|
// recompress data
|
|
retval = def(ftempout, frecomp, compression_level, windowbits, memlevel);
|
|
if ((!penalty_bytes_stored) || (retval != Z_OK)) safe_fclose(&frecomp);
|
|
safe_fclose(&ftempout);
|
|
|
|
if (retval != Z_OK) {
|
|
printf("Error recompressing data!");
|
|
printf("retval = %i\n", retval);
|
|
exit(0);
|
|
}
|
|
|
|
if (penalty_bytes_stored) {
|
|
fflush(frecomp);
|
|
|
|
int pb_pos = 0;
|
|
for (int pbc = 0; pbc < penalty_bytes_len; pbc += 5) {
|
|
pb_pos = ((unsigned char)penalty_bytes[pbc]) << 24;
|
|
pb_pos += ((unsigned char)penalty_bytes[pbc + 1]) << 16;
|
|
pb_pos += ((unsigned char)penalty_bytes[pbc + 2]) << 8;
|
|
pb_pos += (unsigned char)penalty_bytes[pbc + 3];
|
|
|
|
seek_64(frecomp, old_frecomp_pos + pb_pos);
|
|
own_fwrite(penalty_bytes + pbc + 4, 1, 1, frecomp);
|
|
}
|
|
|
|
safe_fclose(&frecomp);
|
|
}
|
|
|
|
frecomp = tryOpen(tempfile2,"rb");
|
|
|
|
int remaining_bytes = recompressed_data_length;
|
|
unsigned int act_idat_chunk = 0;
|
|
for (;;) {
|
|
if ((remaining_bytes + 2) > (int)idat_lengths[act_idat_chunk]) {
|
|
fast_copy(frecomp, fout, idat_lengths[act_idat_chunk]);
|
|
remaining_bytes -= idat_lengths[act_idat_chunk];
|
|
|
|
fputc((idat_crcs[act_idat_chunk+1] >> 24) % 256, fout);
|
|
fputc((idat_crcs[act_idat_chunk+1] >> 16) % 256, fout);
|
|
fputc((idat_crcs[act_idat_chunk+1] >> 8) % 256, fout);
|
|
fputc(idat_crcs[act_idat_chunk+1] % 256, fout);
|
|
fputc((idat_lengths[act_idat_chunk+1] >> 24) % 256, fout);
|
|
fputc((idat_lengths[act_idat_chunk+1] >> 16) % 256, fout);
|
|
fputc((idat_lengths[act_idat_chunk+1] >> 8) % 256, fout);
|
|
fputc(idat_lengths[act_idat_chunk+1] % 256, fout);
|
|
fprintf(fout, "IDAT");
|
|
} else {
|
|
fast_copy(frecomp, fout, remaining_bytes);
|
|
break;
|
|
}
|
|
act_idat_chunk++;
|
|
}
|
|
|
|
safe_fclose(&frecomp);
|
|
|
|
remove(tempfile2);
|
|
remove(tempfile1);
|
|
|
|
free(idat_lengths);
|
|
idat_lengths = NULL;
|
|
free(idat_crcs);
|
|
idat_crcs = NULL;
|
|
|
|
} else if (headertype == 5) { // GIF recompression
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Decompressed data - GIF\n");
|
|
}
|
|
|
|
unsigned char block_size = 255;
|
|
|
|
bool penalty_bytes_stored = ((header1 & 2) == 2);
|
|
if ((header1 & 4) == 4) block_size = 254;
|
|
bool recompress_success_needed = ((header1 & 128) == 128);
|
|
|
|
GifDiffStruct gDiff;
|
|
|
|
// read diff bytes
|
|
gDiff.GIFDiffIndex = (fin_fgetc() << 24);
|
|
gDiff.GIFDiffIndex += (fin_fgetc() << 16);
|
|
gDiff.GIFDiffIndex += (fin_fgetc() << 8);
|
|
gDiff.GIFDiffIndex += fin_fgetc();
|
|
gDiff.GIFDiff = (unsigned char*)malloc(gDiff.GIFDiffIndex * sizeof(unsigned char));
|
|
own_fread(gDiff.GIFDiff, 1, gDiff.GIFDiffIndex, fin);
|
|
if (DEBUG_MODE) {
|
|
printf("Diff bytes were used: %i bytes\n", gDiff.GIFDiffIndex);
|
|
}
|
|
gDiff.GIFDiffSize = gDiff.GIFDiffIndex;
|
|
gDiff.GIFDiffIndex = 0;
|
|
gDiff.GIFCodeCount = 0;
|
|
|
|
// read penalty bytes
|
|
if (penalty_bytes_stored) {
|
|
penalty_bytes_len = (fin_fgetc() << 24);
|
|
penalty_bytes_len += (fin_fgetc() << 16);
|
|
penalty_bytes_len += (fin_fgetc() << 8);
|
|
penalty_bytes_len += fin_fgetc();
|
|
own_fread(penalty_bytes, 1, penalty_bytes_len, fin);
|
|
}
|
|
|
|
int recompressed_data_length;
|
|
recompressed_data_length = (fin_fgetc() << 24);
|
|
recompressed_data_length += (fin_fgetc() << 16);
|
|
recompressed_data_length += (fin_fgetc() << 8);
|
|
recompressed_data_length += fin_fgetc();
|
|
|
|
int decompressed_data_length;
|
|
decompressed_data_length = (fin_fgetc() << 24);
|
|
decompressed_data_length += (fin_fgetc() << 16);
|
|
decompressed_data_length += (fin_fgetc() << 8);
|
|
decompressed_data_length += fin_fgetc();
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Recompressed Length: %i - Decompressed length: %i\n", recompressed_data_length, decompressed_data_length);
|
|
}
|
|
|
|
remove(tempfile1);
|
|
ftempout = tryOpen(tempfile1,"wb");
|
|
|
|
fast_copy(fin, ftempout, decompressed_data_length);
|
|
|
|
safe_fclose(&ftempout);
|
|
|
|
remove(tempfile2);
|
|
|
|
bool recompress_success = false;
|
|
|
|
ftempout = tryOpen(tempfile1,"rb");
|
|
frecomp = tryOpen(tempfile2,"wb");
|
|
|
|
// recompress data
|
|
recompress_success = recompress_gif(ftempout, frecomp, block_size, NULL, &gDiff);
|
|
|
|
safe_fclose(&frecomp);
|
|
safe_fclose(&ftempout);
|
|
|
|
if (recompress_success_needed) {
|
|
if (!recompress_success) {
|
|
printf("Error recompressing data!");
|
|
GifDiffFree(&gDiff);
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
long long old_fout_pos = tell_64(fout);
|
|
|
|
frecomp = tryOpen(tempfile2,"rb");
|
|
|
|
fast_copy(frecomp, fout, recompressed_data_length);
|
|
|
|
safe_fclose(&frecomp);
|
|
|
|
remove(tempfile2);
|
|
remove(tempfile1);
|
|
|
|
if (penalty_bytes_stored) {
|
|
fflush(fout);
|
|
|
|
long long fsave_fout_pos = tell_64(fout);
|
|
|
|
int pb_pos = 0;
|
|
for (int pbc = 0; pbc < penalty_bytes_len; pbc += 5) {
|
|
pb_pos = ((unsigned char)penalty_bytes[pbc]) << 24;
|
|
pb_pos += ((unsigned char)penalty_bytes[pbc + 1]) << 16;
|
|
pb_pos += ((unsigned char)penalty_bytes[pbc + 2]) << 8;
|
|
pb_pos += (unsigned char)penalty_bytes[pbc + 3];
|
|
|
|
seek_64(fout, old_fout_pos + pb_pos);
|
|
own_fwrite(penalty_bytes + pbc + 4, 1, 1, fout);
|
|
}
|
|
|
|
seek_64(fout, fsave_fout_pos);
|
|
}
|
|
|
|
GifDiffFree(&gDiff);
|
|
|
|
} else if (headertype == 6) { // JPG recompression
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Decompressed data - JPG\n");
|
|
}
|
|
|
|
bool mjpg_dht_used = ((header1 & 4) == 4);
|
|
|
|
int recompressed_data_length;
|
|
recompressed_data_length = (fin_fgetc() << 24);
|
|
recompressed_data_length += (fin_fgetc() << 16);
|
|
recompressed_data_length += (fin_fgetc() << 8);
|
|
recompressed_data_length += fin_fgetc();
|
|
|
|
int decompressed_data_length;
|
|
decompressed_data_length = (fin_fgetc() << 24);
|
|
decompressed_data_length += (fin_fgetc() << 16);
|
|
decompressed_data_length += (fin_fgetc() << 8);
|
|
decompressed_data_length += fin_fgetc();
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Recompressed Length: %i - Decompressed length: %i\n", recompressed_data_length, decompressed_data_length);
|
|
}
|
|
|
|
char recompress_msg[256];
|
|
unsigned char* jpg_mem_in = NULL;
|
|
unsigned char* jpg_mem_out = NULL;
|
|
unsigned int jpg_mem_out_size = -1;
|
|
bool in_memory = (recompressed_data_length <= JPG_MAX_MEMORY_SIZE);
|
|
bool recompress_success = false;
|
|
|
|
if (in_memory) {
|
|
jpg_mem_in = new unsigned char[decompressed_data_length];
|
|
|
|
fast_copy(fin, jpg_mem_in, decompressed_data_length);
|
|
|
|
pjglib_init_streams(jpg_mem_in, 1, decompressed_data_length, jpg_mem_out, 1);
|
|
recompress_success = pjglib_convert_stream2mem(&jpg_mem_out, &jpg_mem_out_size, recompress_msg);
|
|
} else {
|
|
remove(tempfile1);
|
|
ftempout = tryOpen(tempfile1,"wb");
|
|
|
|
fast_copy(fin, ftempout, decompressed_data_length);
|
|
|
|
safe_fclose(&ftempout);
|
|
|
|
remove(tempfile2);
|
|
|
|
recompress_success = pjglib_convert_file2file(tempfile1, tempfile2, recompress_msg);
|
|
}
|
|
|
|
if (!recompress_success) {
|
|
if (DEBUG_MODE) printf ("packJPG error: %s\n", recompress_msg);
|
|
printf("Error recompressing data!");
|
|
exit(1);
|
|
}
|
|
|
|
if (!in_memory) {
|
|
frecomp = tryOpen(tempfile2,"rb");
|
|
}
|
|
|
|
if (mjpg_dht_used) {
|
|
long long frecomp_pos = 0;
|
|
bool found_ffda = false;
|
|
bool found_ff = false;
|
|
int ffda_pos = -1;
|
|
|
|
if (in_memory) {
|
|
do {
|
|
ffda_pos++;
|
|
if (ffda_pos >= (int)jpg_mem_out_size) break;
|
|
if (found_ff) {
|
|
found_ffda = (jpg_mem_out[ffda_pos] == 0xDA);
|
|
if (found_ffda) break;
|
|
found_ff = false;
|
|
} else {
|
|
found_ff = (jpg_mem_out[ffda_pos] == 0xFF);
|
|
}
|
|
} while (!found_ffda);
|
|
} else {
|
|
do {
|
|
ffda_pos++;
|
|
if (fread(in, 1, 1, frecomp) != 1) break;
|
|
if (found_ff) {
|
|
found_ffda = (in[0] == 0xDA);
|
|
if (found_ffda) break;
|
|
found_ff = false;
|
|
} else {
|
|
found_ff = (in[0] == 0xFF);
|
|
}
|
|
} while (!found_ffda);
|
|
}
|
|
|
|
if ((!found_ffda) || ((ffda_pos - 1 - MJPGDHT_LEN) < 0)) {
|
|
printf("ERROR: Motion JPG stream corrupted\n");
|
|
exit(1);
|
|
}
|
|
|
|
// remove motion JPG huffman table
|
|
if (in_memory) {
|
|
fast_copy(jpg_mem_out, fout, ffda_pos - 1 - MJPGDHT_LEN);
|
|
fast_copy(jpg_mem_out + (ffda_pos - 1), fout, (recompressed_data_length + MJPGDHT_LEN) - (ffda_pos - 1));
|
|
} else {
|
|
seek_64(frecomp, frecomp_pos);
|
|
fast_copy(frecomp, fout, ffda_pos - 1 - MJPGDHT_LEN);
|
|
|
|
frecomp_pos += ffda_pos - 1;
|
|
seek_64(frecomp, frecomp_pos);
|
|
fast_copy(frecomp, fout, (recompressed_data_length + MJPGDHT_LEN) - (ffda_pos - 1));
|
|
}
|
|
} else {
|
|
if (in_memory) {
|
|
fast_copy(jpg_mem_out, fout, recompressed_data_length);
|
|
} else {
|
|
fast_copy(frecomp, fout, recompressed_data_length);
|
|
}
|
|
}
|
|
|
|
if (in_memory) {
|
|
if (jpg_mem_in != NULL) delete[] jpg_mem_in;
|
|
if (jpg_mem_out != NULL) delete[] jpg_mem_out;
|
|
} else {
|
|
safe_fclose(&frecomp);
|
|
|
|
remove(tempfile2);
|
|
remove(tempfile1);
|
|
}
|
|
|
|
} else if (headertype == 7) { // SWF recompression
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Decompressed data - SWF\n");
|
|
}
|
|
|
|
unsigned char header2 = fin_fgetc();
|
|
|
|
bool penalty_bytes_stored = ((header1 & 2) == 2);
|
|
bool recursion_used = ((header1 & 128) == 128);
|
|
int compression_level = (header1 >> 2) & 15;
|
|
int windowbits = -(((header2 >> 4) & 15) + 8);
|
|
int memlevel = header2 & 15;
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Compression level: %i\n", compression_level);
|
|
printf("Window size: %i\n", -windowbits);
|
|
printf("Memory level: %i\n", memlevel);
|
|
}
|
|
|
|
fputc('C', fout);
|
|
fputc('W', fout);
|
|
fputc('S', fout);
|
|
// get Flash version
|
|
char c = fin_fgetc();
|
|
fputc(c, fout);
|
|
// get length from SWF header
|
|
for (int i = 0; i < 4; i++) {
|
|
c = fin_fgetc();
|
|
fputc(c, fout);
|
|
}
|
|
|
|
// restore zLib header (decrease by 1)
|
|
own_fread(in, 1, 2, fin);
|
|
unsigned char decchar = *(in + 1) - 1;
|
|
own_fwrite(in, 1, 1, fout);
|
|
fputc(decchar, fout);
|
|
|
|
// read penalty bytes
|
|
if (penalty_bytes_stored) {
|
|
penalty_bytes_len = (fin_fgetc() << 24);
|
|
penalty_bytes_len += (fin_fgetc() << 16);
|
|
penalty_bytes_len += (fin_fgetc() << 8);
|
|
penalty_bytes_len += fin_fgetc();
|
|
own_fread(penalty_bytes, 1, penalty_bytes_len, fin);
|
|
}
|
|
|
|
int recompressed_data_length;
|
|
recompressed_data_length = (fin_fgetc() << 24);
|
|
recompressed_data_length += (fin_fgetc() << 16);
|
|
recompressed_data_length += (fin_fgetc() << 8);
|
|
recompressed_data_length += fin_fgetc();
|
|
|
|
int decompressed_data_length;
|
|
decompressed_data_length = (fin_fgetc() << 24);
|
|
decompressed_data_length += (fin_fgetc() << 16);
|
|
decompressed_data_length += (fin_fgetc() << 8);
|
|
decompressed_data_length += fin_fgetc();
|
|
|
|
long long recursion_data_length = 0;
|
|
if (recursion_used) {
|
|
recursion_data_length = ((long long)fin_fgetc() << 56);
|
|
recursion_data_length += ((long long)fin_fgetc() << 48);
|
|
recursion_data_length += ((long long)fin_fgetc() << 40);
|
|
recursion_data_length += ((long long)fin_fgetc() << 32);
|
|
recursion_data_length += ((long long)fin_fgetc() << 24);
|
|
recursion_data_length += ((long long)fin_fgetc() << 16);
|
|
recursion_data_length += ((long long)fin_fgetc() << 8);
|
|
recursion_data_length += (long long)fin_fgetc();
|
|
}
|
|
|
|
if (DEBUG_MODE) {
|
|
if (recursion_used) {
|
|
printf("Recursion data length: ");
|
|
print64(recursion_data_length);
|
|
printf("\n");
|
|
} else {
|
|
printf("Recompressed Length: %i - Decompressed length: %i\n", recompressed_data_length, decompressed_data_length);
|
|
}
|
|
}
|
|
|
|
long long old_fout_pos = tell_64(fout);
|
|
|
|
if (recursion_used) {
|
|
recursion_result r = recursion_decompress(recursion_data_length);
|
|
retval = def_part(r.frecurse, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length);
|
|
safe_fclose(&r.frecurse);
|
|
remove(r.file_name);
|
|
delete[] r.file_name;
|
|
} else {
|
|
retval = def_part(fin, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length);
|
|
}
|
|
|
|
if (retval != Z_OK) {
|
|
printf("Error recompressing data!");
|
|
printf("retval = %i\n", retval);
|
|
exit(0);
|
|
}
|
|
|
|
if (penalty_bytes_stored) {
|
|
fflush(fout);
|
|
|
|
long long fsave_fout_pos = tell_64(fout);
|
|
int pb_pos = 0;
|
|
for (int pbc = 0; pbc < penalty_bytes_len; pbc += 5) {
|
|
pb_pos = ((unsigned char)penalty_bytes[pbc]) << 24;
|
|
pb_pos += ((unsigned char)penalty_bytes[pbc + 1]) << 16;
|
|
pb_pos += ((unsigned char)penalty_bytes[pbc + 2]) << 8;
|
|
pb_pos += (unsigned char)penalty_bytes[pbc + 3];
|
|
|
|
seek_64(fout, old_fout_pos + pb_pos);
|
|
own_fwrite(penalty_bytes + pbc + 4, 1, 1, fout);
|
|
}
|
|
|
|
seek_64(fout, fsave_fout_pos);
|
|
}
|
|
|
|
} else if (headertype == 8) { // Base64 recompression
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Decompressed data - Base64\n");
|
|
}
|
|
|
|
int line_case = (header1 >> 2) & 3;
|
|
bool recursion_used = ((header1 & 128) == 128);
|
|
|
|
// restore Base64 "header"
|
|
int base64_header_length;
|
|
base64_header_length = (fin_fgetc() << 8);
|
|
base64_header_length += fin_fgetc();
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Base64 header length: %i\n", base64_header_length);
|
|
}
|
|
own_fread(in, 1, base64_header_length, fin);
|
|
fputc(*(in) + 1, fout); // first char was decreased
|
|
own_fwrite(in + 1, 1, base64_header_length - 1, fout);
|
|
|
|
// read line length list
|
|
int line_count = fin_fgetc() << 8;
|
|
line_count += fin_fgetc();
|
|
|
|
unsigned int* base64_line_len = new unsigned int[line_count];
|
|
|
|
if (line_case == 2) {
|
|
for (int i = 0; i < line_count; i++) {
|
|
base64_line_len[i] = fin_fgetc();
|
|
}
|
|
} else {
|
|
base64_line_len[0] = fin_fgetc();
|
|
for (int i = 1; i < line_count; i++) {
|
|
base64_line_len[i] = base64_line_len[0];
|
|
}
|
|
if (line_case == 1) base64_line_len[line_count - 1] = fin_fgetc();
|
|
}
|
|
|
|
int recompressed_data_length;
|
|
recompressed_data_length = (fin_fgetc() << 24);
|
|
recompressed_data_length += (fin_fgetc() << 16);
|
|
recompressed_data_length += (fin_fgetc() << 8);
|
|
recompressed_data_length += fin_fgetc();
|
|
|
|
int decompressed_data_length;
|
|
decompressed_data_length = (fin_fgetc() << 24);
|
|
decompressed_data_length += (fin_fgetc() << 16);
|
|
decompressed_data_length += (fin_fgetc() << 8);
|
|
decompressed_data_length += fin_fgetc();
|
|
|
|
long long recursion_data_length = 0;
|
|
if (recursion_used) {
|
|
recursion_data_length = ((long long)fin_fgetc() << 56);
|
|
recursion_data_length += ((long long)fin_fgetc() << 48);
|
|
recursion_data_length += ((long long)fin_fgetc() << 40);
|
|
recursion_data_length += ((long long)fin_fgetc() << 32);
|
|
recursion_data_length += ((long long)fin_fgetc() << 24);
|
|
recursion_data_length += ((long long)fin_fgetc() << 16);
|
|
recursion_data_length += ((long long)fin_fgetc() << 8);
|
|
recursion_data_length += (long long)fin_fgetc();
|
|
}
|
|
|
|
if (DEBUG_MODE) {
|
|
if (recursion_used) {
|
|
printf("Recursion data length: ");
|
|
print64(recursion_data_length);
|
|
printf("\n");
|
|
} else {
|
|
printf("Encoded Length: %i - Decoded length: %i\n", recompressed_data_length, decompressed_data_length);
|
|
}
|
|
}
|
|
|
|
// re-encode Base64
|
|
|
|
if (recursion_used) {
|
|
recursion_result r = recursion_decompress(recursion_data_length);
|
|
base64_reencode(r.frecurse, fout, line_count, base64_line_len, r.file_length, decompressed_data_length);
|
|
safe_fclose(&r.frecurse);
|
|
remove(r.file_name);
|
|
delete[] r.file_name;
|
|
} else {
|
|
base64_reencode(fin, fout, line_count, base64_line_len, recompressed_data_length, decompressed_data_length);
|
|
}
|
|
|
|
delete[] base64_line_len;
|
|
} else if (headertype == 9) { // bZip2 recompression
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Decompressed data - bZip2\n");
|
|
}
|
|
|
|
unsigned char header2 = fin_fgetc();
|
|
|
|
bool penalty_bytes_stored = ((header1 & 2) == 2);
|
|
bool recursion_used = ((header1 & 128) == 128);
|
|
int level = header2;
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Compression level: %i\n", level);
|
|
}
|
|
|
|
// read penalty bytes
|
|
if (penalty_bytes_stored) {
|
|
penalty_bytes_len = (fin_fgetc() << 24);
|
|
penalty_bytes_len += (fin_fgetc() << 16);
|
|
penalty_bytes_len += (fin_fgetc() << 8);
|
|
penalty_bytes_len += fin_fgetc();
|
|
own_fread(penalty_bytes, 1, penalty_bytes_len, fin);
|
|
}
|
|
|
|
int recompressed_data_length;
|
|
recompressed_data_length = (fin_fgetc() << 24);
|
|
recompressed_data_length += (fin_fgetc() << 16);
|
|
recompressed_data_length += (fin_fgetc() << 8);
|
|
recompressed_data_length += fin_fgetc();
|
|
|
|
int decompressed_data_length;
|
|
decompressed_data_length = (fin_fgetc() << 24);
|
|
decompressed_data_length += (fin_fgetc() << 16);
|
|
decompressed_data_length += (fin_fgetc() << 8);
|
|
decompressed_data_length += fin_fgetc();
|
|
|
|
long long recursion_data_length = 0;
|
|
if (recursion_used) {
|
|
recursion_data_length = ((long long)fin_fgetc() << 56);
|
|
recursion_data_length += ((long long)fin_fgetc() << 48);
|
|
recursion_data_length += ((long long)fin_fgetc() << 40);
|
|
recursion_data_length += ((long long)fin_fgetc() << 32);
|
|
recursion_data_length += ((long long)fin_fgetc() << 24);
|
|
recursion_data_length += ((long long)fin_fgetc() << 16);
|
|
recursion_data_length += ((long long)fin_fgetc() << 8);
|
|
recursion_data_length += (long long)fin_fgetc();
|
|
}
|
|
|
|
if (DEBUG_MODE) {
|
|
if (recursion_used) {
|
|
printf("Recursion data length: ");
|
|
print64(recursion_data_length);
|
|
printf("\n");
|
|
} else {
|
|
printf("Recompressed Length: %i - Decompressed length: %i\n", recompressed_data_length, decompressed_data_length);
|
|
}
|
|
}
|
|
|
|
long long old_fout_pos = tell_64(fout);
|
|
|
|
if (recursion_used) {
|
|
recursion_result r = recursion_decompress(recursion_data_length);
|
|
retval = def_part_bzip2(r.frecurse, fout, level, decompressed_data_length, recompressed_data_length);
|
|
safe_fclose(&r.frecurse);
|
|
remove(r.file_name);
|
|
delete[] r.file_name;
|
|
} else {
|
|
retval = def_part_bzip2(fin, fout, level, decompressed_data_length, recompressed_data_length);
|
|
}
|
|
|
|
if (retval != BZ_OK) {
|
|
printf("Error recompressing data!");
|
|
printf("retval = %i\n", retval);
|
|
exit(0);
|
|
}
|
|
|
|
if (penalty_bytes_stored) {
|
|
fflush(fout);
|
|
|
|
long long fsave_fout_pos = tell_64(fout);
|
|
int pb_pos = 0;
|
|
for (int pbc = 0; pbc < penalty_bytes_len; pbc += 5) {
|
|
pb_pos = ((unsigned char)penalty_bytes[pbc]) << 24;
|
|
pb_pos += ((unsigned char)penalty_bytes[pbc + 1]) << 16;
|
|
pb_pos += ((unsigned char)penalty_bytes[pbc + 2]) << 8;
|
|
pb_pos += (unsigned char)penalty_bytes[pbc + 3];
|
|
|
|
seek_64(fout, old_fout_pos + pb_pos);
|
|
own_fwrite(penalty_bytes + pbc + 4, 1, 1, fout);
|
|
}
|
|
|
|
seek_64(fout, fsave_fout_pos);
|
|
}
|
|
} else if (headertype == 10) { // MP3 recompression
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Decompressed data - MP3\n");
|
|
}
|
|
|
|
int recompressed_data_length;
|
|
recompressed_data_length = (fin_fgetc() << 24);
|
|
recompressed_data_length += (fin_fgetc() << 16);
|
|
recompressed_data_length += (fin_fgetc() << 8);
|
|
recompressed_data_length += fin_fgetc();
|
|
|
|
int decompressed_data_length;
|
|
decompressed_data_length = (fin_fgetc() << 24);
|
|
decompressed_data_length += (fin_fgetc() << 16);
|
|
decompressed_data_length += (fin_fgetc() << 8);
|
|
decompressed_data_length += fin_fgetc();
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Recompressed Length: %i - Decompressed length: %i\n", recompressed_data_length, decompressed_data_length);
|
|
}
|
|
|
|
char recompress_msg[256];
|
|
unsigned char* mp3_mem_in = NULL;
|
|
unsigned char* mp3_mem_out = NULL;
|
|
unsigned int mp3_mem_out_size = -1;
|
|
bool in_memory = (recompressed_data_length <= MP3_MAX_MEMORY_SIZE);
|
|
|
|
bool recompress_success = false;
|
|
|
|
if (in_memory) {
|
|
mp3_mem_in = new unsigned char[decompressed_data_length];
|
|
|
|
fast_copy(fin, mp3_mem_in, decompressed_data_length);
|
|
|
|
pmplib_init_streams(mp3_mem_in, 1, decompressed_data_length, mp3_mem_out, 1);
|
|
recompress_success = pmplib_convert_stream2mem(&mp3_mem_out, &mp3_mem_out_size, recompress_msg);
|
|
} else {
|
|
remove(tempfile1);
|
|
ftempout = tryOpen(tempfile1,"wb");
|
|
|
|
fast_copy(fin, ftempout, decompressed_data_length);
|
|
|
|
safe_fclose(&ftempout);
|
|
|
|
remove(tempfile2);
|
|
|
|
recompress_success = pmplib_convert_file2file(tempfile1, tempfile2, recompress_msg);
|
|
}
|
|
|
|
if (!recompress_success) {
|
|
if (DEBUG_MODE) printf ("packMP3 error: %s\n", recompress_msg);
|
|
printf("Error recompressing data!");
|
|
exit(1);
|
|
}
|
|
|
|
if (in_memory) {
|
|
fast_copy(mp3_mem_out, fout, recompressed_data_length);
|
|
|
|
if (mp3_mem_in != NULL) delete[] mp3_mem_in;
|
|
if (mp3_mem_out != NULL) delete[] mp3_mem_out;
|
|
} else {
|
|
frecomp = tryOpen(tempfile2,"rb");
|
|
|
|
fast_copy(frecomp, fout, recompressed_data_length);
|
|
|
|
safe_fclose(&frecomp);
|
|
|
|
remove(tempfile2);
|
|
remove(tempfile1);
|
|
}
|
|
} else if (headertype == 254) { // brute mode recompression
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Decompressed data - brute mode\n");
|
|
}
|
|
|
|
unsigned char header2 = fin_fgetc();
|
|
|
|
bool penalty_bytes_stored = ((header1 & 2) == 2);
|
|
bool recursion_used = ((header1 & 128) == 128);
|
|
int compression_level = (header1 >> 2) & 15;
|
|
int windowbits = -(((header2 >> 4) & 15) + 8);
|
|
int memlevel = header2 & 15;
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Compression level: %i\n", compression_level);
|
|
printf("Window size: %i\n", -windowbits);
|
|
printf("Memory level: %i\n", memlevel);
|
|
}
|
|
|
|
// read penalty bytes
|
|
if (penalty_bytes_stored) {
|
|
penalty_bytes_len = (fin_fgetc() << 24);
|
|
penalty_bytes_len += (fin_fgetc() << 16);
|
|
penalty_bytes_len += (fin_fgetc() << 8);
|
|
penalty_bytes_len += fin_fgetc();
|
|
own_fread(penalty_bytes, 1, penalty_bytes_len, fin);
|
|
}
|
|
|
|
int recompressed_data_length;
|
|
recompressed_data_length = (fin_fgetc() << 24);
|
|
recompressed_data_length += (fin_fgetc() << 16);
|
|
recompressed_data_length += (fin_fgetc() << 8);
|
|
recompressed_data_length += fin_fgetc();
|
|
|
|
int decompressed_data_length;
|
|
decompressed_data_length = (fin_fgetc() << 24);
|
|
decompressed_data_length += (fin_fgetc() << 16);
|
|
decompressed_data_length += (fin_fgetc() << 8);
|
|
decompressed_data_length += fin_fgetc();
|
|
|
|
long long recursion_data_length = 0;
|
|
if (recursion_used) {
|
|
recursion_data_length = ((long long)fin_fgetc() << 56);
|
|
recursion_data_length += ((long long)fin_fgetc() << 48);
|
|
recursion_data_length += ((long long)fin_fgetc() << 40);
|
|
recursion_data_length += ((long long)fin_fgetc() << 32);
|
|
recursion_data_length += ((long long)fin_fgetc() << 24);
|
|
recursion_data_length += ((long long)fin_fgetc() << 16);
|
|
recursion_data_length += ((long long)fin_fgetc() << 8);
|
|
recursion_data_length += (long long)fin_fgetc();
|
|
}
|
|
|
|
if (DEBUG_MODE) {
|
|
if (recursion_used) {
|
|
printf("Recursion data length: ");
|
|
print64(recursion_data_length);
|
|
printf("\n");
|
|
} else {
|
|
printf("Recompressed Length: %i - Decompressed length: %i\n", recompressed_data_length, decompressed_data_length);
|
|
}
|
|
}
|
|
|
|
long long old_fout_pos = tell_64(fout);
|
|
|
|
if (recursion_used) {
|
|
recursion_result r = recursion_decompress(recursion_data_length);
|
|
retval = def_part(r.frecurse, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length);
|
|
safe_fclose(&r.frecurse);
|
|
remove(r.file_name);
|
|
delete[] r.file_name;
|
|
} else {
|
|
retval = def_part(fin, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length);
|
|
}
|
|
|
|
if (retval != Z_OK) {
|
|
printf("Error recompressing data!");
|
|
printf("retval = %i\n", retval);
|
|
exit(0);
|
|
}
|
|
|
|
if (penalty_bytes_stored) {
|
|
fflush(fout);
|
|
|
|
long long fsave_fout_pos = tell_64(fout);
|
|
int pb_pos = 0;
|
|
for (int pbc = 0; pbc < penalty_bytes_len; pbc += 5) {
|
|
pb_pos = ((unsigned char)penalty_bytes[pbc]) << 24;
|
|
pb_pos += ((unsigned char)penalty_bytes[pbc + 1]) << 16;
|
|
pb_pos += ((unsigned char)penalty_bytes[pbc + 2]) << 8;
|
|
pb_pos += (unsigned char)penalty_bytes[pbc + 3];
|
|
|
|
seek_64(fout, old_fout_pos + pb_pos);
|
|
own_fwrite(penalty_bytes + pbc + 4, 1, 1, fout);
|
|
}
|
|
|
|
seek_64(fout, fsave_fout_pos);
|
|
}
|
|
|
|
} else if (headertype == 255) { // raw zLib recompression
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Decompressed data - raw zLib\n");
|
|
}
|
|
|
|
unsigned char header2 = fin_fgetc();
|
|
|
|
bool penalty_bytes_stored = ((header1 & 2) == 2);
|
|
bool recursion_used = ((header1 & 128) == 128);
|
|
int compression_level = (header1 >> 2) & 15;
|
|
int windowbits = -(((header2 >> 4) & 15) + 8);
|
|
int memlevel = header2 & 15;
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Compression level: %i\n", compression_level);
|
|
printf("Window size: %i\n", -windowbits);
|
|
printf("Memory level: %i\n", memlevel);
|
|
}
|
|
|
|
// restore zLib header (decrease by 1)
|
|
own_fread(in, 1, 2, fin);
|
|
unsigned char decchar = *(in + 1) - 1;
|
|
own_fwrite(in, 1, 1, fout);
|
|
fputc(decchar, fout);
|
|
|
|
// read penalty bytes
|
|
if (penalty_bytes_stored) {
|
|
penalty_bytes_len = (fin_fgetc() << 24);
|
|
penalty_bytes_len += (fin_fgetc() << 16);
|
|
penalty_bytes_len += (fin_fgetc() << 8);
|
|
penalty_bytes_len += fin_fgetc();
|
|
own_fread(penalty_bytes, 1, penalty_bytes_len, fin);
|
|
}
|
|
|
|
int recompressed_data_length;
|
|
recompressed_data_length = (fin_fgetc() << 24);
|
|
recompressed_data_length += (fin_fgetc() << 16);
|
|
recompressed_data_length += (fin_fgetc() << 8);
|
|
recompressed_data_length += fin_fgetc();
|
|
|
|
int decompressed_data_length;
|
|
decompressed_data_length = (fin_fgetc() << 24);
|
|
decompressed_data_length += (fin_fgetc() << 16);
|
|
decompressed_data_length += (fin_fgetc() << 8);
|
|
decompressed_data_length += fin_fgetc();
|
|
|
|
long long recursion_data_length = 0;
|
|
if (recursion_used) {
|
|
recursion_data_length = ((long long)fin_fgetc() << 56);
|
|
recursion_data_length += ((long long)fin_fgetc() << 48);
|
|
recursion_data_length += ((long long)fin_fgetc() << 40);
|
|
recursion_data_length += ((long long)fin_fgetc() << 32);
|
|
recursion_data_length += ((long long)fin_fgetc() << 24);
|
|
recursion_data_length += ((long long)fin_fgetc() << 16);
|
|
recursion_data_length += ((long long)fin_fgetc() << 8);
|
|
recursion_data_length += (long long)fin_fgetc();
|
|
}
|
|
|
|
if (DEBUG_MODE) {
|
|
if (recursion_used) {
|
|
printf("Recursion data length: ");
|
|
print64(recursion_data_length);
|
|
printf("\n");
|
|
} else {
|
|
printf("Recompressed Length: %i - Decompressed length: %i\n", recompressed_data_length, decompressed_data_length);
|
|
}
|
|
}
|
|
|
|
long long old_fout_pos = tell_64(fout);
|
|
|
|
if (recursion_used) {
|
|
recursion_result r = recursion_decompress(recursion_data_length);
|
|
retval = def_part(r.frecurse, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length);
|
|
safe_fclose(&r.frecurse);
|
|
remove(r.file_name);
|
|
delete[] r.file_name;
|
|
} else {
|
|
retval = def_part(fin, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length);
|
|
}
|
|
|
|
if (retval != Z_OK) {
|
|
printf("Error recompressing data!");
|
|
printf("retval = %i\n", retval);
|
|
exit(0);
|
|
}
|
|
|
|
if (penalty_bytes_stored) {
|
|
fflush(fout);
|
|
|
|
long long fsave_fout_pos = tell_64(fout);
|
|
|
|
int pb_pos = 0;
|
|
for (int pbc = 0; pbc < penalty_bytes_len; pbc += 5) {
|
|
pb_pos = ((unsigned char)penalty_bytes[pbc]) << 24;
|
|
pb_pos += ((unsigned char)penalty_bytes[pbc + 1]) << 16;
|
|
pb_pos += ((unsigned char)penalty_bytes[pbc + 2]) << 8;
|
|
pb_pos += (unsigned char)penalty_bytes[pbc + 3];
|
|
|
|
seek_64(fout, old_fout_pos + pb_pos);
|
|
own_fwrite(penalty_bytes + pbc + 4, 1, 1, fout);
|
|
}
|
|
|
|
seek_64(fout, fsave_fout_pos);
|
|
}
|
|
} else {
|
|
printf("ERROR: Unsupported stream type %i\n", headertype);
|
|
exit(0);
|
|
}
|
|
|
|
}
|
|
|
|
fin_pos = tell_64(fin);
|
|
if (compression_otf_method != OTF_NONE) {
|
|
if (decompress_otf_end) break;
|
|
if (fin_pos >= fin_length) fin_pos = fin_length - 1;
|
|
}
|
|
}
|
|
|
|
denit_decompress();
|
|
}
|
|
|
|
void convert_file() {
|
|
int bytes_read;
|
|
unsigned char convbuf[COPY_BUF_SIZE];
|
|
int conv_bytes = -1;
|
|
|
|
comp_decomp_state = P_CONVERT;
|
|
|
|
init_compress_otf();
|
|
init_decompress_otf();
|
|
|
|
if (!DEBUG_MODE) show_progress(0, false, false);
|
|
|
|
for (;;) {
|
|
bytes_read = own_fread(copybuf, 1, COPY_BUF_SIZE, fin);
|
|
// truncate by 9 bytes (Precomp on-the-fly delimiter) if converting from compressed data
|
|
if ((conversion_from_method > OTF_NONE) && (bytes_read < COPY_BUF_SIZE)) {
|
|
bytes_read -= 9;
|
|
if (bytes_read < 0) {
|
|
conv_bytes += bytes_read;
|
|
bytes_read = 0;
|
|
}
|
|
}
|
|
if (conv_bytes > -1) own_fwrite(convbuf, 1, conv_bytes, fout);
|
|
for (int i = 0; i < bytes_read; i++) {
|
|
convbuf[i] = copybuf[i];
|
|
}
|
|
conv_bytes = bytes_read;
|
|
if (bytes_read < COPY_BUF_SIZE) {
|
|
break;
|
|
}
|
|
|
|
input_file_pos = tell_64(fin);
|
|
print_work_sign(true);
|
|
if (!DEBUG_MODE) {
|
|
float percent = (input_file_pos / (float)fin_length) * 100;
|
|
show_progress(percent, true, true);
|
|
}
|
|
}
|
|
own_fwrite(convbuf, 1, conv_bytes, fout);
|
|
|
|
denit_compress_otf();
|
|
denit_decompress_otf();
|
|
|
|
denit_convert();
|
|
}
|
|
|
|
int try_to_decompress(FILE* file, int windowbits, int& compressed_stream_size) {
|
|
int r;
|
|
|
|
print_work_sign(true);
|
|
|
|
remove(tempfile1);
|
|
ftempout = tryOpen(tempfile1,"wb");
|
|
if (file == fin) {
|
|
seek_64(file, input_file_pos);
|
|
} else {
|
|
seek_64(file, 0);
|
|
}
|
|
r = inf(file, ftempout, windowbits, compressed_stream_size);
|
|
if (r == Z_OK) {
|
|
fseek(ftempout, 0, SEEK_END);
|
|
r = ftell(ftempout);
|
|
}
|
|
safe_fclose(&ftempout);
|
|
|
|
return r;
|
|
}
|
|
|
|
int try_to_decompress_bzip2(FILE* file, int compression_level, int& compressed_stream_size) {
|
|
int r;
|
|
|
|
print_work_sign(true);
|
|
|
|
remove(tempfile1);
|
|
ftempout = tryOpen(tempfile1,"wb");
|
|
|
|
if (file == fin) {
|
|
seek_64(file, input_file_pos);
|
|
} else {
|
|
seek_64(file, 0);
|
|
}
|
|
|
|
r = inf_bzip2(file, ftempout);
|
|
if (r == Z_OK) {
|
|
fseek(ftempout, 0, SEEK_END);
|
|
r = ftell(ftempout);
|
|
}
|
|
safe_fclose(&ftempout);
|
|
|
|
return r;
|
|
}
|
|
|
|
void try_recompress(FILE* origfile, int comp_level, int mem_level, int windowbits, int& compressed_stream_size) {
|
|
print_work_sign(true);
|
|
|
|
int decomp_bytes_total;
|
|
identical_bytes = file_recompress(origfile, comp_level, windowbits, mem_level, identical_bytes_decomp, decomp_bytes_total);
|
|
if (identical_bytes > -1) { // successfully recompressed?
|
|
if ((identical_bytes > best_identical_bytes) || ((identical_bytes == best_identical_bytes) && (penalty_bytes_len < best_penalty_bytes_len))) {
|
|
if (identical_bytes > min_ident_size) {
|
|
if (DEBUG_MODE) {
|
|
printf("Identical recompressed bytes: %i of %i\n", identical_bytes, compressed_stream_size);
|
|
printf ("Identical decompressed bytes: %i of %i\n", identical_bytes_decomp, decomp_bytes_total);
|
|
}
|
|
|
|
final_compression_found = (identical_bytes_decomp == decomp_bytes_total) && (identical_bytes == compressed_stream_size) && (penalty_bytes_len < PENALTY_BYTES_TOLERANCE);
|
|
}
|
|
|
|
best_identical_bytes_decomp = identical_bytes_decomp;
|
|
best_identical_bytes = identical_bytes;
|
|
best_compression = comp_level;
|
|
best_mem_level = mem_level;
|
|
best_windowbits = windowbits;
|
|
if (penalty_bytes_len > 0) {
|
|
memcpy(best_penalty_bytes, penalty_bytes, penalty_bytes_len);
|
|
best_penalty_bytes_len = penalty_bytes_len;
|
|
} else {
|
|
best_penalty_bytes_len = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void try_recompress_bzip2(FILE* origfile, int level, int& compressed_stream_size) {
|
|
print_work_sign(true);
|
|
|
|
int decomp_bytes_total;
|
|
identical_bytes = file_recompress_bzip2(origfile, level, identical_bytes_decomp, decomp_bytes_total);
|
|
if (identical_bytes > -1) { // successfully recompressed?
|
|
if ((identical_bytes > best_identical_bytes) || ((identical_bytes == best_identical_bytes) && (penalty_bytes_len < best_penalty_bytes_len))) {
|
|
if (identical_bytes > min_ident_size) {
|
|
if (DEBUG_MODE) {
|
|
printf("Identical recompressed bytes: %i of %i\n", identical_bytes, compressed_stream_size);
|
|
printf ("Identical decompressed bytes: %i of %i\n", identical_bytes_decomp, decomp_bytes_total);
|
|
}
|
|
|
|
final_compression_found = (identical_bytes_decomp == decomp_bytes_total) && (identical_bytes == compressed_stream_size) && (penalty_bytes_len < PENALTY_BYTES_TOLERANCE);
|
|
}
|
|
|
|
best_identical_bytes_decomp = identical_bytes_decomp;
|
|
best_identical_bytes = identical_bytes;
|
|
if (penalty_bytes_len > 0) {
|
|
memcpy(best_penalty_bytes, penalty_bytes, penalty_bytes_len);
|
|
best_penalty_bytes_len = penalty_bytes_len;
|
|
} else {
|
|
best_penalty_bytes_len = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void write_header() {
|
|
char* input_file_name_without_path = new char[strlen(input_file_name) + 1];
|
|
|
|
fprintf(fout, "PCF");
|
|
|
|
// version number
|
|
fputc(V_MAJOR, fout);
|
|
fputc(V_MINOR, fout);
|
|
fputc(V_MINOR2, fout);
|
|
|
|
// compression-on-the-fly method used
|
|
fputc(compression_otf_method, fout);
|
|
|
|
// write input file name without path
|
|
char* last_backslash = strrchr(input_file_name, PATH_DELIM);
|
|
if (last_backslash != NULL) {
|
|
strcpy(input_file_name_without_path, last_backslash + 1);
|
|
} else {
|
|
strcpy(input_file_name_without_path, input_file_name);
|
|
}
|
|
|
|
fprintf(fout, "%s", input_file_name_without_path);
|
|
fputc(0, fout);
|
|
|
|
delete[] input_file_name_without_path;
|
|
|
|
// initialize compression-on-the-fly now
|
|
if (compression_otf_method != OTF_NONE) {
|
|
init_compress_otf();
|
|
}
|
|
}
|
|
|
|
#ifdef COMFORT
|
|
bool check_for_pcf_file() {
|
|
seek_64(fin, 0);
|
|
|
|
fread(in, 1, 3, fin);
|
|
if ((in[0] == 'P') && (in[1] == 'C') && (in[2] == 'F')) {
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
fread(in, 1, 3, fin);
|
|
if ((in[0] == V_MAJOR) && (in[1] == V_MINOR) && (in[2] == V_MINOR2)) {
|
|
} else {
|
|
printf("Input file %s was made with a different Precomp version\n", input_file_name);
|
|
printf("PCF version info: %i.%i.%i\n", in[0], in[1], in[2]);
|
|
exit(1);
|
|
}
|
|
|
|
// skip compression method
|
|
fread(in, 1, 1, fin);
|
|
|
|
string header_filename = "";
|
|
char c;
|
|
do {
|
|
c = fgetc(fin);
|
|
if (c != 0) header_filename += c;
|
|
} while (c != 0);
|
|
|
|
// append output filename to the executable directory
|
|
char exec_dir[1024];
|
|
GetModuleFileName(NULL, exec_dir, 1024);
|
|
// truncate to get directory of executable only
|
|
char* lastslash = strrchr(exec_dir, PATH_DELIM) + 1;
|
|
strcpy(lastslash, "");
|
|
header_filename = exec_dir + header_filename;
|
|
|
|
if (output_file_name == NULL) {
|
|
output_file_name = new char[strlen(header_filename.c_str()) + 1];
|
|
strcpy(output_file_name, header_filename.c_str());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
void read_header() {
|
|
seek_64(fin, 0);
|
|
|
|
fread(in, 1, 3, fin);
|
|
if ((in[0] == 'P') && (in[1] == 'C') && (in[2] == 'F')) {
|
|
} else {
|
|
printf("Input file %s has no valid PCF header\n", input_file_name);
|
|
exit(1);
|
|
}
|
|
|
|
fread(in, 1, 3, fin);
|
|
if ((in[0] == V_MAJOR) && (in[1] == V_MINOR) && (in[2] == V_MINOR2)) {
|
|
} else {
|
|
printf("Input file %s was made with a different Precomp version\n", input_file_name);
|
|
printf("PCF version info: %i.%i.%i\n", in[0], in[1], in[2]);
|
|
exit(1);
|
|
}
|
|
|
|
fread(in, 1, 1, fin);
|
|
compression_otf_method = in[0];
|
|
|
|
string header_filename = "";
|
|
char c;
|
|
do {
|
|
c = fgetc(fin);
|
|
if (c != 0) header_filename += c;
|
|
} while (c != 0);
|
|
|
|
if (output_file_name == NULL) {
|
|
output_file_name = new char[strlen(header_filename.c_str()) + 1];
|
|
strcpy(output_file_name, header_filename.c_str());
|
|
}
|
|
}
|
|
|
|
void convert_header() {
|
|
seek_64(fin, 0);
|
|
|
|
fread(in, 1, 3, fin);
|
|
if ((in[0] == 'P') && (in[1] == 'C') && (in[2] == 'F')) {
|
|
} else {
|
|
printf("Input file %s has no valid PCF header\n", input_file_name);
|
|
exit(1);
|
|
}
|
|
fwrite(in, 1, 3, fout);
|
|
|
|
fread(in, 1, 3, fin);
|
|
if ((in[0] == V_MAJOR) && (in[1] == V_MINOR) && (in[2] == V_MINOR2)) {
|
|
} else {
|
|
printf("Input file %s was made with a different Precomp version\n", input_file_name);
|
|
printf("PCF version info: %i.%i.%i\n", in[0], in[1], in[2]);
|
|
exit(1);
|
|
}
|
|
fwrite(in, 1, 3, fout);
|
|
|
|
fread(in, 1, 1, fin);
|
|
conversion_from_method = in[0];
|
|
if (conversion_from_method == conversion_to_method) {
|
|
printf("Input file doesn't need to be converted\n");
|
|
exit(1);
|
|
}
|
|
in[0] = conversion_to_method;
|
|
fwrite(in, 1, 1, fout);
|
|
|
|
string header_filename = "";
|
|
char c;
|
|
do {
|
|
c = fgetc(fin);
|
|
if (c != 0) header_filename += c;
|
|
} while (c != 0);
|
|
fprintf(fout, "%s", header_filename.c_str());
|
|
fputc(0, fout);
|
|
}
|
|
|
|
void progress_update(long long bytes_written) {
|
|
float percent = ((input_file_pos + uncompressed_bytes_written + bytes_written) / ((float)fin_length + uncompressed_bytes_total)) * (global_max_percent - global_min_percent) + global_min_percent;
|
|
show_progress(percent, true, true);
|
|
}
|
|
|
|
void lzma_progress_update() {
|
|
float percent = ((input_file_pos + uncompressed_bytes_written) / ((float)fin_length + uncompressed_bytes_total)) * (global_max_percent - global_min_percent) + global_min_percent;
|
|
|
|
uint64_t progress_in = 0, progress_out = 0;
|
|
|
|
lzma_get_progress(&otf_xz_stream_c, &progress_in, &progress_out);
|
|
|
|
lzma_mib_total = otf_xz_stream_c.total_in / (1024 * 1024);
|
|
lzma_mib_written = progress_in / (1024 * 1024);
|
|
show_progress(percent, true, true);
|
|
}
|
|
|
|
void fast_copy(FILE* file1, FILE* file2, long long bytecount, bool update_progress) {
|
|
if (bytecount == 0) return;
|
|
|
|
long long i;
|
|
int remaining_bytes = (bytecount % COPY_BUF_SIZE);
|
|
long long maxi = (bytecount / COPY_BUF_SIZE);
|
|
|
|
for (i = 1; i <= maxi; i++) {
|
|
own_fread(copybuf, 1, COPY_BUF_SIZE, file1);
|
|
own_fwrite(copybuf, 1, COPY_BUF_SIZE, file2, false, update_progress);
|
|
|
|
if (((i - 1) % FAST_COPY_WORK_SIGN_DIST) == 0) {
|
|
print_work_sign(true);
|
|
if ((update_progress) && (!DEBUG_MODE)) progress_update(i * COPY_BUF_SIZE);
|
|
}
|
|
}
|
|
if (remaining_bytes != 0) {
|
|
own_fread(copybuf, 1, remaining_bytes, file1);
|
|
own_fwrite(copybuf, 1, remaining_bytes, file2, false, update_progress);
|
|
}
|
|
|
|
if ((update_progress) && (!DEBUG_MODE)) uncompressed_bytes_written += bytecount;
|
|
}
|
|
|
|
void fast_copy(FILE* file, unsigned char* mem, long long bytecount) {
|
|
if (bytecount == 0) return;
|
|
|
|
long long i;
|
|
int remaining_bytes = (bytecount % COPY_BUF_SIZE);
|
|
long long maxi = (bytecount / COPY_BUF_SIZE);
|
|
|
|
for (i = 1; i <= maxi; i++) {
|
|
own_fread(mem + (i - 1) * COPY_BUF_SIZE, 1, COPY_BUF_SIZE, file);
|
|
|
|
if (((i - 1) % FAST_COPY_WORK_SIGN_DIST) == 0) print_work_sign(true);
|
|
}
|
|
if (remaining_bytes != 0) {
|
|
own_fread(mem + maxi * COPY_BUF_SIZE, 1, remaining_bytes, file);
|
|
}
|
|
}
|
|
|
|
void fast_copy(unsigned char* mem, FILE* file, long long bytecount) {
|
|
if (bytecount == 0) return;
|
|
|
|
long long i;
|
|
int remaining_bytes = (bytecount % COPY_BUF_SIZE);
|
|
long long maxi = (bytecount / COPY_BUF_SIZE);
|
|
|
|
for (i = 1; i <= maxi; i++) {
|
|
own_fwrite(mem + (i - 1) * COPY_BUF_SIZE, 1, COPY_BUF_SIZE, file);
|
|
|
|
if (((i - 1) % FAST_COPY_WORK_SIGN_DIST) == 0) print_work_sign(true);
|
|
}
|
|
if (remaining_bytes != 0) {
|
|
own_fwrite(mem + maxi * COPY_BUF_SIZE, 1, remaining_bytes, file);
|
|
}
|
|
}
|
|
|
|
size_t own_fwrite(const void *ptr, size_t size, size_t count, FILE* stream, bool final_byte, bool update_lzma_progress) {
|
|
size_t result = 0;
|
|
bool use_otf = false;
|
|
|
|
if (comp_decomp_state == P_CONVERT) {
|
|
use_otf = (conversion_to_method > OTF_NONE);
|
|
if (use_otf) compression_otf_method = conversion_to_method;
|
|
} else {
|
|
if ((stream != fout) || (compression_otf_method == OTF_NONE) || (comp_decomp_state != P_COMPRESS)) {
|
|
use_otf = false;
|
|
} else {
|
|
use_otf = true;
|
|
}
|
|
}
|
|
|
|
if (!use_otf) {
|
|
result = fwrite(ptr, size, count, stream);
|
|
if (result != count) {
|
|
error(ERR_DISK_FULL);
|
|
}
|
|
} else {
|
|
switch (compression_otf_method) {
|
|
case OTF_BZIP2: { // bZip2
|
|
int flush, ret;
|
|
unsigned have;
|
|
|
|
print_work_sign(true);
|
|
|
|
flush = final_byte ? BZ_FINISH : BZ_RUN;
|
|
|
|
otf_bz2_stream_c.avail_in = size * count;
|
|
otf_bz2_stream_c.next_in = (char*)ptr;
|
|
do {
|
|
otf_bz2_stream_c.avail_out = CHUNK;
|
|
otf_bz2_stream_c.next_out = (char*)otf_out;
|
|
ret = BZ2_bzCompress(&otf_bz2_stream_c, flush);
|
|
have = CHUNK - otf_bz2_stream_c.avail_out;
|
|
if (fwrite(otf_out, 1, have, stream) != have || ferror(stream)) {
|
|
result = 0;
|
|
error(ERR_DISK_FULL);
|
|
}
|
|
} while (otf_bz2_stream_c.avail_out == 0);
|
|
if (ret < 0) {
|
|
printf("ERROR: bZip2 compression failed - return value %i\n", ret);
|
|
exit(1);
|
|
}
|
|
result = size * count;
|
|
break;
|
|
}
|
|
case OTF_XZ_MT: {
|
|
lzma_action action = final_byte ? LZMA_FINISH : LZMA_RUN;
|
|
lzma_ret ret;
|
|
unsigned have;
|
|
|
|
otf_xz_stream_c.avail_in = size * count;
|
|
otf_xz_stream_c.next_in = (uint8_t *)ptr;
|
|
do {
|
|
print_work_sign(true);
|
|
otf_xz_stream_c.avail_out = CHUNK;
|
|
otf_xz_stream_c.next_out = (uint8_t *)otf_out;
|
|
ret = lzma_code(&otf_xz_stream_c, action);
|
|
have = CHUNK - otf_xz_stream_c.avail_out;
|
|
if (fwrite(otf_out, 1, have, stream) != have || ferror(stream)) {
|
|
result = 0;
|
|
error(ERR_DISK_FULL);
|
|
}
|
|
if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
|
|
const char *msg;
|
|
switch (ret) {
|
|
case LZMA_MEM_ERROR:
|
|
msg = "Memory allocation failed";
|
|
break;
|
|
|
|
case LZMA_DATA_ERROR:
|
|
msg = "File size limits exceeded";
|
|
break;
|
|
|
|
default:
|
|
msg = "Unknown error, possibly a bug";
|
|
break;
|
|
}
|
|
|
|
printf("ERROR: liblzma error: %s (error code %u)\n", msg, ret);
|
|
#ifdef COMFORT
|
|
wait_for_key();
|
|
#endif // COMFORT
|
|
exit(1);
|
|
} // .avail_out == 0
|
|
if ((!DEBUG_MODE) && (update_lzma_progress)) lzma_progress_update();
|
|
} while ((otf_xz_stream_c.avail_in > 0) || (final_byte && (ret != LZMA_STREAM_END)));
|
|
result = size * count;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
size_t own_fread(void *ptr, size_t size, size_t count, FILE* stream) {
|
|
bool use_otf = false;
|
|
|
|
if (comp_decomp_state == P_CONVERT) {
|
|
use_otf = (conversion_from_method > OTF_NONE);
|
|
if (use_otf) compression_otf_method = conversion_from_method;
|
|
} else {
|
|
if ((stream != fin) || (compression_otf_method == OTF_NONE) || (comp_decomp_state != P_DECOMPRESS)) {
|
|
use_otf = false;
|
|
} else {
|
|
use_otf = true;
|
|
}
|
|
}
|
|
|
|
if (!use_otf) {
|
|
return fread(ptr, size, count, stream);
|
|
} else {
|
|
switch (compression_otf_method) {
|
|
case 1: { // bZip2
|
|
int ret;
|
|
int bytes_read = 0;
|
|
|
|
print_work_sign(true);
|
|
|
|
otf_bz2_stream_d.avail_out = size * count;
|
|
otf_bz2_stream_d.next_out = (char*)ptr;
|
|
|
|
do {
|
|
|
|
if (otf_bz2_stream_d.avail_in == 0) {
|
|
otf_bz2_stream_d.avail_in = fread(otf_in, 1, CHUNK, fin);
|
|
otf_bz2_stream_d.next_in = (char*)otf_in;
|
|
if (otf_bz2_stream_d.avail_in == 0) break;
|
|
}
|
|
|
|
ret = BZ2_bzDecompress(&otf_bz2_stream_d);
|
|
if ((ret != BZ_OK) && (ret != BZ_STREAM_END)) {
|
|
(void)BZ2_bzDecompressEnd(&otf_bz2_stream_d);
|
|
printf("ERROR: bZip2 stream corrupted - return value %i\n", ret);
|
|
exit(1);
|
|
}
|
|
|
|
if (ret == BZ_STREAM_END) decompress_otf_end = true;
|
|
|
|
} while (otf_bz2_stream_d.avail_out > 0);
|
|
|
|
bytes_read = (size * count - otf_bz2_stream_d.avail_out);
|
|
|
|
return bytes_read;
|
|
}
|
|
case OTF_XZ_MT: {
|
|
lzma_action action = LZMA_RUN;
|
|
lzma_ret ret;
|
|
|
|
otf_xz_stream_d.avail_out = size * count;
|
|
otf_xz_stream_d.next_out = (uint8_t *)ptr;
|
|
|
|
do {
|
|
print_work_sign(true);
|
|
if ((otf_xz_stream_d.avail_in == 0) && !feof(fin)) {
|
|
otf_xz_stream_d.next_in = (uint8_t *)otf_in;
|
|
otf_xz_stream_d.avail_in = fread(otf_in, 1, CHUNK, fin);
|
|
|
|
if (ferror(fin)) {
|
|
printf("ERROR: Could not read input file\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
ret = lzma_code(&otf_xz_stream_d, action);
|
|
|
|
if (ret == LZMA_STREAM_END) {
|
|
decompress_otf_end = true;
|
|
break;
|
|
}
|
|
|
|
if (ret != LZMA_OK) {
|
|
const char *msg;
|
|
switch (ret) {
|
|
case LZMA_MEM_ERROR:
|
|
msg = "Memory allocation failed";
|
|
break;
|
|
case LZMA_FORMAT_ERROR:
|
|
msg = "Wrong file format";
|
|
break;
|
|
case LZMA_OPTIONS_ERROR:
|
|
msg = "Unsupported compression options";
|
|
break;
|
|
case LZMA_DATA_ERROR:
|
|
case LZMA_BUF_ERROR:
|
|
msg = "Compressed file is corrupt";
|
|
break;
|
|
default:
|
|
msg = "Unknown error, possibly a bug";
|
|
break;
|
|
}
|
|
|
|
printf("ERROR: liblzma error: %s (error code %u)\n", msg, ret);
|
|
#ifdef COMFORT
|
|
wait_for_key();
|
|
#endif // COMFORT
|
|
exit(1);
|
|
}
|
|
} while (otf_xz_stream_d.avail_out > 0);
|
|
|
|
return size * count - otf_xz_stream_d.avail_out;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void seek_64(FILE* f, unsigned long long pos) {
|
|
#ifndef UNIX
|
|
fpos_t fpt_pos = pos;
|
|
fsetpos(f, &fpt_pos);
|
|
#else
|
|
fseeko(f, pos, SEEK_SET);
|
|
#endif
|
|
}
|
|
|
|
unsigned long long tell_64(FILE* f) {
|
|
#ifndef UNIX
|
|
fpos_t fpt_pos;
|
|
fgetpos(f, &fpt_pos);
|
|
return fpt_pos;
|
|
#else
|
|
return ftello(f);
|
|
#endif
|
|
}
|
|
|
|
bool file_exists(char* filename) {
|
|
fstream fin;
|
|
bool retval = false;
|
|
|
|
fin.open(filename, ios::in);
|
|
retval = fin.is_open();
|
|
fin.close();
|
|
|
|
return retval;
|
|
}
|
|
|
|
long long compare_files_penalty(FILE* file1, FILE* file2, long long pos1, long long pos2) {
|
|
unsigned char input_bytes1[COMP_CHUNK];
|
|
unsigned char input_bytes2[COMP_CHUNK];
|
|
long long same_byte_count = 0;
|
|
long long same_byte_count_penalty = 0;
|
|
long long rek_same_byte_count = 0;
|
|
long long rek_same_byte_count_penalty = -1;
|
|
long long size1, size2, minsize;
|
|
long long i;
|
|
bool endNow = false;
|
|
|
|
unsigned int local_penalty_bytes_len = 0;
|
|
|
|
unsigned int rek_penalty_bytes_len = 0;
|
|
bool use_penalty_bytes = false;
|
|
|
|
long long compare_end;
|
|
if (file1 == fin) {
|
|
fseek(file2, 0, SEEK_END);
|
|
compare_end = ftell(file2);
|
|
} else {
|
|
fseek(file1, 0, SEEK_END);
|
|
fseek(file2, 0, SEEK_END);
|
|
compare_end = min(ftell(file1), ftell(file2));
|
|
}
|
|
|
|
seek_64(file1, pos1);
|
|
seek_64(file2, pos2);
|
|
|
|
do {
|
|
print_work_sign(true);
|
|
|
|
size1 = own_fread(input_bytes1, 1, COMP_CHUNK, file1);
|
|
size2 = own_fread(input_bytes2, 1, COMP_CHUNK, file2);
|
|
|
|
minsize = min(size1, size2);
|
|
for (i = 0; i < minsize; i++) {
|
|
if (input_bytes1[i] != input_bytes2[i]) {
|
|
|
|
same_byte_count_penalty -= 5; // 4 bytes = position, 1 byte = new byte
|
|
|
|
// if same_byte_count_penalty is too low, stop
|
|
if ((long long)(same_byte_count_penalty + (compare_end - same_byte_count)) < 0) {
|
|
endNow = true;
|
|
break;
|
|
}
|
|
// stop, if local_penalty_bytes_len gets too big
|
|
if ((local_penalty_bytes_len + 5) >= MAX_PENALTY_BYTES) {
|
|
endNow = true;
|
|
break;
|
|
}
|
|
|
|
local_penalty_bytes_len += 5;
|
|
// position
|
|
local_penalty_bytes[local_penalty_bytes_len-5] = (same_byte_count >> 24) % 256;
|
|
local_penalty_bytes[local_penalty_bytes_len-4] = (same_byte_count >> 16) % 256;
|
|
local_penalty_bytes[local_penalty_bytes_len-3] = (same_byte_count >> 8) % 256;
|
|
local_penalty_bytes[local_penalty_bytes_len-2] = same_byte_count % 256;
|
|
// new byte
|
|
local_penalty_bytes[local_penalty_bytes_len-1] = input_bytes1[i];
|
|
} else {
|
|
same_byte_count_penalty++;
|
|
}
|
|
|
|
same_byte_count++;
|
|
|
|
if (same_byte_count_penalty > rek_same_byte_count_penalty) {
|
|
|
|
use_penalty_bytes = true;
|
|
rek_penalty_bytes_len = local_penalty_bytes_len;
|
|
|
|
rek_same_byte_count = same_byte_count;
|
|
rek_same_byte_count_penalty = same_byte_count_penalty;
|
|
}
|
|
|
|
}
|
|
} while ((minsize == COMP_CHUNK) && (!endNow));
|
|
|
|
if ((rek_penalty_bytes_len > 0) && (use_penalty_bytes)) {
|
|
memcpy(penalty_bytes, local_penalty_bytes, rek_penalty_bytes_len);
|
|
penalty_bytes_len = rek_penalty_bytes_len;
|
|
} else {
|
|
penalty_bytes_len = 0;
|
|
}
|
|
|
|
return rek_same_byte_count;
|
|
}
|
|
|
|
void try_decompression_gzip(int gzip_header_length) {
|
|
init_decompression_variables();
|
|
|
|
int windowbits;
|
|
|
|
// try to decompress at current position
|
|
int compressed_stream_size = -1;
|
|
retval = try_to_decompress(fin, -15, compressed_stream_size);
|
|
|
|
if (retval > 0) { // seems to be a zLib-Stream
|
|
|
|
decompressed_streams_count++;
|
|
decompressed_gzip_count++;
|
|
|
|
if (DEBUG_MODE) {
|
|
print_debug_percent();
|
|
printf ("Possible zLib-Stream in GZip found at position ");
|
|
print64(saved_input_file_pos);
|
|
printf("\n");
|
|
printf("Compressed size: %i\n", compressed_stream_size);
|
|
|
|
ftempout = tryOpen(tempfile1, "rb");
|
|
fseek(ftempout, 0, SEEK_END);
|
|
printf ("Can be decompressed to %li bytes\n", ftell(ftempout));
|
|
safe_fclose(&ftempout);
|
|
}
|
|
|
|
for (windowbits = -15; windowbits < -7; windowbits++) {
|
|
for (int index = 0; index < 81; index++) {
|
|
if (levels_sorted[index] == -1) break;
|
|
int comp_level = (levels_sorted[index] % 9) + 1;
|
|
int mem_level = (levels_sorted[index] / 9) + 1;
|
|
|
|
try_recompress(fin, comp_level, mem_level, windowbits, compressed_stream_size);
|
|
|
|
if (final_compression_found) break;
|
|
}
|
|
if (final_compression_found) break;
|
|
}
|
|
|
|
if ((best_identical_bytes > min_ident_size) && (best_identical_bytes < best_identical_bytes_decomp)) {
|
|
recompressed_streams_count++;
|
|
recompressed_gzip_count++;
|
|
|
|
windowbits = best_windowbits;
|
|
if (DEBUG_MODE) {
|
|
printf("Best match with level combination %i%i, windowbits = %i: %i bytes, decompressed to %i bytes\n", best_compression, best_mem_level, -windowbits, best_identical_bytes, best_identical_bytes_decomp);
|
|
}
|
|
|
|
if (!(comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9] == -1)) {
|
|
if (fast_mode) {
|
|
comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++;
|
|
zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true;
|
|
for (int i = 0; i < 81; i++) {
|
|
if (i != ((best_compression - 1) + (best_mem_level - 1) * 9)) {
|
|
comp_mem_level_count[i] = -1;
|
|
}
|
|
}
|
|
anything_was_used = true;
|
|
sort_comp_mem_levels();
|
|
} else {
|
|
comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++;
|
|
zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true;
|
|
anything_was_used = true;
|
|
sort_comp_mem_levels();
|
|
}
|
|
}
|
|
|
|
// end uncompressed data
|
|
|
|
compressed_data_found = true;
|
|
end_uncompressed_data();
|
|
|
|
// check recursion
|
|
recursion_result r = recursion_compress(best_identical_bytes, best_identical_bytes_decomp);
|
|
|
|
// write compressed data header (GZip) without 2 first bytes
|
|
|
|
int header_byte = 1 + (best_compression << 2);
|
|
if (best_penalty_bytes_len != 0) {
|
|
header_byte += 2;
|
|
}
|
|
if (r.success) {
|
|
header_byte += 128;
|
|
}
|
|
fout_fputc(header_byte);
|
|
fout_fputc(2); // GZip
|
|
fout_fputc((((-windowbits) - 8) << 4) + best_mem_level);
|
|
|
|
gzip_header_length -= 2;
|
|
|
|
fout_fput24(gzip_header_length);
|
|
|
|
own_fwrite(in_buf + cb + 2, 1, gzip_header_length, fout);
|
|
|
|
// store penalty bytes, if any
|
|
if (best_penalty_bytes_len != 0) {
|
|
if (DEBUG_MODE) {
|
|
printf("Penalty bytes were used: %i bytes\n", best_penalty_bytes_len);
|
|
}
|
|
fout_fput32(best_penalty_bytes_len);
|
|
for (int pbc = 0; pbc < best_penalty_bytes_len; pbc++) {
|
|
fout_fputc(best_penalty_bytes[pbc]);
|
|
}
|
|
}
|
|
|
|
fout_fput32(best_identical_bytes);
|
|
fout_fput32(best_identical_bytes_decomp);
|
|
|
|
if (r.success) {
|
|
fout_fput64(r.file_length);
|
|
}
|
|
|
|
// write decompressed data
|
|
if (r.success) {
|
|
write_decompressed_data(r.file_length, r.file_name);
|
|
remove(r.file_name);
|
|
delete[] r.file_name;
|
|
} else {
|
|
write_decompressed_data(best_identical_bytes_decomp);
|
|
}
|
|
|
|
// start new uncompressed data
|
|
|
|
// set input file pointer after recompressed data
|
|
input_file_pos += best_identical_bytes - 1;
|
|
cb += best_identical_bytes - 1;
|
|
|
|
} else {
|
|
if (brute_mode_is_active()) brute_ignore_offsets->insert(input_file_pos);
|
|
if (DEBUG_MODE) {
|
|
printf("No matches\n");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void try_decompression_png (int windowbits) {
|
|
init_decompression_variables();
|
|
|
|
// try to decompress at current position
|
|
int compressed_stream_size = -1;
|
|
retval = try_to_decompress(fin, windowbits, compressed_stream_size);
|
|
|
|
if (retval > 0) { // seems to be a zLib-Stream
|
|
|
|
decompressed_streams_count++;
|
|
decompressed_png_count++;
|
|
|
|
if (DEBUG_MODE) {
|
|
print_debug_percent();
|
|
printf ("Possible zLib-Stream in PNG found at position ");
|
|
print64(saved_input_file_pos);
|
|
printf(", windowbits = %i\n", -windowbits);
|
|
printf("Compressed size: %i\n", compressed_stream_size);
|
|
|
|
ftempout = tryOpen(tempfile1, "rb");
|
|
fseek(ftempout, 0, SEEK_END);
|
|
printf ("Can be decompressed to %li bytes\n", ftell(ftempout));
|
|
safe_fclose(&ftempout);
|
|
}
|
|
|
|
for (int index = 0; index < 81; index++) {
|
|
if (levels_sorted[index] == -1) break;
|
|
int comp_level = (levels_sorted[index] % 9) + 1;
|
|
int mem_level = (levels_sorted[index] / 9) + 1;
|
|
|
|
try_recompress(fin, comp_level, mem_level, windowbits, compressed_stream_size);
|
|
|
|
if (final_compression_found) break;
|
|
}
|
|
|
|
if ((best_identical_bytes > min_ident_size) && (best_identical_bytes < best_identical_bytes_decomp)) {
|
|
recompressed_streams_count++;
|
|
recompressed_png_count++;
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Best match with level combination %i%i: %i bytes, decompressed to %i bytes\n", best_compression, best_mem_level, best_identical_bytes, best_identical_bytes_decomp);
|
|
}
|
|
|
|
if (!(comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9] == -1)) {
|
|
if (fast_mode) {
|
|
comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++;
|
|
zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true;
|
|
for (int i = 0; i < 81; i++) {
|
|
if (i != ((best_compression - 1) + (best_mem_level - 1) * 9)) {
|
|
comp_mem_level_count[i] = -1;
|
|
}
|
|
}
|
|
anything_was_used = true;
|
|
sort_comp_mem_levels();
|
|
} else {
|
|
comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++;
|
|
zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true;
|
|
anything_was_used = true;
|
|
sort_comp_mem_levels();
|
|
}
|
|
}
|
|
|
|
// end uncompressed data
|
|
|
|
compressed_data_found = true;
|
|
end_uncompressed_data();
|
|
|
|
// write compressed data header (PNG)
|
|
|
|
if (best_penalty_bytes_len == 0) {
|
|
fout_fputc(1 + (best_compression << 2));
|
|
} else {
|
|
fout_fputc(1 + 2 + (best_compression << 2));
|
|
}
|
|
fout_fputc(3); // PNG
|
|
fout_fputc((((-windowbits) - 8) << 4) + best_mem_level);
|
|
|
|
// store zLib header, but increased by 1 to prevent finding it
|
|
// again in the next pass
|
|
own_fwrite(zlib_header, 1, 1, fout);
|
|
unsigned char incchar = *(zlib_header + 1) + 1;
|
|
fout_fputc(incchar);
|
|
|
|
// store penalty bytes, if any
|
|
if (best_penalty_bytes_len != 0) {
|
|
if (DEBUG_MODE) {
|
|
printf("Penalty bytes were used: %i bytes\n", best_penalty_bytes_len);
|
|
}
|
|
fout_fput32(best_penalty_bytes_len);
|
|
for (int pbc = 0; pbc < best_penalty_bytes_len; pbc++) {
|
|
fout_fputc(best_penalty_bytes[pbc]);
|
|
}
|
|
}
|
|
|
|
fout_fput32(best_identical_bytes);
|
|
fout_fput32(best_identical_bytes_decomp);
|
|
|
|
// write decompressed data
|
|
|
|
write_decompressed_data(best_identical_bytes_decomp);
|
|
|
|
// start new uncompressed data
|
|
|
|
// set input file pointer after recompressed data
|
|
input_file_pos += best_identical_bytes - 1;
|
|
cb += best_identical_bytes - 1;
|
|
|
|
} else {
|
|
if (intense_mode_is_active()) intense_ignore_offsets->insert(input_file_pos - 2);
|
|
if (brute_mode_is_active()) brute_ignore_offsets->insert(input_file_pos);
|
|
if (DEBUG_MODE) {
|
|
printf("No matches\n");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void try_decompression_png_multi(int windowbits) {
|
|
init_decompression_variables();
|
|
|
|
// try to decompress at current position
|
|
int compressed_stream_size = -1;
|
|
retval = try_to_decompress(fpng, windowbits, compressed_stream_size);
|
|
|
|
if (retval > 0) { // seems to be a zLib-Stream
|
|
|
|
decompressed_streams_count++;
|
|
decompressed_png_multi_count++;
|
|
|
|
if (DEBUG_MODE) {
|
|
print_debug_percent();
|
|
printf("Possible zLib-Stream in multiPNG found at position ");
|
|
print64(saved_input_file_pos);
|
|
printf(", windowbits = %i\n", -windowbits);
|
|
printf("Compressed size: %i\n", compressed_stream_size);
|
|
|
|
ftempout = tryOpen(tempfile1, "rb");
|
|
fseek(ftempout, 0, SEEK_END);
|
|
printf ("Can be decompressed to %li bytes\n", ftell(ftempout));
|
|
safe_fclose(&ftempout);
|
|
}
|
|
|
|
for (int index = 0; index < 81; index++) {
|
|
if (levels_sorted[index] == -1) break;
|
|
int comp_level = (levels_sorted[index] % 9) + 1;
|
|
int mem_level = (levels_sorted[index] / 9) + 1;
|
|
|
|
try_recompress(fpng, comp_level, mem_level, windowbits, compressed_stream_size);
|
|
|
|
if (final_compression_found) break;
|
|
}
|
|
|
|
if ((best_identical_bytes > min_ident_size) && (best_identical_bytes < best_identical_bytes_decomp)) {
|
|
recompressed_streams_count++;
|
|
recompressed_png_multi_count++;
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Best match with level combination %i%i: %i bytes, decompressed to %i bytes\n", best_compression, best_mem_level, best_identical_bytes, best_identical_bytes_decomp);
|
|
}
|
|
|
|
if (!(comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9] == -1)) {
|
|
if (fast_mode) {
|
|
comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++;
|
|
zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true;
|
|
for (int i = 0; i < 81; i++) {
|
|
if (i != ((best_compression - 1) + (best_mem_level - 1) * 9)) {
|
|
comp_mem_level_count[i] = -1;
|
|
}
|
|
}
|
|
anything_was_used = true;
|
|
sort_comp_mem_levels();
|
|
} else {
|
|
comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++;
|
|
zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true;
|
|
anything_was_used = true;
|
|
sort_comp_mem_levels();
|
|
}
|
|
}
|
|
|
|
// end uncompressed data
|
|
|
|
compressed_data_found = true;
|
|
end_uncompressed_data();
|
|
|
|
// write compressed data header (PNG)
|
|
|
|
if (best_penalty_bytes_len == 0) {
|
|
fout_fputc(1 + (best_compression << 2));
|
|
} else {
|
|
fout_fputc(1 + 2 + (best_compression << 2));
|
|
}
|
|
fout_fputc(4); // PNG multi
|
|
fout_fputc((((-windowbits) - 8) << 4) + best_mem_level);
|
|
|
|
// store zLib header, but increased by 1 to prevent finding it
|
|
// again in the next pass
|
|
own_fwrite(zlib_header, 1, 1, fout);
|
|
unsigned char incchar = *(zlib_header + 1) + 1;
|
|
fout_fputc(incchar);
|
|
|
|
// simulate IDAT write to get IDAT pairs count
|
|
int i = 1;
|
|
int idat_pos = idat_lengths[0] - 2;
|
|
unsigned int idat_pairs_written_count = 0;
|
|
if (idat_pos <= best_identical_bytes) {
|
|
do {
|
|
idat_pairs_written_count++;
|
|
|
|
idat_pos += idat_lengths[i];
|
|
if (idat_pos > best_identical_bytes) break;
|
|
|
|
i++;
|
|
} while (i < idat_count);
|
|
}
|
|
// store IDAT pairs count
|
|
fout_fput16(idat_pairs_written_count);
|
|
|
|
// store IDAT CRCs and lengths
|
|
fout_fput32(idat_lengths[0]);
|
|
|
|
// store IDAT CRCs and lengths
|
|
i = 1;
|
|
idat_pos = idat_lengths[0] - 2;
|
|
idat_pairs_written_count = 0;
|
|
if (idat_pos <= best_identical_bytes) {
|
|
do {
|
|
fout_fput32(idat_crcs[i]);
|
|
fout_fput32(idat_lengths[i]);
|
|
|
|
idat_pairs_written_count++;
|
|
|
|
idat_pos += idat_lengths[i];
|
|
if (idat_pos > best_identical_bytes) break;
|
|
|
|
i++;
|
|
} while (i < idat_count);
|
|
}
|
|
|
|
// store penalty bytes, if any
|
|
if (best_penalty_bytes_len != 0) {
|
|
if (DEBUG_MODE) {
|
|
printf("Penalty bytes were used: %i bytes\n", best_penalty_bytes_len);
|
|
}
|
|
fout_fput32(best_penalty_bytes_len);
|
|
for (int pbc = 0; pbc < best_penalty_bytes_len; pbc++) {
|
|
fout_fputc(best_penalty_bytes[pbc]);
|
|
}
|
|
}
|
|
|
|
fout_fput32(best_identical_bytes);
|
|
fout_fput32(best_identical_bytes_decomp);
|
|
|
|
// write decompressed data
|
|
|
|
write_decompressed_data(best_identical_bytes_decomp);
|
|
|
|
// start new uncompressed data
|
|
|
|
// set input file pointer after recompressed data
|
|
input_file_pos += best_identical_bytes - 1;
|
|
cb += best_identical_bytes - 1;
|
|
// now add IDAT chunk overhead
|
|
input_file_pos += (idat_pairs_written_count * 12);
|
|
cb += (idat_pairs_written_count * 12);
|
|
|
|
} else {
|
|
if (intense_mode_is_active()) intense_ignore_offsets->insert(input_file_pos - 2);
|
|
if (brute_mode_is_active()) brute_ignore_offsets->insert(input_file_pos);
|
|
if (DEBUG_MODE) {
|
|
printf("No matches\n");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// GIF functions
|
|
|
|
bool newgif_may_write;
|
|
FILE* frecompress_gif = NULL;
|
|
FILE* freadfunc = NULL;
|
|
|
|
int readFunc(GifFileType* GifFile, GifByteType* buf, int count)
|
|
{
|
|
return own_fread(buf, 1, count, freadfunc);
|
|
}
|
|
|
|
int writeFunc(GifFileType* GifFile, const GifByteType* buf, int count)
|
|
{
|
|
if (newgif_may_write) {
|
|
return own_fwrite(buf, 1, count, frecompress_gif);
|
|
} else {
|
|
return count;
|
|
}
|
|
}
|
|
|
|
void CopyLine(void* dst, void* src, int count)
|
|
{
|
|
do
|
|
{
|
|
*(short*) dst = *(short*) src;
|
|
src = (unsigned char*)src + 2;
|
|
dst = (unsigned char*)dst + 2;
|
|
count -= 2;
|
|
}
|
|
while (count > 0);
|
|
}
|
|
|
|
int DGifGetLineByte(GifFileType *GifFile, GifPixelType *Line, int LineLen, GifCodeStruct *g)
|
|
{
|
|
GifPixelType* LineBuf = new GifPixelType[LineLen];
|
|
CopyLine(LineBuf, Line, LineLen);
|
|
int result = DGifGetLine(GifFile, LineBuf, g, LineLen);
|
|
CopyLine(Line, LineBuf, LineLen);
|
|
delete[] LineBuf;
|
|
|
|
return result;
|
|
}
|
|
|
|
bool recompress_gif(FILE* srcfile, FILE* dstfile, unsigned char block_size, GifCodeStruct* g, GifDiffStruct* gd) {
|
|
int i, j;
|
|
long long last_pos = -1;
|
|
int Row, Col, Width, Height, ExtCode;
|
|
long long src_pos, init_src_pos;
|
|
|
|
GifFileType* myGifFile;
|
|
GifFileType* newGifFile;
|
|
GifRecordType RecordType;
|
|
GifByteType *Extension;
|
|
|
|
freadfunc = srcfile;
|
|
frecompress_gif = dstfile;
|
|
newgif_may_write = false;
|
|
|
|
init_src_pos = tell_64(srcfile);
|
|
|
|
myGifFile = DGifOpenPCF(NULL, readFunc);
|
|
if (myGifFile == NULL) {
|
|
return false;
|
|
}
|
|
|
|
newGifFile = EGifOpen(NULL, writeFunc);
|
|
|
|
newGifFile->BlockSize = block_size;
|
|
|
|
unsigned char** ScreenBuff;
|
|
|
|
if (newGifFile == NULL) {
|
|
return false;
|
|
}
|
|
|
|
ScreenBuff = new unsigned char*[myGifFile->SHeight];
|
|
for (i = 0; i < myGifFile->SHeight; i++) {
|
|
ScreenBuff[i] = new unsigned char[myGifFile->SWidth];
|
|
}
|
|
|
|
for (i = 0; i < myGifFile->SWidth; i++) /* Set its color to BackGround. */
|
|
ScreenBuff[0][i] = myGifFile->SBackGroundColor;
|
|
for (i = 1; i < myGifFile->SHeight; i++) {
|
|
memcpy(ScreenBuff[i], ScreenBuff[0], myGifFile->SWidth);
|
|
}
|
|
|
|
EGifPutScreenDesc(newGifFile, myGifFile->SWidth, myGifFile->SHeight, myGifFile->SColorResolution, myGifFile->SBackGroundColor, myGifFile->SPixelAspectRatio, myGifFile->SColorMap);
|
|
|
|
do {
|
|
if (DGifGetRecordType(myGifFile, &RecordType) == GIF_ERROR) {
|
|
for (i = 0; i < myGifFile->SHeight; i++) {
|
|
delete[] ScreenBuff[i];
|
|
}
|
|
delete[] ScreenBuff;
|
|
DGifCloseFile(myGifFile);
|
|
EGifCloseFile(newGifFile);
|
|
return false;
|
|
}
|
|
|
|
switch (RecordType) {
|
|
case IMAGE_DESC_RECORD_TYPE:
|
|
if (DGifGetImageDesc(myGifFile) == GIF_ERROR) {
|
|
for (i = 0; i < myGifFile->SHeight; i++) {
|
|
delete[] ScreenBuff[i];
|
|
}
|
|
delete[] ScreenBuff;
|
|
DGifCloseFile(myGifFile);
|
|
EGifCloseFile(newGifFile);
|
|
return false;
|
|
}
|
|
|
|
src_pos = tell_64(srcfile);
|
|
if (last_pos != src_pos) {
|
|
if (last_pos == -1) {
|
|
seek_64(srcfile, init_src_pos);
|
|
fast_copy(srcfile, dstfile, src_pos - init_src_pos);
|
|
seek_64(srcfile, src_pos);
|
|
|
|
long long dstfile_pos = tell_64(dstfile);
|
|
seek_64(dstfile, 0);
|
|
// change PGF8xa to GIF8xa
|
|
fputc('G', dstfile);
|
|
fputc('I', dstfile);
|
|
seek_64(dstfile, dstfile_pos);
|
|
} else {
|
|
seek_64(srcfile, last_pos);
|
|
fast_copy(srcfile, dstfile, src_pos - last_pos);
|
|
seek_64(srcfile, src_pos);
|
|
}
|
|
}
|
|
|
|
Row = myGifFile->Image.Top; /* Image Position relative to Screen. */
|
|
Col = myGifFile->Image.Left;
|
|
Width = myGifFile->Image.Width;
|
|
Height = myGifFile->Image.Height;
|
|
|
|
for (i = Row; i < (Row + Height); i++) {
|
|
own_fread(&ScreenBuff[i][Col], 1, Width, srcfile);
|
|
}
|
|
|
|
// this does send a clear code, so we pass g and gd
|
|
if (EGifPutImageDesc(newGifFile, g, gd, Row, Col, Width, Height, myGifFile->Image.Interlace, myGifFile->Image.ColorMap) == GIF_ERROR) {
|
|
for (i = 0; i < myGifFile->SHeight; i++) {
|
|
delete[] ScreenBuff[i];
|
|
}
|
|
delete[] ScreenBuff;
|
|
DGifCloseFile(myGifFile);
|
|
EGifCloseFile(newGifFile);
|
|
return false;
|
|
}
|
|
|
|
newgif_may_write = true;
|
|
|
|
if (myGifFile->Image.Interlace) {
|
|
for (i = 0; i < 4; i++) {
|
|
for (j = Row + InterlacedOffset[i]; j < (Row + Height); j += InterlacedJumps[i]) {
|
|
EGifPutLine(newGifFile, &ScreenBuff[j][Col], g, gd, Width);
|
|
}
|
|
}
|
|
} else {
|
|
for (i = Row; i < (Row + Height); i++) {
|
|
EGifPutLine(newGifFile, &ScreenBuff[i][Col], g, gd, Width);
|
|
}
|
|
}
|
|
|
|
newgif_may_write = false;
|
|
|
|
last_pos = tell_64(srcfile);
|
|
|
|
break;
|
|
case EXTENSION_RECORD_TYPE:
|
|
/* Skip any extension blocks in file: */
|
|
|
|
if (DGifGetExtension(myGifFile, &ExtCode, &Extension) == GIF_ERROR) {
|
|
for (i = 0; i < myGifFile->SHeight; i++) {
|
|
delete[] ScreenBuff[i];
|
|
}
|
|
delete[] ScreenBuff;
|
|
DGifCloseFile(myGifFile);
|
|
EGifCloseFile(newGifFile);
|
|
return false;
|
|
}
|
|
while (Extension != NULL) {
|
|
if (DGifGetExtensionNext(myGifFile, &Extension) == GIF_ERROR) {
|
|
for (i = 0; i < myGifFile->SHeight; i++) {
|
|
delete[] ScreenBuff[i];
|
|
}
|
|
delete[] ScreenBuff;
|
|
DGifCloseFile(myGifFile);
|
|
EGifCloseFile(newGifFile);
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
case TERMINATE_RECORD_TYPE:
|
|
break;
|
|
default: /* Should be traps by DGifGetRecordType. */
|
|
break;
|
|
}
|
|
} while (RecordType != TERMINATE_RECORD_TYPE);
|
|
|
|
src_pos = tell_64(srcfile);
|
|
if (last_pos != src_pos) {
|
|
seek_64(srcfile, last_pos);
|
|
fast_copy(srcfile, dstfile, src_pos - last_pos);
|
|
seek_64(srcfile, src_pos);
|
|
}
|
|
|
|
for (i = 0; i < myGifFile->SHeight; i++) {
|
|
delete[] ScreenBuff[i];
|
|
}
|
|
delete[] ScreenBuff;
|
|
|
|
DGifCloseFile(myGifFile);
|
|
EGifCloseFile(newGifFile);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool decompress_gif(FILE* srcfile, FILE* dstfile, long long src_pos, int& gif_length, int& decomp_length, unsigned char& block_size, GifCodeStruct* g) {
|
|
int i, j;
|
|
GifFileType* myGifFile;
|
|
int Row, Col, Width, Height, ExtCode;
|
|
GifByteType *Extension;
|
|
GifRecordType RecordType;
|
|
|
|
long long srcfile_pos;
|
|
long long last_pos = -1;
|
|
|
|
freadfunc = srcfile;
|
|
myGifFile = DGifOpen(NULL, readFunc);
|
|
if (myGifFile == NULL) {
|
|
return false;
|
|
}
|
|
|
|
unsigned char** ScreenBuff = NULL;
|
|
|
|
do {
|
|
|
|
if (DGifGetRecordType(myGifFile, &RecordType) == GIF_ERROR) {
|
|
DGifCloseFile(myGifFile);
|
|
return false;
|
|
}
|
|
|
|
switch (RecordType) {
|
|
case IMAGE_DESC_RECORD_TYPE:
|
|
if (ScreenBuff == NULL) {
|
|
ScreenBuff = new unsigned char*[myGifFile->SHeight];
|
|
for (i = 0; i < myGifFile->SHeight; i++) {
|
|
ScreenBuff[i] = new unsigned char[myGifFile->SWidth];
|
|
}
|
|
|
|
for (i = 0; i < myGifFile->SWidth; i++) /* Set its color to BackGround. */
|
|
ScreenBuff[0][i] = myGifFile->SBackGroundColor;
|
|
for (i = 1; i < myGifFile->SHeight; i++) {
|
|
memcpy(ScreenBuff[i], ScreenBuff[0], myGifFile->SWidth);
|
|
}
|
|
}
|
|
|
|
if (DGifGetImageDesc(myGifFile) == GIF_ERROR) {
|
|
if (ScreenBuff != NULL) {
|
|
for (i = 0; i < myGifFile->SHeight; i++) {
|
|
delete[] ScreenBuff[i];
|
|
}
|
|
delete[] ScreenBuff;
|
|
}
|
|
DGifCloseFile(myGifFile);
|
|
return false;
|
|
}
|
|
|
|
srcfile_pos = tell_64(srcfile);
|
|
if (last_pos != srcfile_pos) {
|
|
if (last_pos == -1) {
|
|
seek_64(srcfile, src_pos);
|
|
fast_copy(srcfile, dstfile, srcfile_pos - src_pos);
|
|
seek_64(srcfile, srcfile_pos);
|
|
|
|
long long dstfile_pos = tell_64(dstfile);
|
|
seek_64(dstfile, 0);
|
|
// change GIF8xa to PGF8xa
|
|
fputc('P', dstfile);
|
|
fputc('G', dstfile);
|
|
seek_64(dstfile, dstfile_pos);
|
|
} else {
|
|
seek_64(srcfile, last_pos);
|
|
fast_copy(srcfile, dstfile, srcfile_pos - last_pos);
|
|
seek_64(srcfile, srcfile_pos);
|
|
}
|
|
}
|
|
|
|
unsigned char c;
|
|
c = fgetc(srcfile);
|
|
if (c == 254) {
|
|
block_size = 254;
|
|
}
|
|
seek_64(srcfile, srcfile_pos);
|
|
|
|
Row = myGifFile->Image.Top; /* Image Position relative to Screen. */
|
|
Col = myGifFile->Image.Left;
|
|
Width = myGifFile->Image.Width;
|
|
Height = myGifFile->Image.Height;
|
|
|
|
if (((Col + Width) > myGifFile->SWidth) ||
|
|
((Row + Height) > myGifFile->SHeight)) {
|
|
if (ScreenBuff != NULL) {
|
|
for (i = 0; i < myGifFile->SHeight; i++) {
|
|
delete[] ScreenBuff[i];
|
|
}
|
|
delete[] ScreenBuff;
|
|
}
|
|
DGifCloseFile(myGifFile);
|
|
return false;
|
|
}
|
|
|
|
if (myGifFile->Image.Interlace) {
|
|
/* Need to perform 4 passes on the images: */
|
|
for (i = 0; i < 4; i++) {
|
|
for (j = Row + InterlacedOffset[i]; j < (Row + Height); j += InterlacedJumps[i]) {
|
|
if (DGifGetLineByte(myGifFile, &ScreenBuff[j][Col], Width, g) == GIF_ERROR) {
|
|
if (ScreenBuff != NULL) {
|
|
for (i = 0; i < myGifFile->SHeight; i++) {
|
|
delete[] ScreenBuff[i];
|
|
}
|
|
delete[] ScreenBuff;
|
|
}
|
|
DGifCloseFile(myGifFile);
|
|
// TODO: If this fails, write as much rows to dstfile
|
|
// as possible to support second decompression.
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
// write to dstfile
|
|
for (i = Row; i < (Row + Height); i++) {
|
|
own_fwrite(&ScreenBuff[i][Col], 1, Width, dstfile);
|
|
}
|
|
} else {
|
|
for (i = Row; i < (Row + Height); i++) {
|
|
if (DGifGetLineByte(myGifFile, &ScreenBuff[i][Col], Width, g) == GIF_ERROR) {
|
|
if (ScreenBuff != NULL) {
|
|
for (i = 0; i < myGifFile->SHeight; i++) {
|
|
delete[] ScreenBuff[i];
|
|
}
|
|
delete[] ScreenBuff;
|
|
}
|
|
DGifCloseFile(myGifFile);
|
|
return false;
|
|
}
|
|
// write to dstfile
|
|
own_fwrite(&ScreenBuff[i][Col], 1, Width, dstfile);
|
|
}
|
|
}
|
|
|
|
last_pos = tell_64(srcfile);
|
|
|
|
break;
|
|
case EXTENSION_RECORD_TYPE:
|
|
/* Skip any extension blocks in file: */
|
|
|
|
if (DGifGetExtension(myGifFile, &ExtCode, &Extension) == GIF_ERROR) {
|
|
if (ScreenBuff != NULL) {
|
|
for (i = 0; i < myGifFile->SHeight; i++) {
|
|
delete[] ScreenBuff[i];
|
|
}
|
|
delete[] ScreenBuff;
|
|
}
|
|
DGifCloseFile(myGifFile);
|
|
return false;
|
|
}
|
|
while (Extension != NULL) {
|
|
if (DGifGetExtensionNext(myGifFile, &Extension) == GIF_ERROR) {
|
|
if (ScreenBuff != NULL) {
|
|
for (i = 0; i < myGifFile->SHeight; i++) {
|
|
delete[] ScreenBuff[i];
|
|
}
|
|
delete[] ScreenBuff;
|
|
}
|
|
DGifCloseFile(myGifFile);
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
case TERMINATE_RECORD_TYPE:
|
|
break;
|
|
default: /* Should be traps by DGifGetRecordType. */
|
|
break;
|
|
}
|
|
} while (RecordType != TERMINATE_RECORD_TYPE);
|
|
|
|
srcfile_pos = tell_64(srcfile);
|
|
if (last_pos != srcfile_pos) {
|
|
seek_64(srcfile, last_pos);
|
|
fast_copy(srcfile, dstfile, srcfile_pos - last_pos);
|
|
seek_64(srcfile, srcfile_pos);
|
|
}
|
|
|
|
gif_length = srcfile_pos - src_pos;
|
|
decomp_length = ftell(dstfile);
|
|
|
|
if (ScreenBuff != NULL) {
|
|
for (i = 0; i < myGifFile->SHeight; i++) {
|
|
delete[] ScreenBuff[i];
|
|
}
|
|
delete[] ScreenBuff;
|
|
}
|
|
|
|
DGifCloseFile(myGifFile);
|
|
|
|
return true;
|
|
}
|
|
|
|
void try_decompression_gif(unsigned char version[5]) {
|
|
|
|
unsigned char block_size = 255;
|
|
int gif_length = -1;
|
|
int decomp_length = -1;
|
|
|
|
GifCodeStruct gCode;
|
|
GifCodeInit(&gCode);
|
|
GifDiffStruct gDiff;
|
|
GifDiffInit(&gDiff);
|
|
|
|
bool recompress_success_needed = true;
|
|
|
|
if (DEBUG_MODE) {
|
|
print_debug_percent();
|
|
printf ("Possible GIF found at position ");
|
|
print64(input_file_pos);
|
|
printf("\n");
|
|
}
|
|
|
|
seek_64(fin, input_file_pos);
|
|
|
|
// read GIF file
|
|
ftempout = tryOpen(tempfile1, "wb");
|
|
|
|
if (!decompress_gif(fin, ftempout, input_file_pos, gif_length, decomp_length, block_size, &gCode)) {
|
|
safe_fclose(&ftempout);
|
|
remove(tempfile1);
|
|
GifDiffFree(&gDiff);
|
|
GifCodeFree(&gCode);
|
|
return;
|
|
}
|
|
|
|
if (DEBUG_MODE) {
|
|
printf ("Can be decompressed to %i bytes\n", decomp_length);
|
|
}
|
|
|
|
safe_fclose(&ftempout);
|
|
|
|
decompressed_streams_count++;
|
|
decompressed_gif_count++;
|
|
|
|
ftempout = tryOpen(tempfile1, "rb");
|
|
frecomp = tryOpen(tempfile2,"wb");
|
|
if (recompress_gif(ftempout, frecomp, block_size, &gCode, &gDiff)) {
|
|
|
|
safe_fclose(&frecomp);
|
|
safe_fclose(&ftempout);
|
|
|
|
frecomp = tryOpen(tempfile2,"rb");
|
|
best_identical_bytes = compare_files_penalty(fin, frecomp, input_file_pos, 0);
|
|
safe_fclose(&frecomp);
|
|
|
|
if (best_identical_bytes < gif_length) {
|
|
if (DEBUG_MODE) {
|
|
printf ("Recompression failed\n");
|
|
}
|
|
} else {
|
|
if (DEBUG_MODE) {
|
|
printf ("Recompression successful\n");
|
|
}
|
|
recompress_success_needed = true;
|
|
|
|
if (best_identical_bytes > min_ident_size) {
|
|
recompressed_streams_count++;
|
|
recompressed_gif_count++;
|
|
non_zlib_was_used = true;
|
|
|
|
if (penalty_bytes != NULL) {
|
|
memcpy(best_penalty_bytes, penalty_bytes, penalty_bytes_len);
|
|
best_penalty_bytes_len = penalty_bytes_len;
|
|
} else {
|
|
best_penalty_bytes_len = 0;
|
|
}
|
|
|
|
// end uncompressed data
|
|
|
|
compressed_data_found = true;
|
|
end_uncompressed_data();
|
|
|
|
// write compressed data header (GIF)
|
|
unsigned char add_bits = 0;
|
|
if (best_penalty_bytes_len != 0) add_bits += 2;
|
|
if (block_size == 254) add_bits += 4;
|
|
if (recompress_success_needed) add_bits += 128;
|
|
|
|
fout_fputc(1 + add_bits);
|
|
fout_fputc(5); // GIF
|
|
|
|
// store diff bytes
|
|
fout_fput32(gDiff.GIFDiffIndex);
|
|
if(DEBUG_MODE) {
|
|
if (gDiff.GIFDiffIndex > 0)
|
|
printf("Diff bytes were used: %i bytes\n", gDiff.GIFDiffIndex);
|
|
}
|
|
for (int dbc = 0; dbc < gDiff.GIFDiffIndex; dbc++) {
|
|
fout_fputc(gDiff.GIFDiff[dbc]);
|
|
}
|
|
|
|
// store penalty bytes, if any
|
|
if (best_penalty_bytes_len != 0) {
|
|
if (DEBUG_MODE) {
|
|
printf("Penalty bytes were used: %i bytes\n", best_penalty_bytes_len);
|
|
}
|
|
|
|
fout_fput32(best_penalty_bytes_len);
|
|
|
|
for (int pbc = 0; pbc < best_penalty_bytes_len; pbc++) {
|
|
fout_fputc(best_penalty_bytes[pbc]);
|
|
}
|
|
}
|
|
|
|
fout_fput32(best_identical_bytes);
|
|
fout_fput32(decomp_length);
|
|
|
|
// write decompressed data
|
|
write_decompressed_data(decomp_length);
|
|
|
|
// start new uncompressed data
|
|
|
|
// set input file pointer after recompressed data
|
|
input_file_pos += gif_length - 1;
|
|
cb += gif_length - 1;
|
|
}
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
if (DEBUG_MODE) {
|
|
printf ("No matches\n");
|
|
}
|
|
|
|
safe_fclose(&frecomp);
|
|
safe_fclose(&ftempout);
|
|
|
|
}
|
|
|
|
GifDiffFree(&gDiff);
|
|
GifCodeFree(&gCode);
|
|
|
|
remove(tempfile2);
|
|
remove(tempfile1);
|
|
|
|
}
|
|
|
|
// JPG routines
|
|
|
|
void packjpg_mp3_dll_msg() {
|
|
|
|
printf("Using packJPG for JPG recompression, packMP3 for MP3 recompression.\n");
|
|
printf("%s\n", pjglib_version_info());
|
|
printf("%s\n", pmplib_version_info());
|
|
printf("More about packJPG and packMP3 here: http://www.matthiasstirner.com\n\n");
|
|
|
|
}
|
|
|
|
void try_decompression_jpg (long long jpg_length, bool progressive_jpg) {
|
|
|
|
if (DEBUG_MODE) {
|
|
print_debug_percent();
|
|
if (progressive_jpg) {
|
|
printf ("Possible JPG (progressive) found at position ");
|
|
} else {
|
|
printf ("Possible JPG found at position ");
|
|
}
|
|
print64(saved_input_file_pos);
|
|
printf (", length ");
|
|
print64(jpg_length);
|
|
printf ("\n");
|
|
// do not recompress non-progressive JPGs when prog_only is set
|
|
if ((!progressive_jpg) && (prog_only)) {
|
|
printf("Skipping (only progressive JPGs mode set)\n");
|
|
}
|
|
}
|
|
|
|
// do not recompress non-progressive JPGs when prog_only is set
|
|
if ((!progressive_jpg) && (prog_only)) return;
|
|
|
|
bool jpg_success = false;
|
|
bool recompress_success = false;
|
|
bool mjpg_dht_used = false;
|
|
char recompress_msg[256];
|
|
unsigned char* jpg_mem_in = NULL;
|
|
unsigned char* jpg_mem_out = NULL;
|
|
unsigned int jpg_mem_out_size = -1;
|
|
bool in_memory = ((jpg_length + MJPGDHT_LEN) <= JPG_MAX_MEMORY_SIZE);
|
|
|
|
if (in_memory) { // small stream => do everything in memory
|
|
jpg_mem_in = new unsigned char[jpg_length + MJPGDHT_LEN];
|
|
seek_64(fin, input_file_pos);
|
|
fast_copy(fin, jpg_mem_in, jpg_length);
|
|
|
|
pjglib_init_streams(jpg_mem_in, 1, jpg_length, jpg_mem_out, 1);
|
|
recompress_success = pjglib_convert_stream2mem(&jpg_mem_out, &jpg_mem_out_size, recompress_msg);
|
|
} else { // large stream => use temporary files
|
|
// try to decompress at current position
|
|
fjpg = tryOpen(tempfile0,"wb");
|
|
seek_64(fin, input_file_pos);
|
|
fast_copy(fin, fjpg, jpg_length);
|
|
safe_fclose(&fjpg);
|
|
remove(tempfile1);
|
|
|
|
// Workaround for JPG bugs. Sometimes tempfile1 is removed, but still
|
|
// not accessible by packJPG, so we prevent that by opening it here
|
|
// ourselves.
|
|
FILE* fworkaround = tryOpen(tempfile1,"wb");
|
|
safe_fclose(&fworkaround);
|
|
|
|
recompress_success = pjglib_convert_file2file(tempfile0, tempfile1, recompress_msg);
|
|
}
|
|
|
|
if ((!recompress_success) && (strncmp(recompress_msg, "huffman table missing", 21) == 0) && (use_mjpeg)) {
|
|
if (DEBUG_MODE) printf ("huffman table missing, trying to use Motion JPEG DHT\n");
|
|
// search 0xFF 0xDA, insert MJPGDHT (MJPGDHT_LEN bytes)
|
|
bool found_ffda = false;
|
|
bool found_ff = false;
|
|
int ffda_pos = -1;
|
|
|
|
if (in_memory) {
|
|
do {
|
|
ffda_pos++;
|
|
if (ffda_pos >= jpg_length) break;
|
|
if (found_ff) {
|
|
found_ffda = (jpg_mem_in[ffda_pos] == 0xDA);
|
|
if (found_ffda) break;
|
|
found_ff = false;
|
|
} else {
|
|
found_ff = (jpg_mem_in[ffda_pos] == 0xFF);
|
|
}
|
|
} while (!found_ffda);
|
|
if (found_ffda) {
|
|
memmove(jpg_mem_in + (ffda_pos - 1) + MJPGDHT_LEN, jpg_mem_in + (ffda_pos - 1), jpg_length - (ffda_pos - 1));
|
|
memcpy(jpg_mem_in + (ffda_pos - 1), MJPGDHT, MJPGDHT_LEN);
|
|
|
|
pjglib_init_streams(jpg_mem_in, 1, jpg_length + MJPGDHT_LEN, jpg_mem_out, 1);
|
|
recompress_success = pjglib_convert_stream2mem(&jpg_mem_out, &jpg_mem_out_size, recompress_msg);
|
|
}
|
|
} else {
|
|
fjpg = tryOpen(tempfile0,"rb");
|
|
do {
|
|
ffda_pos++;
|
|
if (fread(in, 1, 1, fjpg) != 1) break;
|
|
if (found_ff) {
|
|
found_ffda = (in[0] == 0xDA);
|
|
if (found_ffda) break;
|
|
found_ff = false;
|
|
} else {
|
|
found_ff = (in[0] == 0xFF);
|
|
}
|
|
} while (!found_ffda);
|
|
if (found_ffda) {
|
|
fdecomp = tryOpen(tempfile3,"wb");
|
|
seek_64(fjpg, 0);
|
|
fast_copy(fjpg, fdecomp, ffda_pos - 1);
|
|
// insert MJPGDHT
|
|
own_fwrite(MJPGDHT, 1, MJPGDHT_LEN, fdecomp);
|
|
seek_64(fjpg, ffda_pos - 1);
|
|
fast_copy(fjpg, fdecomp, jpg_length - (ffda_pos - 1));
|
|
safe_fclose(&fdecomp);
|
|
}
|
|
safe_fclose(&fjpg);
|
|
recompress_success = pjglib_convert_file2file(tempfile3, tempfile1, recompress_msg);
|
|
}
|
|
|
|
mjpg_dht_used = recompress_success;
|
|
}
|
|
|
|
decompressed_streams_count++;
|
|
if (progressive_jpg) {
|
|
decompressed_jpg_prog_count++;
|
|
} else {
|
|
decompressed_jpg_count++;
|
|
}
|
|
|
|
if (!recompress_success) {
|
|
if (DEBUG_MODE) printf ("packJPG error: %s\n", recompress_msg);
|
|
}
|
|
|
|
if (!in_memory) {
|
|
remove(tempfile0);
|
|
}
|
|
|
|
if (recompress_success) {
|
|
int jpg_new_length = -1;
|
|
|
|
if (in_memory) {
|
|
jpg_new_length = jpg_mem_out_size;
|
|
} else {
|
|
ftempout = tryOpen(tempfile1,"rb");
|
|
fseek(ftempout, 0, SEEK_END);
|
|
jpg_new_length = ftell(ftempout);
|
|
safe_fclose(&ftempout);
|
|
}
|
|
|
|
if (jpg_new_length > 0) {
|
|
recompressed_streams_count++;
|
|
if (progressive_jpg) {
|
|
recompressed_jpg_prog_count++;
|
|
} else {
|
|
recompressed_jpg_count++;
|
|
}
|
|
non_zlib_was_used = true;
|
|
|
|
best_identical_bytes = jpg_length;
|
|
best_identical_bytes_decomp = jpg_new_length;
|
|
jpg_success = true;
|
|
}
|
|
}
|
|
|
|
if (jpg_success) {
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Best match: %i bytes, recompressed to %i bytes\n", best_identical_bytes, best_identical_bytes_decomp);
|
|
}
|
|
|
|
// end uncompressed data
|
|
|
|
compressed_data_found = true;
|
|
end_uncompressed_data();
|
|
|
|
// write compressed data header (JPG)
|
|
|
|
if (mjpg_dht_used) {
|
|
fout_fputc(1 + 4); // no penalty bytes, Motion JPG DHT used
|
|
} else {
|
|
fout_fputc(1); // no penalty bytes
|
|
}
|
|
fout_fputc(6); // JPG
|
|
|
|
fout_fput32(best_identical_bytes);
|
|
fout_fput32(best_identical_bytes_decomp);
|
|
|
|
// write compressed JPG
|
|
if (in_memory) {
|
|
fast_copy(jpg_mem_out, fout, best_identical_bytes_decomp);
|
|
} else {
|
|
write_decompressed_data(best_identical_bytes_decomp);
|
|
}
|
|
|
|
// start new uncompressed data
|
|
|
|
// set input file pointer after recompressed data
|
|
input_file_pos += best_identical_bytes - 1;
|
|
cb += best_identical_bytes - 1;
|
|
|
|
} else {
|
|
if (DEBUG_MODE) {
|
|
printf("No matches\n");
|
|
}
|
|
}
|
|
|
|
if (jpg_mem_in != NULL) delete[] jpg_mem_in;
|
|
if (jpg_mem_out != NULL) delete[] jpg_mem_out;
|
|
}
|
|
|
|
void try_decompression_mp3 (long long mp3_length) {
|
|
|
|
if (DEBUG_MODE) {
|
|
print_debug_percent();
|
|
printf ("Possible MP3 found at position ");
|
|
print64(saved_input_file_pos);
|
|
printf (", length ");
|
|
print64(mp3_length);
|
|
printf ("\n");
|
|
}
|
|
|
|
bool mp3_success = false;
|
|
bool recompress_success = false;
|
|
char recompress_msg[256];
|
|
unsigned char* mp3_mem_in = NULL;
|
|
unsigned char* mp3_mem_out = NULL;
|
|
unsigned int mp3_mem_out_size = -1;
|
|
bool in_memory = (mp3_length <= MP3_MAX_MEMORY_SIZE);
|
|
|
|
if (in_memory) { // small stream => do everything in memory
|
|
mp3_mem_in = new unsigned char[mp3_length];
|
|
seek_64(fin, input_file_pos);
|
|
fast_copy(fin, mp3_mem_in, mp3_length);
|
|
|
|
pmplib_init_streams(mp3_mem_in, 1, mp3_length, mp3_mem_out, 1);
|
|
recompress_success = pmplib_convert_stream2mem(&mp3_mem_out, &mp3_mem_out_size, recompress_msg);
|
|
} else { // large stream => use temporary files
|
|
// try to decompress at current position
|
|
fmp3 = tryOpen(tempfile0,"wb");
|
|
seek_64(fin, input_file_pos);
|
|
fast_copy(fin, fmp3, mp3_length);
|
|
safe_fclose(&fmp3);
|
|
remove(tempfile1);
|
|
|
|
// workaround for bugs, similar to packJPG
|
|
FILE* fworkaround = tryOpen(tempfile1,"wb");
|
|
safe_fclose(&fworkaround);
|
|
|
|
recompress_success = pmplib_convert_file2file(tempfile0, tempfile1, recompress_msg);
|
|
}
|
|
|
|
if ((!recompress_success) && (strncmp(recompress_msg, "synching failure", 16) == 0)) {
|
|
int frame_n;
|
|
int pos;
|
|
if (sscanf(recompress_msg, "synching failure (frame #%i at 0x%X)", &frame_n, &pos) == 2) {
|
|
if ((pos > 0) && (pos < mp3_length)) {
|
|
mp3_length = pos;
|
|
|
|
if (DEBUG_MODE) printf ("Too much garbage data at the end, retry with new length %i\n", pos);
|
|
|
|
if (in_memory) {
|
|
pmplib_init_streams(mp3_mem_in, 1, mp3_length, mp3_mem_out, 1);
|
|
recompress_success = pmplib_convert_stream2mem(&mp3_mem_out, &mp3_mem_out_size, recompress_msg);
|
|
} else {
|
|
fmp3 = tryOpen(tempfile0, "r+b");
|
|
ftruncate(fileno(fmp3), pos);
|
|
safe_fclose(&fmp3);
|
|
remove(tempfile1);
|
|
|
|
// workaround for bugs, similar to packJPG
|
|
FILE* fworkaround = tryOpen(tempfile1,"wb");
|
|
safe_fclose(&fworkaround);
|
|
|
|
recompress_success = pmplib_convert_file2file(tempfile0, tempfile1, recompress_msg);
|
|
}
|
|
}
|
|
}
|
|
} else if ((!recompress_success) && (strncmp(recompress_msg, "big value pairs out of bounds", 29) == 0)) {
|
|
suppress_mp3_big_value_pairs_sum = saved_input_file_pos + mp3_length;
|
|
if (DEBUG_MODE) {
|
|
printf("Ignoring following streams with position/length sum ");
|
|
print64(suppress_mp3_big_value_pairs_sum);
|
|
printf(" to avoid slowdown\n");
|
|
}
|
|
}
|
|
|
|
decompressed_streams_count++;
|
|
decompressed_mp3_count++;
|
|
|
|
if (!recompress_success) {
|
|
if (DEBUG_MODE) printf ("packMP3 error: %s\n", recompress_msg);
|
|
}
|
|
|
|
if (!in_memory) {
|
|
remove(tempfile0);
|
|
}
|
|
|
|
if (recompress_success) {
|
|
int mp3_new_length = -1;
|
|
|
|
if (in_memory) {
|
|
mp3_new_length = mp3_mem_out_size;
|
|
} else {
|
|
ftempout = tryOpen(tempfile1,"rb");
|
|
fseek(ftempout, 0, SEEK_END);
|
|
mp3_new_length = ftell(ftempout);
|
|
safe_fclose(&ftempout);
|
|
}
|
|
|
|
if (mp3_new_length > 0) {
|
|
recompressed_streams_count++;
|
|
recompressed_mp3_count++;
|
|
non_zlib_was_used = true;
|
|
|
|
best_identical_bytes = mp3_length;
|
|
best_identical_bytes_decomp = mp3_new_length;
|
|
mp3_success = true;
|
|
}
|
|
}
|
|
|
|
if (mp3_success) {
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Best match: %i bytes, recompressed to %i bytes\n", best_identical_bytes, best_identical_bytes_decomp);
|
|
}
|
|
|
|
// end uncompressed data
|
|
|
|
compressed_data_found = true;
|
|
end_uncompressed_data();
|
|
|
|
// write compressed data header (MP3)
|
|
|
|
fout_fputc(1); // no penalty bytes
|
|
fout_fputc(10); // MP3
|
|
|
|
fout_fput32(best_identical_bytes);
|
|
fout_fput32(best_identical_bytes_decomp);
|
|
|
|
// write compressed MP3
|
|
if (in_memory) {
|
|
fast_copy(mp3_mem_out, fout, best_identical_bytes_decomp);
|
|
} else {
|
|
write_decompressed_data(best_identical_bytes_decomp);
|
|
}
|
|
|
|
// start new uncompressed data
|
|
|
|
// set input file pointer after recompressed data
|
|
input_file_pos += best_identical_bytes - 1;
|
|
cb += best_identical_bytes - 1;
|
|
|
|
} else {
|
|
if (DEBUG_MODE) {
|
|
printf("No matches\n");
|
|
}
|
|
}
|
|
|
|
if (mp3_mem_in != NULL) delete[] mp3_mem_in;
|
|
if (mp3_mem_out != NULL) delete[] mp3_mem_out;
|
|
}
|
|
|
|
bool is_valid_mp3_frame(unsigned char* frame_data, unsigned char header2, unsigned char header3, int protection) {
|
|
unsigned char channels = (header3 >> 6) & 0x3;
|
|
int nch = (channels == MP3_MONO) ? 1 : 2;
|
|
int nsb, gr, ch;
|
|
unsigned short crc;
|
|
unsigned char* sideinfo;
|
|
|
|
nsb = (nch == 1) ? 17 : 32;
|
|
|
|
sideinfo = frame_data;
|
|
if (protection == 0x0) {
|
|
sideinfo += 2;
|
|
// if there is a crc: check and discard
|
|
crc = (frame_data[0] << 8) + frame_data[1];
|
|
if (crc != mp3_calc_layer3_crc(header2, header3, sideinfo, nsb)) {
|
|
// crc checksum mismatch
|
|
return false;
|
|
}
|
|
}
|
|
|
|
abitreader* side_reader = new abitreader(sideinfo, nsb);
|
|
|
|
side_reader->read((nch == 1) ? 18 : 20);
|
|
|
|
// granule specific side info
|
|
char window_switching, region0_size, region1_size;
|
|
for (gr = 0; gr < 2; gr++) {
|
|
for (ch = 0; ch < nch; ch++) {
|
|
side_reader->read(32);
|
|
side_reader->read(1);
|
|
window_switching = (char)side_reader->read(1);
|
|
if (window_switching == 0) {
|
|
side_reader->read(15);
|
|
region0_size = (char)side_reader->read(4);
|
|
region1_size = (char)side_reader->read(3);
|
|
if (region0_size + region1_size > 20) {
|
|
// region size out of bounds
|
|
return false;
|
|
}
|
|
} else {
|
|
side_reader->read(22);
|
|
}
|
|
side_reader->read(3);
|
|
}
|
|
}
|
|
|
|
delete(side_reader);
|
|
|
|
return true;
|
|
}
|
|
|
|
/* -----------------------------------------------
|
|
calculate frame crc
|
|
----------------------------------------------- */
|
|
inline unsigned short mp3_calc_layer3_crc(unsigned char header2, unsigned char header3, unsigned char* sideinfo, int sidesize)
|
|
{
|
|
// crc has a start value of 0xFFFF
|
|
unsigned short crc = 0xFFFF;
|
|
|
|
// process two last bytes from header...
|
|
crc = (crc << 8) ^ crc_table[(crc>>8) ^ header2];
|
|
crc = (crc << 8) ^ crc_table[(crc>>8) ^ header3];
|
|
// ... and all the bytes from the side information
|
|
for ( int i = 0; i < sidesize; i++ )
|
|
crc = (crc << 8) ^ crc_table[(crc>>8) ^ sideinfo[i]];
|
|
|
|
return crc;
|
|
}
|
|
|
|
void try_decompression_zlib(int windowbits) {
|
|
init_decompression_variables();
|
|
|
|
// try to decompress at current position
|
|
int compressed_stream_size = -1;
|
|
retval = try_to_decompress(fin, windowbits, compressed_stream_size);
|
|
|
|
if (retval > 0) { // seems to be a zLib-Stream
|
|
|
|
decompressed_streams_count++;
|
|
decompressed_zlib_count++;
|
|
|
|
if (DEBUG_MODE) {
|
|
print_debug_percent();
|
|
printf("Possible zLib-Stream (intense mode) found at position ");
|
|
print64(saved_input_file_pos);
|
|
printf(", windowbits = %i\n", -windowbits);
|
|
printf("Compressed size: %i\n", compressed_stream_size);
|
|
}
|
|
|
|
ftempout = tryOpen(tempfile1, "rb");
|
|
fseek(ftempout, 0, SEEK_END);
|
|
int stream_length = ftell(ftempout);
|
|
if (DEBUG_MODE) {
|
|
printf ("Can be decompressed to %i bytes\n", stream_length);
|
|
}
|
|
safe_fclose(&ftempout);
|
|
|
|
for (int index = 0; index < 81; index++) {
|
|
if (levels_sorted[index] == -1) break;
|
|
int comp_level = (levels_sorted[index] % 9) + 1;
|
|
int mem_level = (levels_sorted[index] / 9) + 1;
|
|
|
|
try_recompress(fin, comp_level, mem_level, windowbits, compressed_stream_size);
|
|
|
|
if (final_compression_found) break;
|
|
}
|
|
|
|
if ((best_identical_bytes > min_ident_size_intense_brute_mode) && (best_identical_bytes < best_identical_bytes_decomp)) {
|
|
recompressed_streams_count++;
|
|
recompressed_zlib_count++;
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Best match with level combination %i%i: %i bytes, decompressed to %i bytes\n", best_compression, best_mem_level, best_identical_bytes, best_identical_bytes_decomp);
|
|
}
|
|
|
|
if (!(comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9] == -1)) {
|
|
if (fast_mode) {
|
|
comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++;
|
|
zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true;
|
|
for (int i = 0; i < 81; i++) {
|
|
if (i != ((best_compression - 1) + (best_mem_level - 1) * 9)) {
|
|
comp_mem_level_count[i] = -1;
|
|
}
|
|
}
|
|
anything_was_used = true;
|
|
sort_comp_mem_levels();
|
|
} else {
|
|
comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++;
|
|
zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true;
|
|
anything_was_used = true;
|
|
sort_comp_mem_levels();
|
|
}
|
|
}
|
|
|
|
// end uncompressed data
|
|
|
|
compressed_data_found = true;
|
|
end_uncompressed_data();
|
|
|
|
// check recursion
|
|
recursion_result r = recursion_compress(best_identical_bytes, best_identical_bytes_decomp);
|
|
|
|
// write compressed data header (zLib)
|
|
|
|
int header_byte = 1 + (best_compression << 2);
|
|
if (best_penalty_bytes_len != 0) {
|
|
header_byte += 2;
|
|
}
|
|
if (r.success) {
|
|
header_byte += 128;
|
|
}
|
|
fout_fputc(header_byte);
|
|
fout_fputc(255); // raw zLib
|
|
fout_fputc((((-windowbits) - 8) << 4) + best_mem_level);
|
|
|
|
// store zLib header, but increased by 1 to prevent finding it
|
|
// again in the next pass
|
|
own_fwrite(in_buf + cb, 1, 1, fout);
|
|
unsigned char incchar = *(in_buf + cb + 1) + 1;
|
|
fout_fputc(incchar);
|
|
|
|
// store penalty bytes, if any
|
|
if (best_penalty_bytes_len != 0) {
|
|
if (DEBUG_MODE) {
|
|
printf("Penalty bytes were used: %i bytes\n", best_penalty_bytes_len);
|
|
}
|
|
fout_fput32(best_penalty_bytes_len);
|
|
for (int pbc = 0; pbc < best_penalty_bytes_len; pbc++) {
|
|
fout_fputc(best_penalty_bytes[pbc]);
|
|
}
|
|
}
|
|
|
|
fout_fput32(best_identical_bytes);
|
|
fout_fput32(best_identical_bytes_decomp);
|
|
|
|
if (r.success) {
|
|
fout_fput64(r.file_length);
|
|
}
|
|
|
|
// write decompressed data
|
|
if (r.success) {
|
|
write_decompressed_data(r.file_length, r.file_name);
|
|
remove(r.file_name);
|
|
delete[] r.file_name;
|
|
} else {
|
|
write_decompressed_data(best_identical_bytes_decomp);
|
|
}
|
|
|
|
// start new uncompressed data
|
|
|
|
// set input file pointer after recompressed data
|
|
input_file_pos += best_identical_bytes - 1;
|
|
cb += best_identical_bytes - 1;
|
|
|
|
} else {
|
|
if (DEBUG_MODE) {
|
|
printf("No matches\n");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void try_decompression_brute() {
|
|
init_decompression_variables();
|
|
|
|
int windowbits;
|
|
|
|
// try to decompress at current position
|
|
int compressed_stream_size = -1;
|
|
retval = try_to_decompress(fin, -15, compressed_stream_size);
|
|
|
|
if (retval > 0) { // seems to be a zLib-Stream
|
|
|
|
decompressed_streams_count++;
|
|
decompressed_brute_count++;
|
|
|
|
if (DEBUG_MODE) {
|
|
print_debug_percent();
|
|
printf("Possible zLib-Stream (brute mode) found at position ");
|
|
print64(saved_input_file_pos);
|
|
printf("\n");
|
|
printf("Compressed size: %i\n", compressed_stream_size);
|
|
}
|
|
|
|
ftempout = tryOpen(tempfile1, "rb");
|
|
fseek(ftempout, 0, SEEK_END);
|
|
int stream_length = ftell(ftempout);
|
|
if (DEBUG_MODE) {
|
|
printf ("Can be decompressed to %i bytes\n", stream_length);
|
|
}
|
|
safe_fclose(&ftempout);
|
|
|
|
for (windowbits = -15; windowbits < -7; windowbits++) {
|
|
for (int index = 0; index < 81; index++) {
|
|
if (levels_sorted[index] == -1) break;
|
|
int comp_level = (levels_sorted[index] % 9) + 1;
|
|
int mem_level = (levels_sorted[index] / 9) + 1;
|
|
|
|
try_recompress(fin, comp_level, mem_level, windowbits, compressed_stream_size);
|
|
|
|
if (final_compression_found) break;
|
|
}
|
|
if (final_compression_found) break;
|
|
}
|
|
|
|
if ((best_identical_bytes > min_ident_size_intense_brute_mode) && (best_identical_bytes < best_identical_bytes_decomp)) {
|
|
recompressed_streams_count++;
|
|
recompressed_brute_count++;
|
|
|
|
windowbits = best_windowbits;
|
|
if (DEBUG_MODE) {
|
|
printf("Best match with level combination %i%i, windowbits = %i: %i bytes, decompressed to %i bytes\n", best_compression, best_mem_level, -windowbits, best_identical_bytes, best_identical_bytes_decomp);
|
|
}
|
|
|
|
if (!(comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9] == -1)) {
|
|
if (fast_mode) {
|
|
comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++;
|
|
zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true;
|
|
for (int i = 0; i < 81; i++) {
|
|
if (i != ((best_compression - 1) + (best_mem_level - 1) * 9)) {
|
|
comp_mem_level_count[i] = -1;
|
|
}
|
|
}
|
|
anything_was_used = true;
|
|
sort_comp_mem_levels();
|
|
} else {
|
|
comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++;
|
|
zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true;
|
|
anything_was_used = true;
|
|
sort_comp_mem_levels();
|
|
}
|
|
}
|
|
|
|
// end uncompressed data
|
|
|
|
compressed_data_found = true;
|
|
end_uncompressed_data();
|
|
|
|
// check recursion
|
|
recursion_result r = recursion_compress(best_identical_bytes, best_identical_bytes_decomp);
|
|
|
|
// write compressed data header (brute)
|
|
|
|
int header_byte = 1 + (best_compression << 2);
|
|
if (best_penalty_bytes_len != 0) {
|
|
header_byte += 2;
|
|
}
|
|
if (r.success) {
|
|
header_byte += 128;
|
|
}
|
|
fout_fputc(header_byte);
|
|
fout_fputc(254); // brute
|
|
fout_fputc((((-windowbits) - 8) << 4) + best_mem_level);
|
|
|
|
// store penalty bytes, if any
|
|
if (best_penalty_bytes_len != 0) {
|
|
if (DEBUG_MODE) {
|
|
printf("Penalty bytes were used: %i bytes\n", best_penalty_bytes_len);
|
|
}
|
|
fout_fput32(best_penalty_bytes_len);
|
|
for (int pbc = 0; pbc < best_penalty_bytes_len; pbc++) {
|
|
fout_fputc(best_penalty_bytes[pbc]);
|
|
}
|
|
}
|
|
|
|
fout_fput32(best_identical_bytes);
|
|
fout_fput32(best_identical_bytes_decomp);
|
|
|
|
if (r.success) {
|
|
fout_fput64(r.file_length);
|
|
}
|
|
|
|
// write decompressed data
|
|
if (r.success) {
|
|
write_decompressed_data(r.file_length, r.file_name);
|
|
remove(r.file_name);
|
|
delete[] r.file_name;
|
|
} else {
|
|
write_decompressed_data(best_identical_bytes_decomp);
|
|
}
|
|
|
|
// set input file pointer after recompressed data
|
|
input_file_pos += best_identical_bytes - 1;
|
|
cb += best_identical_bytes - 1;
|
|
|
|
} else {
|
|
if (DEBUG_MODE) {
|
|
printf("No matches\n");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void try_decompression_swf(int windowbits) {
|
|
init_decompression_variables();
|
|
|
|
// try to decompress at current position
|
|
int compressed_stream_size = -1;
|
|
retval = try_to_decompress(fin, windowbits, compressed_stream_size);
|
|
|
|
if (retval > 0) { // seems to be a zLib-Stream
|
|
|
|
decompressed_streams_count++;
|
|
decompressed_swf_count++;
|
|
|
|
if (DEBUG_MODE) {
|
|
print_debug_percent();
|
|
printf("Possible zLib-Stream in SWF found at position ");
|
|
print64(saved_input_file_pos);
|
|
printf(", windowbits = %i\n", -windowbits);
|
|
printf("Compressed size: %i\n", compressed_stream_size);
|
|
}
|
|
|
|
if (DEBUG_MODE) {
|
|
ftempout = tryOpen(tempfile1, "rb");
|
|
fseek(ftempout, 0, SEEK_END);
|
|
printf ("Can be decompressed to %li bytes\n", ftell(ftempout));
|
|
safe_fclose(&ftempout);
|
|
}
|
|
|
|
for (int index = 0; index < 81; index++) {
|
|
if (levels_sorted[index] == -1) break;
|
|
int comp_level = (levels_sorted[index] % 9) + 1;
|
|
int mem_level = (levels_sorted[index] / 9) + 1;
|
|
|
|
try_recompress(fin, comp_level, mem_level, windowbits, compressed_stream_size);
|
|
|
|
if (final_compression_found) break;
|
|
}
|
|
|
|
if ((best_identical_bytes > min_ident_size) && (best_identical_bytes < best_identical_bytes_decomp)) {
|
|
recompressed_streams_count++;
|
|
recompressed_swf_count++;
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Best match with level combination %i%i: %i bytes, decompressed to %i bytes\n", best_compression, best_mem_level, best_identical_bytes, best_identical_bytes_decomp);
|
|
}
|
|
|
|
if (!(comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9] == -1)) {
|
|
if (fast_mode) {
|
|
comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++;
|
|
zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true;
|
|
for (int i = 0; i < 81; i++) {
|
|
if (i != ((best_compression - 1) + (best_mem_level - 1) * 9)) {
|
|
comp_mem_level_count[i] = -1;
|
|
}
|
|
}
|
|
anything_was_used = true;
|
|
sort_comp_mem_levels();
|
|
} else {
|
|
comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++;
|
|
zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true;
|
|
anything_was_used = true;
|
|
sort_comp_mem_levels();
|
|
}
|
|
}
|
|
|
|
// end uncompressed data
|
|
|
|
compressed_data_found = true;
|
|
end_uncompressed_data();
|
|
|
|
// check recursion
|
|
recursion_result r = recursion_compress(best_identical_bytes, best_identical_bytes_decomp);
|
|
|
|
// write compressed data header (SWF)
|
|
|
|
int header_byte = 1 + (best_compression << 2);
|
|
if (best_penalty_bytes_len != 0) {
|
|
header_byte += 2;
|
|
}
|
|
if (r.success) {
|
|
header_byte += 128;
|
|
}
|
|
fout_fputc(header_byte);
|
|
fout_fputc(7); // SWF
|
|
fout_fputc((((-windowbits) - 8) << 4) + best_mem_level);
|
|
|
|
// store version and length from SWF header
|
|
own_fwrite(in_buf + cb + 3, 1, 5, fout);
|
|
|
|
// store zLib header, but increased by 1 to prevent finding it
|
|
// again in the next pass
|
|
own_fwrite(in_buf + cb + 8, 1, 1, fout);
|
|
unsigned char incchar = *(in_buf + cb + 9) + 1;
|
|
fout_fputc(incchar);
|
|
|
|
// store penalty bytes, if any
|
|
if (best_penalty_bytes_len != 0) {
|
|
if (DEBUG_MODE) {
|
|
printf("Penalty bytes were used: %i bytes\n", best_penalty_bytes_len);
|
|
}
|
|
fout_fput32(best_penalty_bytes_len);
|
|
for (int pbc = 0; pbc < best_penalty_bytes_len; pbc++) {
|
|
fout_fputc(best_penalty_bytes[pbc]);
|
|
}
|
|
}
|
|
|
|
fout_fput32(best_identical_bytes);
|
|
fout_fput32(best_identical_bytes_decomp);
|
|
|
|
if (r.success) {
|
|
fout_fput64(r.file_length);
|
|
}
|
|
|
|
// write decompressed data
|
|
if (r.success) {
|
|
write_decompressed_data(r.file_length, r.file_name);
|
|
remove(r.file_name);
|
|
delete[] r.file_name;
|
|
} else {
|
|
write_decompressed_data(best_identical_bytes_decomp);
|
|
}
|
|
|
|
// start new uncompressed data
|
|
|
|
// set input file pointer after recompressed data
|
|
input_file_pos += best_identical_bytes - 1;
|
|
cb += best_identical_bytes - 1;
|
|
|
|
} else {
|
|
if (intense_mode_is_active()) intense_ignore_offsets->insert(input_file_pos - 2);
|
|
if (brute_mode_is_active()) brute_ignore_offsets->insert(input_file_pos);
|
|
if (DEBUG_MODE) {
|
|
printf("No matches\n");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void try_decompression_bzip2(int compression_level) {
|
|
init_decompression_variables();
|
|
|
|
// try to decompress at current position
|
|
int compressed_stream_size = -1;
|
|
retval = try_to_decompress_bzip2(fin, compression_level, compressed_stream_size);
|
|
|
|
if (retval > 0) { // seems to be a zLib-Stream
|
|
|
|
decompressed_streams_count++;
|
|
decompressed_bzip2_count++;
|
|
|
|
if (DEBUG_MODE) {
|
|
print_debug_percent();
|
|
printf("Possible bZip2-Stream found at position ");
|
|
print64(saved_input_file_pos);
|
|
printf(", compression level = %i\n", compression_level);
|
|
printf("Compressed size: %i\n", compressed_stream_size);
|
|
|
|
ftempout = tryOpen(tempfile1, "rb");
|
|
fseek(ftempout, 0, SEEK_END);
|
|
printf ("Can be decompressed to %li bytes\n", ftell(ftempout));
|
|
safe_fclose(&ftempout);
|
|
}
|
|
|
|
try_recompress_bzip2(fin, compression_level, compressed_stream_size);
|
|
|
|
if ((best_identical_bytes > min_ident_size) && (best_identical_bytes < best_identical_bytes_decomp)) {
|
|
recompressed_streams_count++;
|
|
recompressed_bzip2_count++;
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Best match: %i bytes, decompressed to %i bytes\n", best_identical_bytes, best_identical_bytes_decomp);
|
|
}
|
|
|
|
non_zlib_was_used = true;
|
|
|
|
// end uncompressed data
|
|
|
|
compressed_data_found = true;
|
|
end_uncompressed_data();
|
|
|
|
// check recursion
|
|
recursion_result r = recursion_compress(best_identical_bytes, best_identical_bytes_decomp);
|
|
|
|
// write compressed data header (bZip2)
|
|
|
|
int header_byte = 1;
|
|
if (best_penalty_bytes_len != 0) {
|
|
header_byte += 2;
|
|
}
|
|
if (r.success) {
|
|
header_byte += 128;
|
|
}
|
|
fout_fputc(header_byte);
|
|
fout_fputc(9); // Base64
|
|
fout_fputc(compression_level);
|
|
|
|
// store penalty bytes, if any
|
|
if (best_penalty_bytes_len != 0) {
|
|
if (DEBUG_MODE) {
|
|
printf("Penalty bytes were used: %i bytes\n", best_penalty_bytes_len);
|
|
}
|
|
fout_fput32(best_penalty_bytes_len);
|
|
for (int pbc = 0; pbc < best_penalty_bytes_len; pbc++) {
|
|
fout_fputc(best_penalty_bytes[pbc]);
|
|
}
|
|
}
|
|
|
|
fout_fput32(best_identical_bytes);
|
|
fout_fput32(best_identical_bytes_decomp);
|
|
|
|
if (r.success) {
|
|
fout_fput64(r.file_length);
|
|
}
|
|
|
|
// write decompressed data
|
|
if (r.success) {
|
|
write_decompressed_data(r.file_length, r.file_name);
|
|
remove(r.file_name);
|
|
delete[] r.file_name;
|
|
} else {
|
|
write_decompressed_data(best_identical_bytes_decomp);
|
|
}
|
|
|
|
// start new uncompressed data
|
|
|
|
// set input file pointer after recompressed data
|
|
input_file_pos += best_identical_bytes - 1;
|
|
cb += best_identical_bytes - 1;
|
|
|
|
} else {
|
|
if (DEBUG_MODE) {
|
|
printf("No matches\n");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Base64 alphabet
|
|
static const char b64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
|
|
unsigned char base64_char_decode(unsigned char c) {
|
|
if ((c >= 'A') && (c <= 'Z')) {
|
|
return (c - 'A');
|
|
}
|
|
if ((c >= 'a') && (c <= 'z')) {
|
|
return (c - 'a' + 26);
|
|
}
|
|
if ((c >= '0') && (c <= '9')) {
|
|
return (c - '0' + 52);
|
|
}
|
|
if (c == '+') return 62;
|
|
if (c == '/') return 63;
|
|
|
|
if (c == '=') return 64; // padding
|
|
return 65; // invalid
|
|
}
|
|
|
|
void base64_reencode(FILE* file_in, FILE* file_out, int line_count, unsigned int* base64_line_len, int max_in_count, int max_byte_count) {
|
|
int line_nr = 0;
|
|
unsigned int act_line_len = 0;
|
|
int avail_in;
|
|
unsigned char a,b,c;
|
|
int i;
|
|
int act_byte_count = 0;
|
|
|
|
int remaining_bytes = max_in_count;
|
|
|
|
do {
|
|
if (remaining_bytes > DIV3CHUNK) {
|
|
avail_in = own_fread(in, 1, DIV3CHUNK, file_in);
|
|
} else {
|
|
avail_in = own_fread(in, 1, remaining_bytes, file_in);
|
|
}
|
|
remaining_bytes -= avail_in;
|
|
|
|
// make sure avail_in mod 3 = 0, pad with 0 bytes
|
|
while ((avail_in % 3) != 0) {
|
|
in[avail_in] = 0;
|
|
avail_in++;
|
|
}
|
|
|
|
for (i = 0; i < (avail_in/3); i++) {
|
|
a = in[i * 3];
|
|
b = in[i * 3 + 1];
|
|
c = in[i * 3 + 2];
|
|
if (act_byte_count < max_byte_count) own_fputc(b64[a >> 2], file_out);
|
|
act_byte_count++;
|
|
act_line_len++;
|
|
if (act_line_len == base64_line_len[line_nr]) { // end of line, write CRLF
|
|
if (act_byte_count < max_byte_count) own_fputc(13, file_out);
|
|
act_byte_count++;
|
|
if (act_byte_count < max_byte_count) own_fputc(10, file_out);
|
|
act_byte_count++;
|
|
act_line_len = 0;
|
|
line_nr++;
|
|
if (line_nr == line_count) break;
|
|
}
|
|
if (act_byte_count < max_byte_count) own_fputc(b64[((a & 0x03) << 4) | (b >> 4)], file_out);
|
|
act_byte_count++;
|
|
act_line_len++;
|
|
if (act_line_len == base64_line_len[line_nr]) { // end of line, write CRLF
|
|
if (act_byte_count < max_byte_count) own_fputc(13, file_out);
|
|
act_byte_count++;
|
|
if (act_byte_count < max_byte_count) own_fputc(10, file_out);
|
|
act_byte_count++;
|
|
act_line_len = 0;
|
|
line_nr++;
|
|
if (line_nr == line_count) break;
|
|
}
|
|
if (act_byte_count < max_byte_count) own_fputc(b64[((b & 0x0F) << 2) | (c >> 6)], file_out);
|
|
act_byte_count++;
|
|
act_line_len++;
|
|
if (act_line_len == base64_line_len[line_nr]) { // end of line, write CRLF
|
|
if (act_byte_count < max_byte_count) own_fputc(13, file_out);
|
|
act_byte_count++;
|
|
if (act_byte_count < max_byte_count) own_fputc(10, file_out);
|
|
act_byte_count++;
|
|
act_line_len = 0;
|
|
line_nr++;
|
|
if (line_nr == line_count) break;
|
|
}
|
|
if (act_byte_count < max_byte_count) own_fputc(b64[c & 63], file_out);
|
|
act_byte_count++;
|
|
act_line_len++;
|
|
if (act_line_len == base64_line_len[line_nr]) { // end of line, write CRLF
|
|
if (act_byte_count < max_byte_count) own_fputc(13, file_out);
|
|
act_byte_count++;
|
|
if (act_byte_count < max_byte_count) own_fputc(10, file_out);
|
|
act_byte_count++;
|
|
act_line_len = 0;
|
|
line_nr++;
|
|
if (line_nr == line_count) break;
|
|
}
|
|
}
|
|
if (line_nr == line_count) break;
|
|
} while ((remaining_bytes > 0) && (avail_in > 0));
|
|
|
|
}
|
|
|
|
void try_decompression_base64(int base64_header_length) {
|
|
init_decompression_variables();
|
|
|
|
// try to decode at current position
|
|
remove(tempfile1);
|
|
ftempout = tryOpen(tempfile1,"wb");
|
|
seek_64(fin, input_file_pos);
|
|
|
|
unsigned char base64_data[CHUNK >> 2];
|
|
unsigned int* base64_line_len = new unsigned int[65536];
|
|
|
|
int avail_in = 0;
|
|
int i, j, k;
|
|
unsigned char a, b, c, d;
|
|
int cr_count = 0;
|
|
bool decoding_failed = false;
|
|
bool stream_finished = false;
|
|
k = 0;
|
|
|
|
unsigned int line_nr = 0;
|
|
int line_count = 0;
|
|
unsigned int act_line_len = 0;
|
|
|
|
do {
|
|
avail_in = fread(in, 1, CHUNK, fin);
|
|
for (i = 0; i < (avail_in >> 2); i++) {
|
|
// are these valid base64 chars?
|
|
for (j = (i << 2); j < ((i << 2) + 4); j++) {
|
|
c = base64_char_decode(in[j]);
|
|
if (c < 64) {
|
|
base64_data[k] = c;
|
|
k++;
|
|
cr_count = 0;
|
|
act_line_len++;
|
|
continue;
|
|
}
|
|
if ((in[j] == 13) || (in[j] == 10)) {
|
|
if (in[j] == 13) {
|
|
cr_count++;
|
|
if (cr_count == 2) { // double CRLF -> base64 end
|
|
stream_finished = true;
|
|
break;
|
|
}
|
|
base64_line_len[line_nr] = act_line_len;
|
|
line_nr++;
|
|
if (line_nr == 65534) stream_finished = true;
|
|
act_line_len = 0;
|
|
}
|
|
continue;
|
|
} else {
|
|
cr_count = 0;
|
|
}
|
|
stream_finished = true;
|
|
base64_line_len[line_nr] = act_line_len;
|
|
line_nr++;
|
|
act_line_len = 0;
|
|
// "=" -> Padding
|
|
if (in[j] == '=') {
|
|
while ((k % 4) != 0) {
|
|
base64_data[k] = 0;
|
|
k++;
|
|
}
|
|
break;
|
|
}
|
|
// "-" -> base64 end
|
|
if (in[j] == '-') break;
|
|
// invalid char found -> decoding failed
|
|
decoding_failed = true;
|
|
break;
|
|
}
|
|
if (decoding_failed) break;
|
|
|
|
for (j = 0; j < (k >> 2); j++) {
|
|
a = base64_data[(j << 2)];
|
|
b = base64_data[(j << 2) + 1];
|
|
c = base64_data[(j << 2) + 2];
|
|
d = base64_data[(j << 2) + 3];
|
|
fputc((a << 2) | (b >> 4), ftempout);
|
|
fputc(((b << 4) & 0xFF) | (c >> 2), ftempout);
|
|
fputc(((c << 6) & 0xFF) | d, ftempout);
|
|
}
|
|
if (stream_finished) break;
|
|
for (j = 0; j < (k % 4); j++) {
|
|
base64_data[j] = base64_data[((k >> 2) << 2) + j];
|
|
}
|
|
k = k % 4;
|
|
}
|
|
} while ((avail_in == CHUNK) && (!decoding_failed) && (!stream_finished));
|
|
|
|
line_count = line_nr;
|
|
// if one of the lines is longer than 255 characters -> decoding failed
|
|
for (i = 0; i < line_count; i++) {
|
|
if (base64_line_len[i] > 255) {
|
|
decoding_failed = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
safe_fclose(&ftempout);
|
|
|
|
if (!decoding_failed) {
|
|
int line_case = -1;
|
|
// check line case
|
|
if (line_count == 1) {
|
|
line_case = 0; // one length for all lines
|
|
} else {
|
|
for (i = 1; i < (line_count - 1); i++) {
|
|
if (base64_line_len[i] != base64_line_len[0]) {
|
|
line_case = 2; // save complete line length list
|
|
break;
|
|
}
|
|
}
|
|
if (line_case == -1) {
|
|
// check last line
|
|
if (base64_line_len[line_count - 1] == base64_line_len[0]) {
|
|
line_case = 0; // one length for all lines
|
|
} else {
|
|
line_case = 1; // first length for all lines, second length for last line
|
|
}
|
|
}
|
|
}
|
|
|
|
decompressed_streams_count++;
|
|
decompressed_base64_count++;
|
|
|
|
ftempout = tryOpen(tempfile1, "rb");
|
|
fseek(ftempout, 0, SEEK_END);
|
|
identical_bytes = ftell(ftempout);
|
|
safe_fclose(&ftempout);
|
|
|
|
|
|
if (DEBUG_MODE) {
|
|
print_debug_percent();
|
|
printf ("Possible Base64-Stream (line_case %i, line_count %i) found at position ", line_case, line_count);
|
|
print64(saved_input_file_pos);
|
|
printf("\n");
|
|
printf ("Can be decoded to %i bytes\n", identical_bytes);
|
|
}
|
|
|
|
// try to re-encode Base64 data
|
|
|
|
ftempout = fopen(tempfile1,"rb");
|
|
if (ftempout == NULL) {
|
|
error(ERR_TEMP_FILE_DISAPPEARED);
|
|
}
|
|
|
|
remove(tempfile2);
|
|
frecomp = tryOpen(tempfile2,"w+b");
|
|
|
|
base64_reencode(ftempout, frecomp, line_count, base64_line_len);
|
|
|
|
safe_fclose(&ftempout);
|
|
|
|
identical_bytes_decomp = compare_files(fin, frecomp, input_file_pos, 0);
|
|
|
|
safe_fclose(&frecomp);
|
|
|
|
if (identical_bytes_decomp > min_ident_size) {
|
|
recompressed_streams_count++;
|
|
recompressed_base64_count++;
|
|
if (DEBUG_MODE) {
|
|
printf("Match: encoded to %i bytes\n", identical_bytes_decomp);
|
|
}
|
|
|
|
// end uncompressed data
|
|
|
|
compressed_data_found = true;
|
|
end_uncompressed_data();
|
|
|
|
// check recursion
|
|
recursion_result r = recursion_compress(identical_bytes_decomp, identical_bytes);
|
|
|
|
// write compressed data header (Base64)
|
|
int header_byte = 1 + (line_case << 2);
|
|
if (r.success) {
|
|
header_byte += 128;
|
|
}
|
|
fout_fputc(header_byte);
|
|
fout_fputc(8); // Base64
|
|
|
|
fout_fput16(base64_header_length);
|
|
|
|
// write "header", but change first char to prevent re-detection
|
|
fout_fputc(in_buf[cb] - 1);
|
|
own_fwrite(in_buf + cb + 1, 1, base64_header_length - 1, fout);
|
|
|
|
fout_fput16(line_count);
|
|
if (line_case == 2) {
|
|
for (i = 0; i < line_count; i++) {
|
|
fout_fputc(base64_line_len[i]);
|
|
}
|
|
} else {
|
|
fout_fputc(base64_line_len[0]);
|
|
if (line_case == 1) fout_fputc(base64_line_len[line_count - 1]);
|
|
}
|
|
|
|
delete[] base64_line_len;
|
|
|
|
fout_fput32(identical_bytes);
|
|
fout_fput32(identical_bytes_decomp);
|
|
|
|
if (r.success) {
|
|
fout_fput64(r.file_length);
|
|
}
|
|
|
|
// write decompressed data
|
|
if (r.success) {
|
|
write_decompressed_data(r.file_length, r.file_name);
|
|
remove(r.file_name);
|
|
delete[] r.file_name;
|
|
} else {
|
|
write_decompressed_data(identical_bytes);
|
|
}
|
|
|
|
// start new uncompressed data
|
|
|
|
// set input file pointer after recompressed data
|
|
input_file_pos += identical_bytes_decomp - 1;
|
|
cb += identical_bytes_decomp - 1;
|
|
} else {
|
|
if (DEBUG_MODE) {
|
|
printf("No match\n");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef COMFORT
|
|
void wait_for_key() {
|
|
printf("\nPress any key to continue\n");
|
|
// wait for key
|
|
do {
|
|
Sleep(55); // lower CPU cost
|
|
} while (!kbhit());
|
|
}
|
|
#endif
|
|
|
|
void error(int error_nr) {
|
|
printf("\nERROR %i: ", error_nr);
|
|
switch (error_nr) {
|
|
case ERR_IGNORE_POS_TOO_BIG:
|
|
printf("Ignore position too big");
|
|
break;
|
|
case ERR_IDENTICAL_BYTE_SIZE_TOO_BIG:
|
|
printf("Identical bytes size bigger than 4 GB");
|
|
break;
|
|
case ERR_ONLY_SET_MIN_SIZE_ONCE:
|
|
printf("Minimal identical size can only be set once");
|
|
break;
|
|
case ERR_MORE_THAN_ONE_OUTPUT_FILE:
|
|
printf("More than one output file given");
|
|
break;
|
|
case ERR_MORE_THAN_ONE_INPUT_FILE:
|
|
printf("More than one input file given");
|
|
break;
|
|
case ERR_DONT_USE_SPACE:
|
|
printf("Please don't use a space between the -o switch and the output filename");
|
|
break;
|
|
case ERR_TEMP_FILE_DISAPPEARED:
|
|
printf("Temporary file %s disappeared", tempfile1);
|
|
break;
|
|
case ERR_DISK_FULL:
|
|
printf("There is not enough space on disk");
|
|
// delete output file
|
|
safe_fclose(&fout);
|
|
remove(output_file_name);
|
|
break;
|
|
case ERR_RECURSION_DEPTH_TOO_BIG:
|
|
printf("Recursion depth too big");
|
|
break;
|
|
case ERR_ONLY_SET_RECURSION_DEPTH_ONCE:
|
|
printf("Recursion depth can only be set once");
|
|
break;
|
|
case ERR_CTRL_C:
|
|
printf("CTRL-C detected");
|
|
break;
|
|
case ERR_INTENSE_MODE_LIMIT_TOO_BIG:
|
|
printf("Intense mode level limit too big");
|
|
break;
|
|
case ERR_BRUTE_MODE_LIMIT_TOO_BIG:
|
|
printf("Brute mode level limit too big");
|
|
break;
|
|
case ERR_ONLY_SET_LZMA_MEMORY_ONCE:
|
|
printf("LZMA maximal memory can only be set once");
|
|
break;
|
|
case ERR_ONLY_SET_LZMA_THREAD_ONCE:
|
|
printf("LZMA thread count can only be set once");
|
|
break;
|
|
default:
|
|
printf("Unknown error");
|
|
}
|
|
printf("\n");
|
|
|
|
#ifdef COMFORT
|
|
wait_for_key();
|
|
#endif
|
|
|
|
exit(error_nr);
|
|
}
|
|
|
|
FILE* tryOpen(const char* filename, const char* mode) {
|
|
FILE* fptr;
|
|
|
|
fptr = fopen(filename,mode);
|
|
|
|
if (fptr != NULL) return fptr;
|
|
|
|
long long timeoutstart = get_time_ms();
|
|
while ((fptr == NULL) && ((get_time_ms() - timeoutstart) <= 15000)) {
|
|
fptr = fopen(filename,mode);
|
|
}
|
|
if (fptr == NULL) {
|
|
printf("ERROR: Access denied for %s\n", filename);
|
|
|
|
exit(1);
|
|
}
|
|
if (DEBUG_MODE) {
|
|
printf("Access problem for %s\n", filename);
|
|
printf("Time for getting access: %li ms\n", (long)(get_time_ms() - timeoutstart));
|
|
}
|
|
return fptr;
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
wchar_t* convertCharArrayToLPCWSTR(const char* charArray)
|
|
{
|
|
wchar_t* wString=new wchar_t[4096];
|
|
MultiByteToWideChar(CP_ACP, 0, charArray, -1, wString, 4096);
|
|
return wString;
|
|
}
|
|
#endif
|
|
|
|
long long fileSize64(char* filename) {
|
|
#ifndef UNIX
|
|
unsigned long s1 = 0, s2 = 0;
|
|
|
|
#ifdef _MSC_VER
|
|
HANDLE h = CreateFile(convertCharArrayToLPCWSTR(filename), 0, (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE), NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
#else
|
|
HANDLE h = CreateFile(filename, 0, (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE), NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
#endif
|
|
|
|
s2 = GetFileSize(h, &s1);
|
|
|
|
if (GetLastError() != NO_ERROR) {
|
|
printf("ERROR: Could not get file size of file %s\n", filename);
|
|
|
|
CloseHandle(h);
|
|
exit(0);
|
|
}
|
|
|
|
CloseHandle(h);
|
|
|
|
return ((long long)(s1) << 32) + s2;
|
|
#else
|
|
FILE* f = fopen(filename, "rb");
|
|
if (f == NULL) return 0;
|
|
fseeko(f, 0, SEEK_END);
|
|
long long result=ftello(f);
|
|
safe_fclose(&f);
|
|
return result;
|
|
#endif // UNIX
|
|
}
|
|
|
|
void print64(long long i64) {
|
|
if (i64 < 0) {
|
|
printf("ERROR: print64 called with negative value\n");
|
|
return;
|
|
}
|
|
|
|
char s[25];
|
|
|
|
int i = 24, j;
|
|
do {
|
|
s[i] = i64 % 10;
|
|
i--;
|
|
i64 /= 10;
|
|
} while (i64 > 0);
|
|
|
|
for (j = i+1; j < 25; j++) {
|
|
printf("%i", s[j]);
|
|
}
|
|
}
|
|
|
|
void init_temp_files() {
|
|
int i = 0, j, k;
|
|
do {
|
|
k = i;
|
|
for (j = 7; j >= 0; j--) {
|
|
metatempfile[5+j] = '0' + (k % 10);
|
|
k /= 10;
|
|
}
|
|
i++;
|
|
} while (file_exists(metatempfile));
|
|
|
|
k = i - 1;
|
|
for (j = 7; j >= 0; j--) {
|
|
tempfile0[5+j] = '0' + (k % 10);
|
|
tempfile1[5+j] = '0' + (k % 10);
|
|
tempfile2[5+j] = '0' + (k % 10);
|
|
tempfile3[5+j] = '0' + (k % 10);
|
|
k /= 10;
|
|
}
|
|
|
|
// create meta file
|
|
FILE* f = fopen(metatempfile, "wb");
|
|
safe_fclose(&f);
|
|
|
|
// update temporary file list
|
|
tempfilelist_count += 8;
|
|
tempfilelist = (char*)realloc(tempfilelist, 20 * tempfilelist_count * sizeof(char));
|
|
strcpy(tempfilelist + (tempfilelist_count - 8) * 20, metatempfile);
|
|
strcpy(tempfilelist + (tempfilelist_count - 7) * 20, tempfile0);
|
|
strcpy(tempfilelist + (tempfilelist_count - 6) * 20, tempfile1);
|
|
|
|
// recursion input file
|
|
strcpy(tempfilelist + (tempfilelist_count - 5) * 20, tempfile1);
|
|
tempfilelist[(tempfilelist_count - 5) * 20 + 18] = '_';
|
|
tempfilelist[(tempfilelist_count - 5) * 20 + 19] = 0;
|
|
|
|
strcpy(tempfilelist + (tempfilelist_count - 4) * 20, tempfile2);
|
|
strcpy(tempfilelist + (tempfilelist_count - 2) * 20, tempfile3);
|
|
}
|
|
|
|
void recursion_stack_push(void* var, int var_size) {
|
|
recursion_stack = (unsigned char*)realloc(recursion_stack, (recursion_stack_size + var_size) * sizeof(unsigned char));
|
|
for (int i = 0; i < var_size; i++) {
|
|
recursion_stack[recursion_stack_size] = ((unsigned char*)var)[i];
|
|
recursion_stack_size++;
|
|
}
|
|
}
|
|
|
|
void recursion_stack_pop(void* var, int var_size) {
|
|
for (int i = var_size - 1; i >= 0; i--) {
|
|
recursion_stack_size--;
|
|
((unsigned char*)var)[i] = recursion_stack[recursion_stack_size];
|
|
}
|
|
recursion_stack = (unsigned char*)realloc(recursion_stack, recursion_stack_size * sizeof(unsigned char));
|
|
}
|
|
|
|
void recursion_push() {
|
|
recursion_stack_push(&fin_length, sizeof(fin_length));
|
|
recursion_stack_push(&input_file_name, sizeof(input_file_name));
|
|
recursion_stack_push(&output_file_name, sizeof(output_file_name));
|
|
recursion_stack_push(&uncompressed_pos, sizeof(uncompressed_pos));
|
|
recursion_stack_push(&uncompressed_start, sizeof(uncompressed_start));
|
|
recursion_stack_push(&compressed_data_found, sizeof(compressed_data_found));
|
|
recursion_stack_push(&uncompressed_data_in_work, sizeof(uncompressed_data_in_work));
|
|
recursion_stack_push(&uncompressed_length, sizeof(uncompressed_length));
|
|
recursion_stack_push(&uncompressed_bytes_total, sizeof(uncompressed_bytes_total));
|
|
recursion_stack_push(&uncompressed_bytes_written, sizeof(uncompressed_bytes_written));
|
|
recursion_stack_push(&input_file_pos, sizeof(input_file_pos));
|
|
recursion_stack_push(&retval, sizeof(retval));
|
|
recursion_stack_push(&in_buf_pos, sizeof(in_buf_pos));
|
|
recursion_stack_push(&cb, sizeof(cb));
|
|
recursion_stack_push(&saved_input_file_pos, sizeof(saved_input_file_pos));
|
|
recursion_stack_push(&saved_cb, sizeof(saved_cb));
|
|
recursion_stack_push(&fin, sizeof(fin));
|
|
recursion_stack_push(&fout, sizeof(fout));
|
|
recursion_stack_push(&ftempout, sizeof(ftempout));
|
|
recursion_stack_push(&frecomp, sizeof(frecomp));
|
|
recursion_stack_push(&fdecomp, sizeof(fdecomp));
|
|
recursion_stack_push(&fpack, sizeof(fpack));
|
|
recursion_stack_push(&fpng, sizeof(fpng));
|
|
recursion_stack_push(&fjpg, sizeof(fjpg));
|
|
recursion_stack_push(&fmp3, sizeof(fmp3));
|
|
recursion_stack_push(&in_buf[0], sizeof(in_buf[0]) * IN_BUF_SIZE);
|
|
recursion_stack_push(&metatempfile[0], sizeof(metatempfile[0]) * 18);
|
|
recursion_stack_push(&tempfile0[0], sizeof(tempfile0[0]) * 19);
|
|
recursion_stack_push(&tempfile1[0], sizeof(tempfile1[0]) * 19);
|
|
recursion_stack_push(&tempfile2[0], sizeof(tempfile2[0]) * 19);
|
|
recursion_stack_push(&tempfile3[0], sizeof(tempfile3[0]) * 19);
|
|
recursion_stack_push(&penalty_bytes, sizeof(penalty_bytes));
|
|
recursion_stack_push(&local_penalty_bytes, sizeof(penalty_bytes));
|
|
recursion_stack_push(&best_penalty_bytes, sizeof(penalty_bytes));
|
|
|
|
recursion_stack_push(&identical_bytes, sizeof(identical_bytes));
|
|
recursion_stack_push(&best_identical_bytes, sizeof(best_identical_bytes));
|
|
recursion_stack_push(&best_identical_bytes_decomp, sizeof(best_identical_bytes_decomp));
|
|
recursion_stack_push(&best_compression, sizeof(best_compression));
|
|
recursion_stack_push(&best_mem_level, sizeof(best_mem_level));
|
|
recursion_stack_push(&penalty_bytes_len, sizeof(penalty_bytes_len));
|
|
recursion_stack_push(&best_penalty_bytes_len, sizeof(best_penalty_bytes_len));
|
|
recursion_stack_push(&identical_bytes_decomp, sizeof(identical_bytes_decomp));
|
|
recursion_stack_push(&final_compression_found, sizeof(final_compression_found));
|
|
|
|
recursion_stack_push(&anything_was_used, sizeof(anything_was_used));
|
|
recursion_stack_push(&non_zlib_was_used, sizeof(non_zlib_was_used));
|
|
recursion_stack_push(&sec_time, sizeof(sec_time));
|
|
recursion_stack_push(&global_min_percent, sizeof(global_min_percent));
|
|
recursion_stack_push(&global_max_percent, sizeof(global_max_percent));
|
|
recursion_stack_push(&comp_decomp_state, sizeof(comp_decomp_state));
|
|
recursion_stack_push(&suppress_jpg_parsing_until, sizeof(suppress_jpg_parsing_until));
|
|
recursion_stack_push(&suppress_mp3_type_until[0], sizeof(suppress_mp3_type_until[0]) * 16);
|
|
recursion_stack_push(&suppress_mp3_big_value_pairs_sum, sizeof(suppress_mp3_big_value_pairs_sum));
|
|
recursion_stack_push(&mp3_parsing_cache_second_frame, sizeof(mp3_parsing_cache_second_frame));
|
|
recursion_stack_push(&mp3_parsing_cache_n, sizeof(mp3_parsing_cache_n));
|
|
recursion_stack_push(&mp3_parsing_cache_mp3_length, sizeof(mp3_parsing_cache_mp3_length));
|
|
recursion_stack_push(&intense_ignore_offsets, sizeof(intense_ignore_offsets));
|
|
recursion_stack_push(&brute_ignore_offsets, sizeof(brute_ignore_offsets));
|
|
|
|
recursion_stack_push(&compression_otf_method, sizeof(compression_otf_method));
|
|
recursion_stack_push(&decompress_otf_end, sizeof(decompress_otf_end));
|
|
}
|
|
|
|
void recursion_pop() {
|
|
recursion_stack_pop(&decompress_otf_end, sizeof(decompress_otf_end));
|
|
recursion_stack_pop(&compression_otf_method, sizeof(compression_otf_method));
|
|
|
|
recursion_stack_pop(&brute_ignore_offsets, sizeof(brute_ignore_offsets));
|
|
recursion_stack_pop(&intense_ignore_offsets, sizeof(intense_ignore_offsets));
|
|
recursion_stack_pop(&mp3_parsing_cache_mp3_length, sizeof(mp3_parsing_cache_mp3_length));
|
|
recursion_stack_pop(&mp3_parsing_cache_n, sizeof(mp3_parsing_cache_n));
|
|
recursion_stack_pop(&mp3_parsing_cache_second_frame, sizeof(mp3_parsing_cache_second_frame));
|
|
recursion_stack_pop(&suppress_mp3_big_value_pairs_sum, sizeof(suppress_mp3_big_value_pairs_sum));
|
|
recursion_stack_pop(&suppress_mp3_type_until[0], sizeof(suppress_mp3_type_until[0]) * 16);
|
|
recursion_stack_pop(&suppress_jpg_parsing_until, sizeof(suppress_jpg_parsing_until));
|
|
recursion_stack_pop(&comp_decomp_state, sizeof(comp_decomp_state));
|
|
recursion_stack_pop(&global_max_percent, sizeof(global_max_percent));
|
|
recursion_stack_pop(&global_min_percent, sizeof(global_min_percent));
|
|
recursion_stack_pop(&sec_time, sizeof(sec_time));
|
|
recursion_stack_pop(&non_zlib_was_used, sizeof(non_zlib_was_used));
|
|
recursion_stack_pop(&anything_was_used, sizeof(anything_was_used));
|
|
|
|
recursion_stack_pop(&final_compression_found, sizeof(final_compression_found));
|
|
recursion_stack_pop(&identical_bytes_decomp, sizeof(identical_bytes_decomp));
|
|
recursion_stack_pop(&best_penalty_bytes_len, sizeof(best_penalty_bytes_len));
|
|
recursion_stack_pop(&penalty_bytes_len, sizeof(penalty_bytes_len));
|
|
recursion_stack_pop(&best_mem_level, sizeof(best_mem_level));
|
|
recursion_stack_pop(&best_compression, sizeof(best_compression));
|
|
recursion_stack_pop(&best_identical_bytes_decomp, sizeof(best_identical_bytes_decomp));
|
|
recursion_stack_pop(&best_identical_bytes, sizeof(best_identical_bytes));
|
|
recursion_stack_pop(&identical_bytes, sizeof(identical_bytes));
|
|
|
|
recursion_stack_pop(&best_penalty_bytes, sizeof(penalty_bytes));
|
|
recursion_stack_pop(&local_penalty_bytes, sizeof(penalty_bytes));
|
|
recursion_stack_pop(&penalty_bytes, sizeof(penalty_bytes));
|
|
recursion_stack_pop(&tempfile3[0], sizeof(tempfile3[0]) * 19);
|
|
recursion_stack_pop(&tempfile2[0], sizeof(tempfile2[0]) * 19);
|
|
recursion_stack_pop(&tempfile1[0], sizeof(tempfile1[0]) * 19);
|
|
recursion_stack_pop(&tempfile0[0], sizeof(tempfile0[0]) * 19);
|
|
recursion_stack_pop(&metatempfile[0], sizeof(metatempfile[0]) * 18);
|
|
recursion_stack_pop(&in_buf[0], sizeof(in_buf[0]) * IN_BUF_SIZE);
|
|
recursion_stack_pop(&fmp3, sizeof(fmp3));
|
|
recursion_stack_pop(&fjpg, sizeof(fjpg));
|
|
recursion_stack_pop(&fpng, sizeof(fpng));
|
|
recursion_stack_pop(&fpack, sizeof(fpack));
|
|
recursion_stack_pop(&fdecomp, sizeof(fdecomp));
|
|
recursion_stack_pop(&frecomp, sizeof(frecomp));
|
|
recursion_stack_pop(&ftempout, sizeof(ftempout));
|
|
recursion_stack_pop(&fout, sizeof(fout));
|
|
recursion_stack_pop(&fin, sizeof(fin));
|
|
recursion_stack_pop(&saved_cb, sizeof(saved_cb));
|
|
recursion_stack_pop(&saved_input_file_pos, sizeof(saved_input_file_pos));
|
|
recursion_stack_pop(&cb, sizeof(cb));
|
|
recursion_stack_pop(&in_buf_pos, sizeof(in_buf_pos));
|
|
recursion_stack_pop(&retval, sizeof(retval));
|
|
recursion_stack_pop(&input_file_pos, sizeof(input_file_pos));
|
|
recursion_stack_pop(&uncompressed_bytes_written, sizeof(uncompressed_bytes_written));
|
|
recursion_stack_pop(&uncompressed_bytes_total, sizeof(uncompressed_bytes_total));
|
|
recursion_stack_pop(&uncompressed_length, sizeof(uncompressed_length));
|
|
recursion_stack_pop(&uncompressed_data_in_work, sizeof(uncompressed_data_in_work));
|
|
recursion_stack_pop(&compressed_data_found, sizeof(compressed_data_found));
|
|
recursion_stack_pop(&uncompressed_start, sizeof(uncompressed_start));
|
|
recursion_stack_pop(&uncompressed_pos, sizeof(uncompressed_pos));
|
|
recursion_stack_pop(&output_file_name, sizeof(output_file_name));
|
|
recursion_stack_pop(&input_file_name, sizeof(input_file_name));
|
|
recursion_stack_pop(&fin_length, sizeof(fin_length));
|
|
}
|
|
|
|
recursion_result recursion_compress(int compressed_bytes, int decompressed_bytes) {
|
|
FILE* recursion_fout;
|
|
recursion_result tmp_r;
|
|
tmp_r.success = false;
|
|
|
|
float recursion_min_percent = ((input_file_pos + uncompressed_bytes_written) / ((float)fin_length + uncompressed_bytes_total)) * (global_max_percent - global_min_percent) + global_min_percent;
|
|
float recursion_max_percent = ((input_file_pos + uncompressed_bytes_written +(compressed_bytes - 1)) / ((float)fin_length + uncompressed_bytes_total)) * (global_max_percent - global_min_percent) + global_min_percent;
|
|
|
|
bool rescue_anything_was_used = false;
|
|
bool rescue_non_zlib_was_used = false;
|
|
|
|
if ((recursion_depth + 1) > max_recursion_depth) {
|
|
max_recursion_depth_reached = true;
|
|
return tmp_r;
|
|
}
|
|
|
|
recursion_push();
|
|
|
|
// shorten tempfile1 to decompressed_bytes
|
|
FILE* ftempfile1 = fopen(tempfile1, "r+b");
|
|
ftruncate(fileno(ftempfile1), decompressed_bytes);
|
|
fclose(ftempfile1);
|
|
|
|
fin_length = fileSize64(tempfile1);
|
|
fin = fopen(tempfile1, "rb");
|
|
if (fin == NULL) {
|
|
printf("ERROR: Recursion input file \"%s\" doesn't exist\n", tempfile1);
|
|
|
|
exit(0);
|
|
}
|
|
input_file_name = new char[strlen(tempfile1)+1];
|
|
strcpy(input_file_name, tempfile1);
|
|
output_file_name = new char[strlen(tempfile1)+2];
|
|
strcpy(output_file_name, tempfile1);
|
|
output_file_name[strlen(tempfile1)] = '_';
|
|
output_file_name[strlen(tempfile1) + 1] = 0;
|
|
tmp_r.file_name = new char[strlen(tempfile1)+2];
|
|
strcpy(tmp_r.file_name, output_file_name);
|
|
recursion_fout = tryOpen(output_file_name,"wb");
|
|
fout = recursion_fout;
|
|
|
|
penalty_bytes = new char[MAX_PENALTY_BYTES];
|
|
local_penalty_bytes = new char[MAX_PENALTY_BYTES];
|
|
best_penalty_bytes = new char[MAX_PENALTY_BYTES];
|
|
|
|
intense_ignore_offsets = new set<long long>();
|
|
brute_ignore_offsets = new set<long long>();
|
|
|
|
// init JPG suppression
|
|
suppress_jpg_parsing_until = -1;
|
|
|
|
// init MP3 suppression
|
|
for (int i = 0; i < 16; i++) {
|
|
suppress_mp3_type_until[i] = -1;
|
|
}
|
|
suppress_mp3_big_value_pairs_sum = -1;
|
|
mp3_parsing_cache_second_frame = -1;
|
|
|
|
// disable compression-on-the-fly in recursion - we don't want compressed compressed streams
|
|
compression_otf_method = OTF_NONE;
|
|
|
|
recursion_depth++;
|
|
if (DEBUG_MODE) {
|
|
printf("Recursion start - new recursion depth %i\n", recursion_depth);
|
|
}
|
|
tmp_r.success = compress_file(recursion_min_percent, recursion_max_percent);
|
|
|
|
if (anything_was_used)
|
|
rescue_anything_was_used = true;
|
|
|
|
if (non_zlib_was_used)
|
|
rescue_non_zlib_was_used = true;
|
|
|
|
recursion_depth--;
|
|
recursion_pop();
|
|
|
|
if (rescue_anything_was_used)
|
|
anything_was_used = true;
|
|
|
|
if (rescue_non_zlib_was_used)
|
|
non_zlib_was_used = true;
|
|
|
|
if (DEBUG_MODE) {
|
|
if (tmp_r.success) {
|
|
printf("Recursion streams found\n");
|
|
} else {
|
|
printf("No recursion streams found\n");
|
|
}
|
|
printf("Recursion end - back to recursion depth %i\n", recursion_depth);
|
|
}
|
|
|
|
if (!tmp_r.success) {
|
|
remove(tmp_r.file_name);
|
|
} else {
|
|
if ((recursion_depth + 1) > max_recursion_depth_used)
|
|
max_recursion_depth_used = (recursion_depth + 1);
|
|
// get recursion file size
|
|
tmp_r.file_length = fileSize64(tmp_r.file_name);
|
|
}
|
|
|
|
return tmp_r;
|
|
}
|
|
|
|
recursion_result recursion_decompress(long long recursion_data_length) {
|
|
FILE* recursion_fin;
|
|
FILE* recursion_fout;
|
|
recursion_result tmp_r;
|
|
|
|
recursion_push();
|
|
|
|
remove(tempfile1);
|
|
recursion_fin = tryOpen(tempfile1,"wb");
|
|
|
|
fast_copy(fin, recursion_fin, recursion_data_length);
|
|
|
|
safe_fclose(&recursion_fin);
|
|
|
|
fin_length = fileSize64(tempfile1);
|
|
fin = fopen(tempfile1, "rb");
|
|
if (fin == NULL) {
|
|
printf("ERROR: Recursion input file \"%s\" doesn't exist\n", tempfile1);
|
|
|
|
exit(0);
|
|
}
|
|
input_file_name = new char[strlen(tempfile1)+1];
|
|
strcpy(input_file_name, tempfile1);
|
|
output_file_name = new char[strlen(tempfile1)+2];
|
|
strcpy(output_file_name, tempfile1);
|
|
output_file_name[strlen(tempfile1)] = '_';
|
|
output_file_name[strlen(tempfile1) + 1] = 0;
|
|
tmp_r.file_name = new char[strlen(tempfile1)+2];
|
|
strcpy(tmp_r.file_name, output_file_name);
|
|
recursion_fout = tryOpen(output_file_name,"wb");
|
|
fout = recursion_fout;
|
|
|
|
penalty_bytes = new char[MAX_PENALTY_BYTES];
|
|
local_penalty_bytes = new char[MAX_PENALTY_BYTES];
|
|
best_penalty_bytes = new char[MAX_PENALTY_BYTES];
|
|
|
|
// disable compression-on-the-fly in recursion - we don't want compressed compressed streams
|
|
compression_otf_method = OTF_NONE;
|
|
|
|
recursion_depth++;
|
|
if (DEBUG_MODE) {
|
|
printf("Recursion start - new recursion depth %i\n", recursion_depth);
|
|
}
|
|
decompress_file();
|
|
|
|
recursion_depth--;
|
|
recursion_pop();
|
|
|
|
if (DEBUG_MODE) {
|
|
printf("Recursion end - back to recursion depth %i\n", recursion_depth);
|
|
}
|
|
|
|
// get recursion file size
|
|
tmp_r.file_length = fileSize64(tmp_r.file_name);
|
|
|
|
tmp_r.frecurse = fopen(tmp_r.file_name, "rb");
|
|
|
|
return tmp_r;
|
|
}
|
|
|
|
void own_fputc(char c, FILE* f) {
|
|
bool use_otf = false;
|
|
|
|
if (comp_decomp_state == P_CONVERT) {
|
|
use_otf = (conversion_to_method > OTF_NONE);
|
|
if (use_otf) compression_otf_method = conversion_to_method;
|
|
} else {
|
|
if ((f != fout) || (compression_otf_method == OTF_NONE)) {
|
|
use_otf = false;
|
|
} else {
|
|
use_otf = true;
|
|
}
|
|
}
|
|
|
|
if (!use_otf) {
|
|
fputc(c, f);
|
|
} else {
|
|
fout_fputc(c);
|
|
}
|
|
}
|
|
|
|
void fout_fputc(char c) {
|
|
if (compression_otf_method == OTF_NONE) { // uncompressed
|
|
fputc(c, fout);
|
|
} else {
|
|
unsigned char temp_buf[1];
|
|
temp_buf[0] = c;
|
|
own_fwrite(temp_buf, 1, 1, fout);
|
|
}
|
|
}
|
|
|
|
void fout_fput16(int v) {
|
|
fout_fputc((v >> 8) % 256);
|
|
fout_fputc(v % 256);
|
|
}
|
|
|
|
void fout_fput24(int v) {
|
|
fout_fputc((v >> 16) % 256);
|
|
fout_fputc((v >> 8) % 256);
|
|
fout_fputc(v % 256);
|
|
}
|
|
|
|
void fout_fput32_little_endian(int v) {
|
|
fout_fputc(v % 256);
|
|
fout_fputc((v >> 8) % 256);
|
|
fout_fputc((v >> 16) % 256);
|
|
fout_fputc((v >> 24) % 256);
|
|
}
|
|
|
|
void fout_fput32(int v) {
|
|
fout_fputc((v >> 24) % 256);
|
|
fout_fputc((v >> 16) % 256);
|
|
fout_fputc((v >> 8) % 256);
|
|
fout_fputc(v % 256);
|
|
}
|
|
|
|
void fout_fput32(unsigned int v) {
|
|
fout_fputc((v >> 24) % 256);
|
|
fout_fputc((v >> 16) % 256);
|
|
fout_fputc((v >> 8) % 256);
|
|
fout_fputc(v % 256);
|
|
}
|
|
|
|
void fout_fput64(long long v) {
|
|
fout_fputc((v >> 56) % 256);
|
|
fout_fputc((v >> 48) % 256);
|
|
fout_fputc((v >> 40) % 256);
|
|
fout_fputc((v >> 32) % 256);
|
|
fout_fputc((v >> 24) % 256);
|
|
fout_fputc((v >> 16) % 256);
|
|
fout_fputc((v >> 8) % 256);
|
|
fout_fputc(v % 256);
|
|
}
|
|
|
|
void fout_fput64(unsigned long long v) {
|
|
fout_fputc((v >> 56) % 256);
|
|
fout_fputc((v >> 48) % 256);
|
|
fout_fputc((v >> 40) % 256);
|
|
fout_fputc((v >> 32) % 256);
|
|
fout_fputc((v >> 24) % 256);
|
|
fout_fputc((v >> 16) % 256);
|
|
fout_fputc((v >> 8) % 256);
|
|
fout_fputc(v % 256);
|
|
}
|
|
|
|
unsigned char fin_fgetc() {
|
|
if (comp_decomp_state == P_CONVERT) compression_otf_method = conversion_from_method;
|
|
|
|
if (compression_otf_method == OTF_NONE) {
|
|
return fgetc(fin);
|
|
} else {
|
|
unsigned char temp_buf[1];
|
|
own_fread(temp_buf, 1, 1, fin);
|
|
return temp_buf[0];
|
|
}
|
|
}
|
|
|
|
void init_compress_otf() {
|
|
if (comp_decomp_state == P_CONVERT) compression_otf_method = conversion_to_method;
|
|
|
|
switch (compression_otf_method) {
|
|
case OTF_BZIP2: { // bZip2
|
|
otf_bz2_stream_c.bzalloc = NULL;
|
|
otf_bz2_stream_c.bzfree = NULL;
|
|
otf_bz2_stream_c.opaque = NULL;
|
|
if (BZ2_bzCompressInit(&otf_bz2_stream_c, 9, 0, 0) != BZ_OK) {
|
|
printf("ERROR: bZip2 init failed\n");
|
|
exit(1);
|
|
}
|
|
break;
|
|
}
|
|
case OTF_XZ_MT: {
|
|
uint64_t memory_usage = 0;
|
|
uint64_t block_size = 0;
|
|
uint64_t max_memory = compression_otf_max_memory * 1024 * 1024LL;
|
|
int threads = compression_otf_thread_count;
|
|
|
|
if (max_memory == 0) {
|
|
max_memory = lzma_max_memory_default() * 1024 * 1024LL;
|
|
}
|
|
if (threads == 0) {
|
|
threads = auto_detected_thread_count();
|
|
}
|
|
|
|
if (!init_encoder_mt(&otf_xz_stream_c, threads, max_memory, memory_usage, block_size)) {
|
|
printf("ERROR: xz Multi-Threaded init failed\n");
|
|
exit(1);
|
|
}
|
|
|
|
string plural = "";
|
|
if (threads > 1) {
|
|
plural = "s";
|
|
}
|
|
printf("Compressing with LZMA, %i thread%s, memory usage: ", threads, plural.c_str());
|
|
print64(memory_usage / (1024 * 1024));
|
|
printf(" MiB, block size: ");
|
|
print64(block_size / (1024 * 1024));
|
|
printf(" MiB\n\n");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int auto_detected_thread_count() {
|
|
int threads = std::thread::hardware_concurrency();
|
|
if (threads == 0) threads = 2;
|
|
|
|
return threads;
|
|
}
|
|
|
|
// Return maximal memory to use per default for LZMA in MiB
|
|
// Use only 1 GiB in the 32-bit windows variant
|
|
// because of the 2 or 3 GiB limit on these systems
|
|
int lzma_max_memory_default() {
|
|
int max_memory = 2048;
|
|
#ifndef UNIX
|
|
#ifndef BIT64
|
|
max_memory = 1024;
|
|
#endif
|
|
#endif
|
|
return max_memory;
|
|
}
|
|
|
|
void denit_compress_otf() {
|
|
if (comp_decomp_state == P_CONVERT) compression_otf_method = conversion_to_method;
|
|
|
|
if (compression_otf_method > OTF_NONE) {
|
|
|
|
// uncompressed data of length 0 ends compress-on-the-fly data
|
|
char final_buf[9];
|
|
for (int i = 0; i < 9; i++) {
|
|
final_buf[i] = 0;
|
|
}
|
|
own_fwrite(final_buf, 1, 9, fout, true, true);
|
|
}
|
|
|
|
switch (compression_otf_method) {
|
|
case OTF_BZIP2: { // bZip2
|
|
|
|
(void)BZ2_bzCompressEnd(&otf_bz2_stream_c);
|
|
break;
|
|
}
|
|
case OTF_XZ_MT: {
|
|
(void)lzma_end(&otf_xz_stream_c);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void init_decompress_otf() {
|
|
if (comp_decomp_state == P_CONVERT) compression_otf_method = conversion_from_method;
|
|
|
|
switch (compression_otf_method) {
|
|
case OTF_BZIP2: {
|
|
otf_bz2_stream_d.bzalloc = NULL;
|
|
otf_bz2_stream_d.bzfree = NULL;
|
|
otf_bz2_stream_d.opaque = NULL;
|
|
otf_bz2_stream_d.avail_in = 0;
|
|
otf_bz2_stream_d.next_in = NULL;
|
|
if (BZ2_bzDecompressInit(&otf_bz2_stream_d, 0, 0) != BZ_OK) {
|
|
printf("ERROR: bZip2 init failed\n");
|
|
exit(1);
|
|
}
|
|
break;
|
|
}
|
|
case OTF_XZ_MT: {
|
|
if (!init_decoder(&otf_xz_stream_d)) {
|
|
printf("ERROR: liblzma init failed\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
decompress_otf_end = false;
|
|
}
|
|
|
|
void denit_decompress_otf() {
|
|
if (comp_decomp_state == P_CONVERT) compression_otf_method = conversion_from_method;
|
|
|
|
switch (compression_otf_method) {
|
|
case OTF_BZIP2: { // bZip2
|
|
|
|
(void)BZ2_bzDecompressEnd(&otf_bz2_stream_d);
|
|
break;
|
|
}
|
|
case OTF_XZ_MT: { // lzma2 multithreaded
|
|
(void)lzma_end(&otf_xz_stream_d);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// get current time in ms
|
|
long long get_time_ms() {
|
|
#ifndef UNIX
|
|
return GetTickCount();
|
|
#else
|
|
timeval t;
|
|
gettimeofday(&t, NULL);
|
|
return (t.tv_sec * 1000) + (t.tv_usec / 1000);
|
|
#endif
|
|
}
|
|
|
|
// nice time output, input t in ms
|
|
// 2^32 ms maximum, so will display incorrect negative values after about 49 days
|
|
void printf_time(long long t) {
|
|
printf("Time: ");
|
|
if (t < 1000) { // several milliseconds
|
|
printf("%li millisecond(s)\n", (long)t);
|
|
} else if (t < 1000*60) { // several seconds
|
|
printf("%li second(s), %li millisecond(s)\n", (long)(t / 1000), (long)(t % 1000));
|
|
} else if (t < 1000*60*60) { // several minutes
|
|
printf("%li minute(s), %li second(s)\n", (long)(t / (1000*60)), (long)((t / 1000) % 60));
|
|
} else if (t < 1000*60*60*24) { // several hours
|
|
printf("%li hour(s), %li minute(s), %li second(s)\n", (long)(t / (1000*60*60)), (long)((t / (1000*60)) % 60), (long)((t / 1000) % 60));
|
|
} else {
|
|
printf("%li day(s), %li hour(s), %li minute(s)\n", (long)(t / (1000*60*60*24)), (long)((t / (1000*60*60)) % 24), (long)((t / (1000*60)) % 60));
|
|
}
|
|
}
|
|
|
|
char get_char_with_echo() {
|
|
#ifndef UNIX
|
|
return getche();
|
|
#else
|
|
return fgetc(stdin);
|
|
#endif
|
|
}
|
|
|
|
void safe_fclose(FILE** f) {
|
|
if (*f != NULL) fclose(*f);
|
|
*f = NULL;
|
|
}
|
|
|
|
void print_work_sign(bool with_backspace) {
|
|
if (!DEBUG_MODE) {
|
|
if ((get_time_ms() - work_sign_start_time) >= 250) {
|
|
work_sign_var = (work_sign_var + 1) % 4;
|
|
work_sign_start_time = get_time_ms();
|
|
if (with_backspace) printf("\b\b\b\b\b\b");
|
|
printf("%c ", work_signs[work_sign_var]);
|
|
fflush(stdout);
|
|
} else if (!with_backspace) {
|
|
printf("%c ", work_signs[work_sign_var]);
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
}
|
|
|
|
void print_debug_percent() {
|
|
printf("(%.2f%%) ", (input_file_pos / (float)fin_length) * (global_max_percent - global_min_percent) + global_min_percent);
|
|
}
|
|
|
|
void show_progress(float percent, bool use_backspaces, bool check_time) {
|
|
if (!check_time || ((get_time_ms() - sec_time) >= 250)) {
|
|
if (use_backspaces) {
|
|
printf(string(6,'\b').c_str()); // backspace to remove work sign and 5 extra spaces
|
|
}
|
|
|
|
bool new_lzma_text = false;
|
|
if ((show_lzma_progress) && ((comp_decomp_state == P_COMPRESS) || ((comp_decomp_state == P_CONVERT) && (conversion_to_method == OTF_XZ_MT)))) {
|
|
int snprintf_ret = snprintf(lzma_progress_text, 70, "lzma total/written/left: %i/%i/%i MiB ", lzma_mib_total, lzma_mib_written, lzma_mib_total - lzma_mib_written);
|
|
if ((snprintf_ret > -1) && (snprintf_ret < 70)) {
|
|
new_lzma_text = true;
|
|
if ((old_lzma_progress_text_length > -1) && (use_backspaces)) {
|
|
printf("%s", string(old_lzma_progress_text_length, '\b').c_str()); // backspaces to remove old lzma progress text
|
|
}
|
|
old_lzma_progress_text_length = snprintf_ret;
|
|
}
|
|
}
|
|
|
|
if (use_backspaces) {
|
|
printf("%s", string(8,'\b').c_str()); // backspaces to remove output from %6.2f%
|
|
}
|
|
printf("%6.2f%% ", percent);
|
|
|
|
if (new_lzma_text) {
|
|
printf("%s", lzma_progress_text);
|
|
}
|
|
|
|
print_work_sign(false);
|
|
sec_time = get_time_ms();
|
|
}
|
|
}
|
|
|
|
void ctrl_c_handler(int sig) {
|
|
printf("\n\nCTRL-C detected\n");
|
|
if (tempfilelist_count > 0) {
|
|
printf("Removing temporary files...\n");
|
|
for (int i = 0; i < tempfilelist_count; i++) {
|
|
if ((tempfilelist[i * 20]) == '~') { // just to be safe
|
|
remove(tempfilelist + i * 20);
|
|
}
|
|
}
|
|
}
|
|
(void) signal(SIGINT, SIG_DFL);
|
|
|
|
error(ERR_CTRL_C);
|
|
}
|