2018-01-02 14:10:46 +01:00
/* Copyright 2006-2018 Christian Schneider
2016-01-06 12:10:58 +01:00
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
2016-01-26 12:35:25 +01:00
// version information
2016-01-06 12:10:58 +01:00
# define V_MAJOR 0
# define V_MINOR 4
2017-09-21 06:30:26 +02:00
# define V_MINOR2 7
//#define V_STATE "ALPHA"
# define V_STATE "DEVELOPMENT"
2017-09-08 06:32:14 +02:00
# define V_MSG "USE FOR TESTING ONLY"
//#define V_MSG "USE AT YOUR OWN RISK!"
2016-12-28 16:52:45 +01:00
# 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
2016-01-06 12:10:58 +01:00
// 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
2017-04-05 16:49:58 +02:00
# define ERR_ONLY_SET_LZMA_MEMORY_ONCE 16
# define ERR_ONLY_SET_LZMA_THREAD_ONCE 17
2018-02-12 19:37:06 +01:00
# define ERR_ONLY_SET_LZMA_FILTERS_ONCE 18
2016-01-06 12:10:58 +01:00
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <math.h>
# include <fstream>
# include <sstream>
# include <string>
# include <signal.h>
2016-12-28 11:14:41 +01:00
# include <thread>
2017-07-27 15:11:21 +02:00
# include <set>
2016-12-28 11:14:41 +01:00
# ifdef MINGW
2017-12-28 22:14:09 +05:30
# ifndef _GLIBCXX_HAS_GTHREADS
2016-12-28 11:14:41 +01:00
# include "contrib\mingw_std_threads\mingw.thread.h"
2017-12-28 22:14:09 +05:30
# endif // _GLIBCXX_HAS_GTHREADS
2016-12-28 11:14:41 +01:00
# endif
2016-01-13 15:55:09 +01:00
# ifdef _MSC_VER
# include <io.h>
# define ftruncate _chsize
# else
2016-01-06 12:10:58 +01:00
# include <unistd.h>
2016-01-13 15:55:09 +01:00
# endif
2016-01-06 12:10:58 +01:00
2016-02-13 10:48:56 +01:00
# ifndef UNIX
2016-01-06 12:10:58 +01:00
# 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 ;
2016-03-05 16:15:19 +01:00
# include "contrib/bzip2/bzlib.h"
# include "contrib/giflib/precomp_gif.h"
# include "contrib/packjpg/precomp_jpg.h"
# include "contrib/packmp3/precomp_mp3.h"
2016-01-07 12:22:18 +01:00
# include "contrib/zlib/zlib.h"
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
# define CHUNK 262144 // 256 KB buffersize
# define DIV3CHUNK 262143 // DIV3CHUNK is a bit smaller/larger than CHUNK, so that DIV3CHUNK mod 3 = 0
2016-01-06 12:10:58 +01:00
# 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
2017-01-02 11:22:01 +01:00
# define PENALTY_BYTES_TOLERANCE 160
2017-08-30 08:17:31 +02:00
# define IDENTICAL_COMPRESSED_BYTES_TOLERANCE 32
2016-01-06 12:10:58 +01:00
2017-08-28 16:52:47 +02:00
# define MAX_IO_BUFFER_SIZE 64 * 1024 * 1024
2017-08-29 17:23:15 +02:00
unsigned char * decomp_io_buf = NULL ;
2017-08-28 16:52:47 +02:00
2016-01-06 12:10:58 +01:00
unsigned char copybuf [ COPY_BUF_SIZE ] ;
unsigned char in_buf [ IN_BUF_SIZE ] ;
long long in_buf_pos ;
2016-01-26 12:35:25 +01:00
int cb ; // "checkbuf"
2016-01-06 12:10:58 +01:00
unsigned char in [ CHUNK ] ;
unsigned char out [ CHUNK ] ;
2016-01-26 12:35:25 +01:00
// name of temporary files
2016-01-06 12:10:58 +01:00
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 ;
2016-03-05 16:15:19 +01:00
# include "precomp.h"
2016-01-06 12:10:58 +01:00
static char work_signs [ 5 ] = " |/- \\ " ;
int work_sign_var = 0 ;
long long work_sign_start_time = get_time_ms ( ) ;
2016-01-26 12:35:25 +01:00
// recursion
2016-01-06 12:10:58 +01:00
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 ;
2016-01-26 12:35:25 +01:00
// compression-on-the-fly
2016-11-09 16:39:33 +01:00
unsigned char otf_in [ CHUNK ] ;
unsigned char otf_out [ CHUNK ] ;
2016-06-19 16:53:50 +08:00
# include "contrib/liblzma/precomp_xz.h"
lzma_stream otf_xz_stream_c = LZMA_STREAM_INIT , otf_xz_stream_d = LZMA_STREAM_INIT ;
2018-02-12 19:37:06 +01:00
bool otf_xz_filter_enabled [ 6 ] ;
bool otf_xz_filter_delta_enabled = false ;
int otf_xz_filter_delta_distance = 0 ;
int otf_xz_filter_used_count = 0 ;
2016-06-19 16:53:50 +08:00
2016-07-02 18:37:31 +02:00
int compression_otf_method = OTF_XZ_MT ;
2017-04-05 15:30:02 +02:00
uint64_t compression_otf_max_memory = 0 ;
2017-04-05 16:49:58 +02:00
int compression_otf_thread_count = 0 ;
2016-07-02 18:24:23 +02:00
int conversion_from_method ;
int conversion_to_method ;
2016-01-06 12:10:58 +01:00
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 ;
2016-01-21 15:39:31 +01:00
FILE * fmp3 = NULL ;
2016-01-06 12:10:58 +01:00
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 ;
2017-06-16 07:31:37 +02:00
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 ;
2016-01-06 12:10:58 +01:00
int comp_mem_level_count [ 81 ] ;
2017-12-25 11:14:05 +01:00
zLibMTF MTF ;
2016-01-06 12:10:58 +01:00
bool zlib_level_was_used [ 81 ] ;
bool anything_was_used ;
bool level_switch_used = false ;
bool non_zlib_was_used ;
2016-01-26 12:35:25 +01:00
// statistics
2016-01-06 12:10:58 +01:00
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 ;
2016-01-17 16:49:34 +01:00
unsigned int recompressed_mp3_count = 0 ;
2016-01-06 12:10:58 +01:00
unsigned int recompressed_swf_count = 0 ;
unsigned int recompressed_base64_count = 0 ;
unsigned int recompressed_bzip2_count = 0 ;
2016-01-26 12:35:25 +01:00
unsigned int recompressed_zlib_count = 0 ; // intense mode
unsigned int recompressed_brute_count = 0 ; // brute mode
2016-01-06 12:10:58 +01:00
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 ;
2016-01-17 16:49:34 +01:00
unsigned int decompressed_mp3_count = 0 ;
2016-01-06 12:10:58 +01:00
unsigned int decompressed_swf_count = 0 ;
unsigned int decompressed_base64_count = 0 ;
unsigned int decompressed_bzip2_count = 0 ;
2016-01-26 12:35:25 +01:00
unsigned int decompressed_zlib_count = 0 ; // intense mode
unsigned int decompressed_brute_count = 0 ; // brute mode
2016-01-06 12:10:58 +01:00
# define P_NONE 0
# define P_COMPRESS 1
# define P_DECOMPRESS 2
# define P_CONVERT 3
int comp_decomp_state = P_NONE ;
2016-01-26 12:35:25 +01:00
// penalty bytes
2016-01-06 12:10:58 +01:00
# 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 ;
2016-01-26 12:35:25 +01:00
long long * ignore_list = NULL ; // positions to ignore
2016-01-06 12:10:58 +01:00
int ignore_list_len = 0 ;
long long saved_input_file_pos , saved_cb ;
int min_ident_size = 4 ;
2017-07-29 11:10:27 +02:00
int min_ident_size_intense_brute_mode = 64 ;
2016-01-06 12:10:58 +01:00
2017-07-28 10:37:08 +02:00
set < long long > * intense_ignore_offsets = NULL ;
set < long long > * brute_ignore_offsets = NULL ;
2017-07-27 15:11:21 +02:00
2016-01-06 12:10:58 +01:00
unsigned char zlib_header [ 2 ] ;
unsigned int * idat_lengths = NULL ;
unsigned int * idat_crcs = NULL ;
int idat_count ;
2016-04-02 12:25:40 +02:00
long long suppress_mp3_type_until [ 16 ] ;
2016-05-06 11:31:47 +02:00
long long suppress_mp3_big_value_pairs_sum ;
2016-05-06 12:12:36 +02:00
long long mp3_parsing_cache_second_frame ;
long long mp3_parsing_cache_n ;
long long mp3_parsing_cache_mp3_length ;
2016-04-02 12:25:40 +02:00
2016-01-06 12:10:58 +01:00
bool fast_mode = false ;
2017-07-29 11:10:27 +02:00
bool intense_mode = false ;
2016-01-06 12:10:58 +01:00
bool brute_mode = false ;
bool pdf_bmp_mode = false ;
bool prog_only = false ;
bool use_mjpeg = true ;
2017-07-29 11:10:27 +02:00
int intense_mode_depth_limit = - 1 ;
2016-01-06 12:10:58 +01:00
int brute_mode_depth_limit = - 1 ;
2016-01-26 12:35:25 +01:00
// compression type bools
2016-01-06 12:10:58 +01:00
bool use_pdf = true ;
bool use_zip = true ;
bool use_gzip = true ;
bool use_png = true ;
bool use_gif = true ;
bool use_jpg = true ;
2016-01-17 16:49:34 +01:00
bool use_mp3 = true ;
2016-01-06 12:10:58 +01:00
bool use_swf = true ;
bool use_base64 = true ;
bool use_bzip2 = true ;
2016-01-26 12:35:25 +01:00
// Precomp DLL things
2016-01-06 12:10:58 +01:00
# ifdef PRECOMPDLL
2016-03-05 16:15:19 +01:00
# include "precomp_dll.h"
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// get copyright message
2016-01-06 12:10:58 +01:00
// msg = Buffer for error messages (256 bytes buffer size are enough)
DLL void get_copyright_msg ( char * msg ) {
if ( V_MINOR2 = = 0 ) {
2018-01-02 14:10:46 +01:00
sprintf ( msg , " Precomp DLL v%i.%i (c) 2006-2018 by Christian Schneider " , V_MAJOR , V_MINOR ) ;
2016-01-06 12:10:58 +01:00
} else {
2018-01-02 14:10:46 +01:00
sprintf ( msg , " Precomp DLL v%i.%i.%i (c) 2006-2018 by Christian Schneider " , V_MAJOR , V_MINOR , V_MINOR2 ) ;
2016-01-06 12:10:58 +01:00
}
}
void setSwitches ( Switches switches ) {
compression_otf_method = switches . compression_method ;
2017-06-16 07:31:37 +02:00
show_lzma_progress = ( compression_otf_method = = OTF_XZ_MT ) ;
2016-01-06 12:10:58 +01:00
ignore_list = switches . ignore_list ;
ignore_list_len = switches . ignore_list_len ;
2017-07-29 11:10:27 +02:00
intense_mode = switches . intense_mode ;
2016-01-06 12:10:58 +01:00
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 ;
2017-04-05 16:49:58 +02:00
compression_otf_max_memory = switches . compression_otf_max_memory ;
compression_otf_thread_count = switches . compression_otf_thread_count ;
2016-01-06 12:10:58 +01:00
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 ;
2016-01-17 16:49:34 +01:00
use_mp3 = switches . use_mp3 ;
2016-01-06 12:10:58 +01:00
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 ;
}
}
2016-01-26 12:35:25 +01:00
// precompress a file
2016-01-06 12:10:58 +01:00
// 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 ) {
2016-01-26 12:35:25 +01:00
// init compression and memory level count
2016-01-06 12:10:58 +01:00
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 ) ;
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 ;
}
2016-01-26 12:35:25 +01:00
// recompress a file
2016-01-06 12:10:58 +01:00
// 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 ) {
2016-01-26 12:35:25 +01:00
// init compression and memory level count
2016-01-06 12:10:58 +01:00
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 ) ;
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 ;
}
2016-01-26 12:35:25 +01:00
// test if a file contains streams that can be precompressed
2016-01-06 12:10:58 +01:00
DLL bool file_precompressable ( char * in , char * msg ) {
return false ;
}
# else
int main ( int argc , char * argv [ ] )
{
int return_errorlevel = 0 ;
2016-01-26 12:35:25 +01:00
// register CTRL-C handler
2016-01-06 12:10:58 +01:00
( 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 ( ) ;
2016-01-26 12:35:25 +01:00
if ( ! compress_file ( ) ) { // none of the streams could be decompressed
2016-01-06 12:10:58 +01:00
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
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
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 ) {
2016-12-28 16:52:45 +01:00
printf ( " Precomp v%i.%i %s %s - %s version " , V_MAJOR , V_MINOR , V_OS , V_BIT , V_STATE ) ;
2016-01-06 12:10:58 +01:00
} else {
2016-12-28 16:52:45 +01:00
printf ( " Precomp v%i.%i.%i %s %s - %s version " , V_MAJOR , V_MINOR , V_MINOR2 , V_OS , V_BIT , V_STATE ) ;
2016-01-06 12:10:58 +01:00
}
printf ( " - %s \n " , V_MSG ) ;
2018-01-02 14:10:46 +01:00
printf ( " Free for non-commercial use - Copyright 2006-2018 by Christian Schneider \n \n " ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// init compression and memory level count
2016-01-06 12:10:58 +01:00
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 ;
}
2016-05-06 11:31:47 +02:00
// init MP3 suppression
2016-04-02 12:25:40 +02:00
for ( i = 0 ; i < 16 ; i + + ) {
2017-05-04 11:24:52 +08:00
suppress_mp3_type_until [ i ] = - 1 ;
2016-04-02 12:25:40 +02:00
}
2016-05-06 11:31:47 +02:00
suppress_mp3_big_value_pairs_sum = - 1 ;
2016-05-06 12:12:36 +02:00
mp3_parsing_cache_second_frame = - 1 ;
2018-02-12 19:37:06 +01:00
// init LZMA filters
for ( int i = 0 ; i < 6 ; i + + ) {
otf_xz_filter_enabled [ i ] = false ;
}
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
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 ;
2017-04-05 16:49:58 +02:00
bool lzma_max_memory_set = false ;
bool lzma_thread_count_set = false ;
2018-02-12 19:37:06 +01:00
bool lzma_filters_set = false ;
2016-01-06 12:10:58 +01:00
bool long_help = false ;
2017-07-17 21:45:14 +05:30
bool preserve_extension = false ;
2016-01-06 12:10:58 +01:00
for ( i = 1 ; ( i < argc ) & & ( parse_on ) ; i + + ) {
2016-01-26 12:35:25 +01:00
if ( argv [ i ] [ 0 ] = = ' - ' ) { // switch
2016-01-06 12:10:58 +01:00
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 ' :
{
2016-01-26 12:35:25 +01:00
if ( toupper ( argv [ i ] [ 2 ] ) = = ' N ' ) { // intense mode
2016-01-06 12:10:58 +01:00
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 ' ) ) {
2017-07-29 11:10:27 +02:00
intense_mode = true ;
2016-01-06 12:10:58 +01:00
if ( strlen ( argv [ i ] ) > 8 ) {
2017-07-29 11:10:27 +02:00
int intense_mode_limit = 0 ;
2016-01-06 12:10:58 +01:00
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 ) ;
}
2017-07-29 11:10:27 +02:00
intense_mode_limit + = ( ( long long ) ( argv [ i ] [ j + 8 ] ) - ' 0 ' ) * multiplicator ;
2016-01-06 12:10:58 +01:00
if ( ( multiplicator * 10 ) < multiplicator ) {
error ( ERR_INTENSE_MODE_LIMIT_TOO_BIG ) ;
}
multiplicator * = 10 ;
}
2017-07-29 11:10:27 +02:00
intense_mode_depth_limit = intense_mode_limit ;
2016-01-06 12:10:58 +01:00
}
} 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 ' ) ) {
2017-07-17 21:45:14 +05:30
long_help = true ;
2017-04-05 16:49:58 +02:00
} 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 - - ) {
2018-02-12 19:37:06 +01:00
if ( ( argv [ i ] [ j + 3 ] < ' 0 ' ) | | ( argv [ i ] [ j + 3 ] > ' 9 ' ) ) {
2017-04-05 16:49:58 +02:00
printf ( " ERROR: Only numbers allowed for LZMA thread count \n " ) ;
exit ( 1 ) ;
}
2018-02-12 19:37:06 +01:00
compression_otf_thread_count + = ( ( unsigned int ) ( argv [ i ] [ j + 3 ] ) - ' 0 ' ) * multiplicator ;
2017-04-05 16:49:58 +02:00
if ( ( multiplicator * 10 ) < multiplicator ) {
exit ( 1 ) ;
}
multiplicator * = 10 ;
2017-07-17 21:45:14 +05:30
}
2017-04-05 16:49:58 +02:00
lzma_thread_count_set = true ;
2018-02-12 19:37:06 +01:00
} else if ( toupper ( argv [ i ] [ 2 ] ) = = ' F ' ) { // LZMA filters
if ( lzma_filters_set ) {
error ( ERR_ONLY_SET_LZMA_FILTERS_ONCE ) ;
}
switch ( argv [ i ] [ 3 ] ) {
case ' + ' :
break ;
case ' - ' :
if ( argv [ i ] [ 4 ] ! = 0 ) {
printf ( " ERROR: \" -lf- \" must not be followed by anything \n " ) ;
exit ( 1 ) ;
break ;
}
break ;
default :
printf ( " ERROR: Only + or - after \" -lf \" allowed \n " ) ;
exit ( 1 ) ;
break ;
}
int argindex = 4 ;
while ( argv [ i ] [ argindex ] ! = 0 ) {
switch ( toupper ( argv [ i ] [ argindex ] ) ) {
case ' X ' :
otf_xz_filter_enabled [ 0 ] = true ;
break ;
case ' P ' :
otf_xz_filter_enabled [ 1 ] = true ;
break ;
case ' I ' :
otf_xz_filter_enabled [ 2 ] = true ;
break ;
case ' A ' :
otf_xz_filter_enabled [ 3 ] = true ;
break ;
case ' T ' :
otf_xz_filter_enabled [ 4 ] = true ;
break ;
case ' S ' :
otf_xz_filter_enabled [ 5 ] = true ;
break ;
case ' D ' :
{
argindex + + ;
if ( ( argv [ i ] [ argindex ] ) = = 0 ) {
printf ( " ERROR: LZMA delta filter must be followed by a distance (1..256) \n " ) ;
exit ( 1 ) ;
}
otf_xz_filter_delta_enabled = true ;
int multiplicator = 1 ;
for ( j = strlen ( argv [ i ] ) - ( argindex + 1 ) ; j > = 0 ; j - - ) {
if ( ( argv [ i ] [ j + argindex ] < ' 0 ' ) | | ( argv [ i ] [ j + argindex ] > ' 9 ' ) ) {
printf ( " ERROR: Only numbers allowed for LZMA delta filter distance \n " ) ;
exit ( 1 ) ;
}
otf_xz_filter_delta_distance + = ( ( unsigned int ) ( argv [ i ] [ j + argindex ] ) - ' 0 ' ) * multiplicator ;
if ( ( multiplicator * 10 ) < multiplicator ) {
exit ( 1 ) ;
}
multiplicator * = 10 ;
}
if ( ( otf_xz_filter_delta_distance < 1 ) | | ( otf_xz_filter_delta_distance > 256 ) ) {
printf ( " ERROR: LZMA delta filter distance must be in range 1..256 \n " ) ;
exit ( 1 ) ;
}
break ;
}
default :
printf ( " ERROR: Unknown LZMA filter type \" %c \" \n " , argv [ i ] [ argindex ] ) ;
exit ( 1 ) ;
break ;
}
otf_xz_filter_used_count + + ;
if ( otf_xz_filter_used_count > 3 ) {
printf ( " ERROR: Only up to 3 LZMA filters can be used at the same time \n " ) ;
exit ( 1 ) ;
}
argindex + + ;
}
lzma_filters_set = true ;
break ;
2016-01-06 12:10:58 +01:00
} 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 ;
}
2017-12-28 22:14:09 +05:30
if ( argv [ i ] [ 8 ] ! = 0 ) {
printf ( " ERROR: Unknown switch \" %s \" \n " , argv [ i ] ) ;
exit ( 1 ) ;
}
2016-01-06 12:10:58 +01:00
} 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 ;
}
2017-12-28 22:14:09 +05:30
if ( argv [ i ] [ 8 ] ! = 0 ) {
printf ( " ERROR: Unknown switch \" %s \" \n " , argv [ i ] ) ;
exit ( 1 ) ;
}
2016-01-06 12:10:58 +01:00
} 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 ;
2016-01-17 16:49:34 +01:00
use_mp3 = false ;
2016-01-06 12:10:58 +01:00
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 ;
2016-01-17 16:49:34 +01:00
use_mp3 = true ;
2016-01-06 12:10:58 +01:00
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 ] ) ) {
2016-01-26 12:35:25 +01:00
case ' P ' : // PDF
2016-01-06 12:10:58 +01:00
use_pdf = set_to ;
break ;
2016-01-26 12:35:25 +01:00
case ' Z ' : // ZIP
2016-01-06 12:10:58 +01:00
use_zip = set_to ;
break ;
2016-01-26 12:35:25 +01:00
case ' G ' : // GZip
2016-01-06 12:10:58 +01:00
use_gzip = set_to ;
break ;
2016-01-26 12:35:25 +01:00
case ' N ' : // PNG
2016-01-06 12:10:58 +01:00
use_png = set_to ;
break ;
2016-01-26 12:35:25 +01:00
case ' F ' : // GIF
2016-01-06 12:10:58 +01:00
use_gif = set_to ;
break ;
2016-01-26 12:35:25 +01:00
case ' J ' : // JPG
2016-01-06 12:10:58 +01:00
use_jpg = set_to ;
break ;
2016-01-26 12:35:25 +01:00
case ' 3 ' : // MP3
2016-01-17 16:49:34 +01:00
use_mp3 = set_to ;
break ;
2016-01-26 12:35:25 +01:00
case ' S ' : // SWF
2016-01-06 12:10:58 +01:00
use_swf = set_to ;
break ;
2016-01-26 12:35:25 +01:00
case ' M ' : // MIME Base64
2016-01-06 12:10:58 +01:00
use_base64 = set_to ;
break ;
2016-01-26 12:35:25 +01:00
case ' B ' : // bZip2
2016-01-06 12:10:58 +01:00
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 ] ) ) {
2016-01-26 12:35:25 +01:00
case ' N ' : // no compression
2016-07-02 18:37:31 +02:00
compression_otf_method = OTF_NONE ;
2016-01-06 12:10:58 +01:00
break ;
case ' B ' : // bZip2
2016-07-02 18:37:31 +02:00
compression_otf_method = OTF_BZIP2 ;
2016-01-06 12:10:58 +01:00
break ;
2016-12-29 18:31:47 +01:00
case ' L ' : // lzma2 multithreaded
2016-07-02 18:37:31 +02:00
compression_otf_method = OTF_XZ_MT ;
2016-06-19 16:53:50 +08:00
break ;
2016-01-06 12:10:58 +01:00
default :
printf ( " ERROR: Invalid compression method %c \n " , argv [ i ] [ 2 ] ) ;
exit ( 1 ) ;
break ;
}
2017-12-28 22:14:09 +05:30
if ( argv [ i ] [ 3 ] ! = 0 ) { // Extra Parameters?
printf ( " ERROR: Unknown switch \" %s \" \n " , argv [ i ] ) ;
exit ( 1 ) ;
}
2017-06-16 07:31:37 +02:00
show_lzma_progress = ( compression_otf_method = = OTF_XZ_MT ) ;
2016-01-06 12:10:58 +01:00
break ;
}
case ' N ' :
{
switch ( toupper ( argv [ i ] [ 2 ] ) ) {
2016-01-26 12:35:25 +01:00
case ' N ' : // no compression
2016-07-02 18:37:31 +02:00
conversion_to_method = OTF_NONE ;
2016-01-06 12:10:58 +01:00
break ;
case ' B ' : // bZip2
2016-07-02 18:37:31 +02:00
conversion_to_method = OTF_BZIP2 ;
2016-01-06 12:10:58 +01:00
break ;
2016-12-29 18:31:47 +01:00
case ' L ' : // lzma2 multithreaded
2016-07-02 18:37:31 +02:00
conversion_to_method = OTF_XZ_MT ;
2016-07-02 18:24:23 +02:00
break ;
2016-01-06 12:10:58 +01:00
default :
printf ( " ERROR: Invalid conversion method %c \n " , argv [ i ] [ 2 ] ) ;
exit ( 1 ) ;
break ;
}
2017-12-28 22:14:09 +05:30
if ( argv [ i ] [ 3 ] ! = 0 ) { // Extra Parameters?
printf ( " ERROR: Unknown switch \" %s \" \n " , argv [ i ] ) ;
exit ( 1 ) ;
}
2016-01-06 12:10:58 +01:00
operation = P_CONVERT ;
break ;
}
case ' V ' :
{
DEBUG_MODE = true ;
2017-12-28 22:14:09 +05:30
if ( argv [ i ] [ 2 ] ! = 0 ) { // Extra Parameters?
printf ( " ERROR: Unknown switch \" %s \" \n " , argv [ i ] ) ;
exit ( 1 ) ;
}
2016-01-06 12:10:58 +01:00
break ;
}
case ' R ' :
{
operation = P_DECOMPRESS ;
2017-12-28 22:14:09 +05:30
if ( argv [ i ] [ 2 ] ! = 0 ) { // Extra Parameters?
printf ( " ERROR: Unknown switch \" %s \" \n " , argv [ i ] ) ;
exit ( 1 ) ;
}
2016-01-06 12:10:58 +01:00
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 ) ;
2016-01-26 12:35:25 +01:00
// check for backslash in file name
2016-01-06 12:10:58 +01:00
char * backslash_at_pos = strrchr ( output_file_name , PATH_DELIM ) ;
2016-01-26 12:35:25 +01:00
// dot in output file name? If not, use .pcf extension
2016-01-06 12:10:58 +01:00
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 ;
}
2017-12-28 22:14:09 +05:30
if ( argv [ i ] [ 7 ] ! = 0 ) { // Extra Parameters?
printf ( " ERROR: Unknown switch \" %s \" \n " , argv [ i ] ) ;
exit ( 1 ) ;
}
2016-01-06 12:10:58 +01:00
} 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 ;
2017-12-28 22:14:09 +05:30
if ( argv [ i ] [ 2 ] ! = 0 ) { // Extra Parameters?
printf ( " ERROR: Unknown switch \" %s \" \n " , argv [ i ] ) ;
exit ( 1 ) ;
}
2016-01-06 12:10:58 +01:00
break ;
}
2017-07-17 21:45:14 +05:30
case ' E ' :
{
preserve_extension = true ;
2017-12-28 22:14:09 +05:30
if ( argv [ i ] [ 2 ] ! = 0 ) { // Extra Parameters?
printf ( " ERROR: Unknown switch \" %s \" \n " , argv [ i ] ) ;
exit ( 1 ) ;
}
2017-07-17 21:45:14 +05:30
break ;
}
2016-01-06 12:10:58 +01:00
default :
{
printf ( " ERROR: Unknown switch \" %s \" \n " , argv [ i ] ) ;
exit ( 1 ) ;
}
}
2016-01-26 12:35:25 +01:00
} else { // no switch
2016-01-06 12:10:58 +01:00
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 ) ;
}
2016-01-26 12:35:25 +01:00
// output file given? If not, use input filename with .pcf extension
2016-01-06 12:10:58 +01:00
if ( ( ! output_file_given ) & & ( operation = = P_COMPRESS ) ) {
2017-07-17 21:45:14 +05:30
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 " ) ;
}
}
2016-01-06 12:10:58 +01:00
} else {
2017-07-17 21:45:14 +05:30
output_file_name = new char [ strlen ( input_file_name ) + 9 ] ;
strcpy ( output_file_name , input_file_name ) ;
strcat ( output_file_name , " .pcf " ) ;
2016-01-06 12:10:58 +01:00
}
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 " ) ;
2017-12-27 11:09:22 +01:00
printf ( " e preserve original extension of input name for output name <off> \n " ) ;
2016-12-29 18:31:47 +01:00
printf ( " c[lbn] Compression method to use, l = lzma2, b = bZip2, n = none <l> \n " ) ;
2017-04-05 16:49:58 +02:00
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 ( ) ) ;
2017-12-27 11:27:04 +01:00
if ( long_help ) {
2018-02-12 19:37:06 +01:00
printf ( " lf[+-][xpiatsd] Set LZMA filters (up to 3 of them can be combined) <none> \n " ) ;
2017-12-27 11:27:04 +01:00
printf ( " lf+[xpiatsd] = enable these filters, lf- = disable all \n " ) ;
printf ( " X = x86, P = PowerPC, I = IA-64, A = ARM, T = ARM-Thumb \n " ) ;
2017-12-29 11:01:14 +01:00
printf ( " S = SPARC, D = delta (must be followed by distance 1..256) \n " ) ;
2017-12-27 11:27:04 +01:00
} else {
2018-02-12 19:37:06 +01:00
printf ( " lf[+-][xpiatsd] Set LZMA filters (up to 3, see long help for details) <none> \n " ) ;
2017-12-27 11:27:04 +01:00
}
2017-04-05 16:51:54 +02:00
printf ( " n[lbn] Convert a PCF file to this compression (same as above) <off> \n " ) ;
2016-01-06 12:10:58 +01:00
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 " ) ;
}
2016-01-17 16:49:34 +01:00
printf ( " t[+-][pzgnfjsmb3] Compression type switch <all enabled> \n " ) ;
2016-01-06 12:10:58 +01:00
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 " ) ;
2016-01-17 16:49:34 +01:00
printf ( " S = SWF, M = MIME Base64, B = bZip2, 3 = MP3 \n " ) ;
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
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 ) {
2016-01-26 12:35:25 +01:00
// if .pcf was appended, remove it
2016-01-06 12:10:58 +01:00
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 {
2016-02-13 10:48:56 +01:00
# ifndef UNIX
2016-01-06 12:10:58 +01:00
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 ;
}
2016-01-17 16:34:42 +01:00
packjpg_mp3_dll_msg ( ) ;
2016-01-06 12:10:58 +01:00
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 ;
2017-04-05 16:49:58 +02:00
bool lzma_max_memory_set = false ;
bool lzma_thread_count_set = false ;
2017-07-17 21:45:14 +05:30
bool preserve_extension = false ;
2016-01-06 12:10:58 +01:00
printf ( " \n " ) ;
if ( V_MINOR2 = = 0 ) {
2016-12-28 16:52:45 +01:00
printf ( " Precomp Comfort v%i.%i %s %s - %s version " , V_MAJOR , V_MINOR , V_OS , V_BIT , V_STATE ) ;
2016-01-06 12:10:58 +01:00
} else {
2016-12-28 16:52:45 +01:00
printf ( " Precomp Comfort v%i.%i.%i %s %s - %s version " , V_MAJOR , V_MINOR , V_MINOR2 , V_OS , V_BIT , V_STATE ) ;
2016-01-06 12:10:58 +01:00
}
printf ( " - %s \n " , V_MSG ) ;
2018-01-02 14:10:46 +01:00
printf ( " Free for non-commercial use - Copyright 2006-2018 by Christian Schneider \n \n " ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// init compression and memory level count
2016-01-06 12:10:58 +01:00
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 ;
}
2017-05-04 11:24:52 +08:00
// 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 ;
2018-02-12 19:37:06 +01:00
// init LZMA filters
for ( int i = 0 ; i < 6 ; i + + ) {
otf_xz_filter_enabled [ 6 ] = false ;
}
2016-01-26 12:35:25 +01:00
// parse parameters (should be input file only)
2016-01-06 12:10:58 +01:00
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 ) ;
}
2016-01-26 12:35:25 +01:00
2016-03-19 09:13:54 +01:00
if ( fin_length > 6 ) {
2016-01-06 12:10:58 +01:00
if ( check_for_pcf_file ( ) ) {
operation = P_DECOMPRESS ;
}
}
}
2016-01-26 12:35:25 +01:00
// precomf.ini in EXE directory?
2016-01-06 12:10:58 +01:00
char precomf_ini [ 1024 ] ;
2016-06-12 23:20:00 +08:00
# ifdef _MSC_VER
# ifdef UNICODE
# define GetModuleFileName GetModuleFileNameA
# endif // UNICODE
# endif // _MSC_VER
2016-01-06 12:10:58 +01:00
GetModuleFileName ( NULL , precomf_ini , 1024 ) ;
2016-01-26 12:35:25 +01:00
// truncate to get directory of executable only
2016-01-06 12:10:58 +01:00
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 " ) ;
2016-12-28 16:52:45 +01:00
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 ) ;
2016-01-06 12:10:58 +01:00
fprintf ( fnewini , " ;; Use a semicolon (;) for comments \n \n " ) ;
fprintf ( fnewini , " ;; Compression method to use \n " ) ;
2016-12-29 18:31:47 +01:00
fprintf ( fnewini , " ;; 0 = none, 1 = bZip2, 2 = lzma2 multi-threaded \n " ) ;
2017-04-05 16:49:58 +02:00
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 " ) ;
2017-12-27 11:27:04 +01:00
fprintf ( fnewini , " ;; LZMA filters to use (up to 3 of the them can be combined) \n " ) ;
fprintf ( fnewini , " ;; X = x86, P = PowerPC, I = IA-64, A = ARM, T = ARM-Thumb \n " ) ;
2018-02-12 19:37:06 +01:00
fprintf ( fnewini , " ;; S = SPARC, D = delta (must be followed by distance 1..256)) \n " ) ;
fprintf ( fnewini , " ;; The default is to disable all filters \n " ) ;
fprintf ( fnewini , " LZMA_Filters= \n " ) ;
2016-01-06 12:10:58 +01:00
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 " ) ;
2017-07-17 21:45:14 +05:30
fprintf ( fnewini , " ;; Preserve Input's file extension (on/off) \n " ) ;
fprintf ( fnewini , " Preserve_Extension=off \n \n " ) ;
2016-01-06 12:10:58 +01:00
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 " ) ;
2016-01-17 16:49:34 +01:00
fprintf ( fnewini , " ;; M = MIME Base64, B = bZip2, 3 = MP3 \n " ) ;
2017-07-24 12:59:43 +02:00
fprintf ( fnewini , " ; Compression_Types_Enable=PZGNFJSMB3 \n " ) ;
fprintf ( fnewini , " ; Compression_Types_Disable=PZGNFJSMB3 \n \n " ) ;
2016-01-06 12:10:58 +01:00
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 ;
2017-04-05 16:49:58 +02:00
compression_otf_max_memory = 2048 ;
lzma_max_memory_set = true ;
2017-07-17 21:45:14 +05:30
lzma_thread_count_set = true ;
2016-01-06 12:10:58 +01:00
parse_ini_file = false ;
}
}
if ( parse_ini_file ) {
2016-01-26 12:35:25 +01:00
// parse INI file
2016-01-06 12:10:58 +01:00
bool print_ignore_positions_message = true ;
2017-07-24 12:59:43 +02:00
bool compression_type_line_used = false ;
2016-01-06 12:10:58 +01:00
ifstream ini_file ( precomf_ini ) ;
string line ;
string parName , valuestr ;
string : : iterator it ;
char param [ 256 ] , value [ 256 ] ;
2017-07-17 21:45:14 +05:30
while ( getline ( ini_file , line ) ) {
2016-01-06 12:10:58 +01:00
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 ) ;
}
2016-01-26 12:35:25 +01:00
// valid line must contain an equal sign (=)
2016-01-06 12:10:58 +01:00
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 ;
2016-01-26 12:35:25 +01:00
// get parameter name
2016-01-06 12:10:58 +01:00
getline ( ss , parName , ' = ' ) ;
2016-01-26 12:35:25 +01:00
// remove spaces
2016-01-06 12:10:58 +01:00
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 ) ;
2017-07-17 21:45:14 +05:30
2016-01-26 12:35:25 +01:00
// get value
2016-01-06 12:10:58 +01:00
getline ( ss , valuestr ) ;
2016-01-26 12:35:25 +01:00
// remove spaces
2016-01-06 12:10:58 +01:00
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 ) ;
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
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 " ) ;
2016-07-02 18:37:31 +02:00
compression_otf_method = OTF_NONE ;
2016-01-06 12:10:58 +01:00
valid_param = true ;
}
if ( strcmp ( value , " 1 " ) = = 0 ) {
printf ( " INI: Using bZip2 compression method \n " ) ;
2016-07-02 18:37:31 +02:00
compression_otf_method = OTF_BZIP2 ;
2016-01-06 12:10:58 +01:00
valid_param = true ;
}
2016-06-19 16:53:50 +08:00
if ( strcmp ( value , " 2 " ) = = 0 ) {
2016-12-29 18:31:47 +01:00
printf ( " INI: Using lzma2 multithreaded compression method \n " ) ;
2016-08-27 12:28:26 +02:00
compression_otf_method = OTF_XZ_MT ;
2016-06-19 16:53:50 +08:00
valid_param = true ;
}
2017-07-17 21:45:14 +05:30
2017-06-16 07:31:37 +02:00
show_lzma_progress = ( compression_otf_method = = OTF_XZ_MT ) ;
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
if ( ! valid_param ) {
printf ( " ERROR: Invalid compression method value: %s \n " , value ) ;
wait_for_key ( ) ;
exit ( 1 ) ;
}
}
2017-07-17 21:45:14 +05:30
2017-04-05 16:49:58 +02:00
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 ) ;
}
2017-07-17 21:45:14 +05:30
2017-04-05 16:49:58 +02:00
valid_param = true ;
}
2017-07-17 21:45:14 +05:30
2017-04-05 16:49:58 +02:00
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 ;
2016-01-06 12:10:58 +01:00
2017-04-05 16:49:58 +02:00
if ( compression_otf_thread_count > 0 ) {
printf ( " INI: Set LZMA thread count to %i \n " , compression_otf_thread_count ) ;
}
2017-07-17 21:45:14 +05:30
2017-04-05 16:49:58 +02:00
valid_param = true ;
}
2018-02-12 19:37:06 +01:00
if ( strcmp ( param , " lzma_filters " ) = = 0 ) {
if ( lzma_filters_set ) {
error ( ERR_ONLY_SET_LZMA_FILTERS_ONCE ) ;
}
for ( j = 0 ; j < ( int ) strlen ( value ) ; j + + ) {
switch ( toupper ( argv [ i ] [ j ] ) ) {
case ' X ' :
otf_xz_filter_enabled [ 0 ] = true ;
break ;
case ' P ' :
otf_xz_filter_enabled [ 1 ] = true ;
break ;
case ' I ' :
otf_xz_filter_enabled [ 2 ] = true ;
break ;
case ' A ' :
otf_xz_filter_enabled [ 3 ] = true ;
break ;
case ' T ' :
otf_xz_filter_enabled [ 4 ] = true ;
break ;
case ' S ' :
otf_xz_filter_enabled [ 5 ] = true ;
break ;
case ' D ' :
j + + ;
if ( ( argv [ i ] [ j ] ) = = 0 ) {
printf ( " ERROR: LZMA delta filter must be followed by a distance (1..256) \n " ) ;
exit ( 1 ) ;
}
otf_xz_filter_delta_enabled = true ;
int multiplicator = 1 ;
for ( k = ( strlen ( value ) - ( j + 1 ) ; k > = 0 ; k - - ) {
if ( ( argv [ i ] [ j + k ] < ' 0 ' ) | | ( argv [ i ] [ j + k ] > ' 9 ' ) ) {
printf ( " ERROR: Only numbers allowed for LZMA delta filter distance \n " ) ;
exit ( 1 ) ;
}
otf_xz_filter_delta_distance + = ( ( unsigned int ) ( argv [ i ] [ j + k ] ) - ' 0 ' ) * multiplicator ;
if ( multiplicator * 10 ) < multiplicator ) {
exit ( 1 ) ;
}
multiplicator * = 10 ;
}
if ( ( otf_xz_filter_delta_distance < 1 ) | | ( otf_xz_filter_delta_distance > 256 ) ) {
printf ( " ERROR: LZMA delta filter distance must be in range 1..256 \n );
exit ( 1 ) ;
}
break ;
default :
printf ( " ERROR: Unknown LZMA filter type \" %c \" \n " , argv [ i ] [ j ] ) ;
exit ( 1 ) ;
break ;
}
otf_xz_filter_used_count + + ;
if ( otf_xz_filter_used_count > 3 ) {
printf ( " ERROR: Only up to 3 LZMA filters can be used at the same time \n " ) ;
exit ( 1 ) ;
}
}
lzma_filters_set = true ;
valid_param = true ;
}
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
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 ) ;
}
}
2017-07-17 21:45:14 +05:30
// 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 ;
}
2016-01-06 12:10:58 +01:00
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 " ) ;
2017-07-29 11:10:27 +02:00
intense_mode = true ;
2016-01-06 12:10:58 +01:00
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 ) ;
}
}
2017-07-24 12:59:43 +02:00
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 ;
2016-01-06 12:10:58 +01:00
use_pdf = false ;
use_zip = false ;
use_gzip = false ;
use_png = false ;
use_gif = false ;
use_jpg = false ;
2016-01-17 16:49:34 +01:00
use_mp3 = false ;
2016-01-06 12:10:58 +01:00
use_swf = false ;
use_base64 = false ;
use_bzip2 = false ;
for ( j = 0 ; j < ( int ) strlen ( value ) ; j + + ) {
switch ( toupper ( value [ j ] ) ) {
2016-01-26 12:35:25 +01:00
case ' P ' : // PDF
2016-01-06 12:10:58 +01:00
use_pdf = true ;
break ;
2016-01-26 12:35:25 +01:00
case ' Z ' : // ZIP
2016-01-06 12:10:58 +01:00
use_zip = true ;
break ;
2016-01-26 12:35:25 +01:00
case ' G ' : // GZip
2016-01-06 12:10:58 +01:00
use_gzip = true ;
break ;
2016-01-26 12:35:25 +01:00
case ' N ' : // PNG
2016-01-06 12:10:58 +01:00
use_png = true ;
break ;
2016-01-26 12:35:25 +01:00
case ' F ' : // GIF
2016-01-06 12:10:58 +01:00
use_gif = true ;
break ;
2016-01-26 12:35:25 +01:00
case ' J ' : // JPG
2016-01-06 12:10:58 +01:00
use_jpg = true ;
break ;
2016-01-26 12:35:25 +01:00
case ' 3 ' : // MP3
2016-01-17 16:49:34 +01:00
use_mp3 = true ;
break ;
2016-01-26 12:35:25 +01:00
case ' S ' : // SWF
2016-01-06 12:10:58 +01:00
use_swf = true ;
break ;
2016-01-26 12:35:25 +01:00
case ' M ' : // MIME Base64
2016-01-06 12:10:58 +01:00
use_base64 = true ;
break ;
2016-01-26 12:35:25 +01:00
case ' B ' : // bZip2
2016-01-06 12:10:58 +01:00
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 " ) ;
2017-07-17 21:45:14 +05:30
}
2016-01-06 12:10:58 +01:00
if ( use_zip ) {
printf ( " INI: ZIP compression enabled \n " ) ;
} else {
printf ( " INI: ZIP compression disabled \n " ) ;
2017-07-17 21:45:14 +05:30
}
2016-01-06 12:10:58 +01:00
if ( use_gzip ) {
printf ( " INI: GZip compression enabled \n " ) ;
} else {
printf ( " INI: GZip compression disabled \n " ) ;
2017-07-17 21:45:14 +05:30
}
2016-01-06 12:10:58 +01:00
if ( use_png ) {
printf ( " INI: PNG compression enabled \n " ) ;
} else {
printf ( " INI: PNG compression disabled \n " ) ;
2017-07-17 21:45:14 +05:30
}
2016-01-06 12:10:58 +01:00
if ( use_gif ) {
printf ( " INI: GIF compression enabled \n " ) ;
} else {
printf ( " INI: GIF compression disabled \n " ) ;
2017-07-17 21:45:14 +05:30
}
2016-01-06 12:10:58 +01:00
if ( use_jpg ) {
printf ( " INI: JPG compression enabled \n " ) ;
} else {
printf ( " INI: JPG compression disabled \n " ) ;
2017-07-17 21:45:14 +05:30
}
2016-01-06 12:10:58 +01:00
2016-01-17 16:49:34 +01:00
if ( use_mp3 ) {
printf ( " INI: MP3 compression enabled \n " ) ;
} else {
printf ( " INI: MP3 compression disabled \n " ) ;
2017-07-17 21:45:14 +05:30
}
2016-01-17 16:49:34 +01:00
2016-01-06 12:10:58 +01:00
if ( use_swf ) {
printf ( " INI: SWF compression enabled \n " ) ;
} else {
printf ( " INI: SWF compression disabled \n " ) ;
2017-07-17 21:45:14 +05:30
}
2016-01-06 12:10:58 +01:00
if ( use_base64 ) {
printf ( " INI: Base64 compression enabled \n " ) ;
} else {
printf ( " INI: Base64 compression disabled \n " ) ;
2017-07-17 21:45:14 +05:30
}
2016-01-06 12:10:58 +01:00
if ( use_bzip2 ) {
printf ( " INI: bZip2 compression enabled \n " ) ;
} else {
printf ( " INI: bZip2 compression disabled \n " ) ;
2017-07-17 21:45:14 +05:30
}
2016-01-06 12:10:58 +01:00
valid_param = true ;
}
2017-07-24 12:59:43 +02:00
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 ;
}
2016-01-26 12:35:25 +01:00
// zLib levels
2016-01-06 12:10:58 +01:00
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 ) ;
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
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 ( ) ;
}
2017-07-17 21:45:14 +05:30
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 " ) ;
}
}
2016-01-06 12:10:58 +01:00
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 ;
}
2016-01-17 16:34:42 +01:00
packjpg_mp3_dll_msg ( ) ;
2016-01-06 12:10:58 +01:00
return operation ;
}
# endif
# endif
void denit_compress ( ) {
2016-07-02 18:37:31 +02:00
if ( compression_otf_method ! = OTF_NONE ) {
2016-01-06 12:10:58 +01:00
denit_compress_otf ( ) ;
}
safe_fclose ( & fin ) ;
safe_fclose ( & fout ) ;
2017-06-16 07:31:37 +02:00
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
}
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
# ifndef PRECOMPDLL
long long fout_length = fileSize64 ( output_file_name ) ;
if ( recursion_depth = = 0 ) {
if ( ! DEBUG_MODE ) {
2017-06-16 07:31:37 +02:00
printf ( string ( 14 , ' \b ' ) . c_str ( ) ) ;
2016-01-06 12:10:58 +01:00
printf ( " 100.00%% - New size: " ) ;
print64 ( fout_length ) ;
printf ( " instead of " ) ;
print64 ( fin_length ) ;
2017-06-16 07:31:37 +02:00
printf ( " \n " ) ;
2016-01-06 12:10:58 +01:00
} else {
printf ( " New size: " ) ;
print64 ( fout_length ) ;
printf ( " instead of " ) ;
print64 ( fin_length ) ;
2017-06-16 07:31:37 +02:00
printf ( " \n " ) ;
2016-01-06 12:10:58 +01:00
}
}
# else
if ( recursion_depth = = 0 ) {
if ( ! DEBUG_MODE ) {
2017-06-16 07:31:37 +02:00
printf ( string ( 14 , ' \b ' ) . c_str ( ) ) ;
printf ( " 100.00%% - " ) ;
2016-01-06 12:10:58 +01:00
printf_time ( get_time_ms ( ) - start_time ) ;
}
}
# endif
# ifndef PRECOMPDLL
if ( recursion_depth = = 0 ) {
printf ( " \n Done. \n " ) ;
printf_time ( get_time_ms ( ) - start_time ) ;
2016-01-26 12:35:25 +01:00
// statistics
2016-01-06 12:10:58 +01:00
printf ( " \n Recompressed 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 ) ;
2016-01-17 16:49:34 +01:00
if ( ( use_mp3 ) & & ( ( recompressed_mp3_count > 0 ) | | ( decompressed_mp3_count > 0 ) ) ) printf ( " MP3 streams: %i/%i \n " , recompressed_mp3_count , decompressed_mp3_count ) ;
2016-01-06 12:10:58 +01:00
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 ) ;
2017-07-29 11:10:27 +02:00
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 ) ;
2016-01-06 12:10:58 +01:00
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 ) ;
}
2017-08-30 06:46:26 +02:00
if ( decomp_io_buf ! = NULL ) delete [ ] decomp_io_buf ;
2016-01-06 12:10:58 +01:00
denit ( ) ;
}
void denit_decompress ( ) {
# ifndef PRECOMPDLL
if ( recursion_depth = = 0 ) {
if ( ! DEBUG_MODE ) {
2017-06-16 07:31:37 +02:00
printf ( string ( 14 , ' \b ' ) . c_str ( ) ) ;
2016-01-06 12:10:58 +01:00
printf ( " 100.00%% \n " ) ;
}
printf ( " \n Done. \n " ) ;
printf_time ( get_time_ms ( ) - start_time ) ;
}
# else
if ( recursion_depth = = 0 ) {
if ( ! DEBUG_MODE ) {
2017-06-16 07:31:37 +02:00
printf ( string ( 14 , ' \b ' ) . c_str ( ) ) ;
printf ( " 100.00%% - " ) ;
2016-01-06 12:10:58 +01:00
printf_time ( get_time_ms ( ) - start_time ) ;
}
}
# endif
2016-07-02 18:37:31 +02:00
if ( compression_otf_method ! = OTF_NONE ) {
2016-01-06 12:10:58 +01:00
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 ( ) {
2016-01-14 11:57:58 +01:00
safe_fclose ( & fin ) ;
safe_fclose ( & fout ) ;
2017-06-27 07:16:05 +02:00
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
}
2017-07-17 21:45:14 +05:30
2016-01-14 11:57:58 +01:00
long long fout_length = fileSize64 ( output_file_name ) ;
2016-01-06 12:10:58 +01:00
# ifndef PRECOMPDLL
if ( ! DEBUG_MODE ) {
2017-06-16 07:31:37 +02:00
printf ( string ( 14 , ' \b ' ) . c_str ( ) ) ;
2016-01-14 11:57:58 +01:00
printf ( " 100.00%% - New size: " ) ;
print64 ( fout_length ) ;
printf ( " instead of " ) ;
print64 ( fin_length ) ;
2017-06-16 07:31:37 +02:00
printf ( " \n " ) ;
2016-01-14 12:07:44 +01:00
} else {
printf ( " New size: " ) ;
print64 ( fout_length ) ;
printf ( " instead of " ) ;
print64 ( fin_length ) ;
2017-06-16 07:31:37 +02:00
printf ( " \n " ) ;
2017-07-17 21:45:14 +05:30
}
2016-01-06 12:10:58 +01:00
printf ( " \n Done. \n " ) ;
printf_time ( get_time_ms ( ) - start_time ) ;
# else
if ( ! DEBUG_MODE ) {
2017-06-16 07:31:37 +02:00
printf ( string ( 14 , ' \b ' ) . c_str ( ) ) ;
printf ( " 100.00%% - New size: " ) ;
2016-01-14 11:57:58 +01:00
print64 ( fout_length ) ;
printf ( " instead of " ) ;
print64 ( fin_length ) ;
2017-06-16 07:31:37 +02:00
printf ( " \n " ) ;
2016-01-06 12:10:58 +01:00
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 ;
}
2017-08-14 07:01:31 +02:00
// Brute mode detects a bit less than intense mode to avoid false positives
// and slowdowns, so both can be active. Also, both of them can have a level
// limit, so two helper functions make things easier to handle.
2017-07-29 11:22:09 +02:00
bool intense_mode_is_active ( ) {
2017-08-14 07:01:31 +02:00
if ( ! intense_mode ) return false ;
2017-07-29 11:22:09 +02:00
if ( ( intense_mode_depth_limit = = - 1 ) | | ( recursion_depth < = intense_mode_depth_limit ) ) return true ;
2017-12-28 22:14:09 +05:30
2017-07-29 11:22:09 +02:00
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 ;
2017-12-28 22:14:09 +05:30
2017-07-29 11:22:09 +02:00
return false ;
}
2016-06-02 07:07:05 +02:00
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 ;
}
}
2016-01-06 12:10:58 +01:00
# define DEF_COMPARE_CHUNK 512
2017-08-29 17:23:15 +02:00
int def_compare ( FILE * compfile , int level , int windowbits , int memlevel , int & decompressed_bytes_used , int decompressed_bytes_total , bool in_memory ) {
2016-01-06 12:10:58 +01:00
int ret , flush ;
unsigned have ;
z_stream strm ;
long long identical_bytes_compare = 0 ;
int comp_pos = 0 ;
2016-05-28 09:54:57 +02:00
decompressed_bytes_used = 0 ;
2016-01-06 12:10:58 +01:00
/* 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 ;
2016-06-02 07:07:05 +02:00
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 ;
2017-08-29 17:23:15 +02:00
unsigned char * buf_ptr = decomp_io_buf ;
int buf_pos = 0 ;
2016-01-06 12:10:58 +01:00
/* compress until end of file */
do {
print_work_sign ( true ) ;
2017-08-29 17:23:15 +02:00
if ( in_memory ) {
strm . avail_in = min ( decompressed_bytes_total - buf_pos , DEF_COMPARE_CHUNK ) ;
strm . next_in = buf_ptr + buf_pos ;
buf_pos + = strm . avail_in ;
flush = ( buf_pos > = decompressed_bytes_total ) ? Z_FINISH : Z_NO_FLUSH ;
} else {
strm . avail_in = own_fread ( in , 1 , DEF_COMPARE_CHUNK , ftempout ) ;
if ( ferror ( ftempout ) ) {
( void ) deflateEnd ( & strm ) ;
return - 1 ;
}
flush = feof ( ftempout ) ? Z_FINISH : Z_NO_FLUSH ;
strm . next_in = in ;
2016-01-06 12:10:58 +01:00
}
2016-05-28 09:54:57 +02:00
decompressed_bytes_used + = strm . avail_in ;
2016-01-06 12:10:58 +01:00
do {
strm . avail_out = DEF_COMPARE_CHUNK ;
strm . next_out = out ;
ret = deflate ( & strm , flush ) ;
have = DEF_COMPARE_CHUNK - strm . avail_out ;
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
if ( have > 0 ) {
if ( compfile = = fin ) {
2016-06-02 07:07:05 +02:00
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 ) ;
2016-01-06 12:10:58 +01:00
} else {
2016-06-02 07:07:05 +02:00
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 ) ;
2016-01-06 12:10:58 +01:00
}
}
if ( have > 0 ) {
if ( ( unsigned int ) identical_bytes_compare < ( have > > 1 ) ) {
( void ) deflateEnd ( & strm ) ;
2016-06-02 07:07:05 +02:00
copy_penalty_bytes ( rek_penalty_bytes_len , use_penalty_bytes ) ;
return rek_same_byte_count ;
2016-01-06 12:10:58 +01:00
}
}
comp_pos + = have ;
} while ( strm . avail_out = = 0 ) ;
} while ( flush ! = Z_FINISH ) ;
( void ) deflateEnd ( & strm ) ;
2016-06-02 07:07:05 +02:00
copy_penalty_bytes ( rek_penalty_bytes_len , use_penalty_bytes ) ;
return rek_same_byte_count ;
2016-01-06 12:10:58 +01:00
}
2016-06-02 07:07:05 +02:00
int def_compare_bzip2 ( FILE * source , FILE * compfile , int level , int & decompressed_bytes_used ) {
2016-05-30 13:54:09 +02:00
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 ;
2016-06-02 07:07:05 +02:00
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 ;
2017-07-17 21:45:14 +05:30
2016-05-30 13:54:09 +02:00
/* 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 ) {
2016-06-02 07:07:05 +02:00
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 ) ;
2016-05-30 13:54:09 +02:00
} else {
2016-06-02 07:07:05 +02:00
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 ) ;
2016-05-30 13:54:09 +02:00
}
}
if ( have > 0 ) {
if ( ( unsigned int ) identical_bytes_compare < ( have > > 1 ) ) {
( void ) BZ2_bzCompressEnd ( & strm ) ;
2016-06-02 07:07:05 +02:00
copy_penalty_bytes ( rek_penalty_bytes_len , use_penalty_bytes ) ;
return rek_same_byte_count ;
2016-05-30 13:54:09 +02:00
}
}
comp_pos + = have ;
} while ( strm . avail_out = = 0 ) ;
} while ( flush ! = BZ_FINISH ) ;
( void ) BZ2_bzCompressEnd ( & strm ) ;
2016-06-02 07:07:05 +02:00
copy_penalty_bytes ( rek_penalty_bytes_len , use_penalty_bytes ) ;
return rek_same_byte_count ;
2016-05-30 13:54:09 +02:00
}
2016-01-06 12:10:58 +01:00
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 ;
}
2016-01-26 12:35:25 +01:00
// skip padding bytes
2016-01-06 12:10:58 +01:00
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 ;
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
/* 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 ;
}
2017-08-29 17:23:15 +02:00
int inf ( FILE * source , int windowbits , int & compressed_stream_size , int & decompressed_stream_size , bool & in_memory ) {
2016-01-06 12:10:58 +01:00
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 ;
2016-06-05 11:49:48 +02:00
compressed_stream_size = 0 ;
2017-08-29 17:23:15 +02:00
decompressed_stream_size = 0 ;
2016-06-05 11:49:48 +02:00
int avail_in_before ;
2017-12-28 22:14:09 +05:30
2016-01-06 12:10:58 +01:00
/* decompress until deflate stream ends or end of file */
do {
print_work_sign ( true ) ;
strm . avail_in = own_fread ( in , 1 , CHUNK , source ) ;
2016-06-05 11:49:48 +02:00
avail_in_before = strm . avail_in ;
2016-01-06 12:10:58 +01:00
if ( ferror ( source ) ) {
( void ) inflateEnd ( & strm ) ;
2017-08-29 17:23:15 +02:00
if ( ! in_memory ) safe_fclose ( & ftempout ) ;
2016-01-06 12:10:58 +01:00
return Z_ERRNO ;
}
if ( strm . avail_in = = 0 )
break ;
strm . next_in = in ;
/* run inflate() on input until output buffer not full */
2017-08-29 17:23:15 +02:00
unsigned char * buf_ptr ;
2016-01-06 12:10:58 +01:00
do {
strm . avail_out = CHUNK ;
2017-12-26 10:16:33 +01:00
if ( in_memory ) {
2017-09-04 13:04:44 +02:00
buf_ptr = decomp_io_buf + decompressed_stream_size ;
strm . next_out = buf_ptr ;
2017-12-26 10:16:33 +01:00
}
else {
2017-09-04 13:04:44 +02:00
strm . next_out = out ;
2017-12-26 10:16:33 +01:00
}
2016-01-06 12:10:58 +01:00
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 ) ;
2017-08-29 17:23:15 +02:00
if ( ! in_memory ) safe_fclose ( & ftempout ) ;
2016-01-06 12:10:58 +01:00
return ret ;
}
2016-06-05 11:49:48 +02:00
compressed_stream_size + = ( avail_in_before - strm . avail_in ) ;
avail_in_before = strm . avail_in ;
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
have = CHUNK - strm . avail_out ;
2017-08-29 17:23:15 +02:00
if ( ! in_memory ) {
if ( own_fwrite ( out , 1 , have , ftempout ) ! = have | | ferror ( ftempout ) ) {
( void ) inflateEnd ( & strm ) ;
safe_fclose ( & ftempout ) ;
return Z_ERRNO ;
}
2017-12-26 10:16:33 +01:00
}
else {
if ( ( decompressed_stream_size + have + CHUNK ) > = MAX_IO_BUFFER_SIZE ) {
in_memory = false ;
write_ftempout_if_not_present ( decompressed_stream_size + have , true , true ) ;
}
}
decompressed_stream_size + = have ;
2016-01-06 12:10:58 +01:00
} while ( strm . avail_out = = 0 ) ;
/* done when inflate() says it's done */
} while ( ret ! = Z_STREAM_END ) ;
/* clean up and return */
( void ) inflateEnd ( & strm ) ;
2017-08-29 17:23:15 +02:00
if ( ! in_memory ) safe_fclose ( & ftempout ) ;
2016-01-06 12:10:58 +01:00
return ret = = Z_STREAM_END ? Z_OK : Z_DATA_ERROR ;
}
2017-08-21 06:54:43 +02:00
int histogram [ 256 ] ;
2017-08-13 11:09:44 +02:00
bool check_inf_result ( int cb_pos , int windowbits , bool use_brute_parameters = false ) {
2017-08-04 06:58:54 +02:00
// first check BTYPE bits, skip 11 ("reserved (error)")
2017-07-03 08:38:28 +02:00
int btype = ( in_buf [ cb_pos ] & 0x07 ) > > 1 ;
2017-08-04 06:58:54 +02:00
if ( btype = = 3 ) return false ;
2017-08-13 11:09:44 +02:00
// 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
2017-08-21 06:54:43 +02:00
if ( use_brute_parameters ) {
if ( btype = = 0 ) return false ;
2017-12-28 22:14:09 +05:30
2017-08-21 06:54:43 +02:00
// use a histogram to see if the first 64 bytes are too redundant for a deflate stream,
// if a byte is present 8 or more times, it's most likely not a deflate stream
// and could slow down the process (e.g. repeated patterns of "0xEBE1F1" or "0xEBEBEBFF"
// did this before)
2017-11-04 20:49:45 +01:00
memset ( & histogram [ 0 ] , 0 , sizeof ( histogram ) ) ;
int maximum = 0 , used = 0 , offset = cb_pos ;
2017-11-05 20:47:32 +01:00
for ( int i = 0 ; i < 4 ; i + + , offset + = 64 ) {
2017-11-04 20:49:45 +01:00
for ( int j = 0 ; j < 64 ; j + + ) {
int * freq = & histogram [ in_buf [ offset + j ] ] ;
used + = ( ( * freq ) = = 0 ) ;
maximum + = ( + + ( * freq ) ) > maximum ;
}
2017-11-05 20:28:15 +01:00
if ( maximum > = ( ( 12 + i ) < < i ) | | used * ( 7 - ( i + ( i / 2 ) ) ) < ( i + 1 ) * 64 )
2017-11-04 20:49:45 +01:00
return false ;
2017-08-21 06:54:43 +02:00
}
2017-12-28 22:14:09 +05:30
}
2017-06-30 20:49:12 +02:00
int ret ;
2017-07-02 11:43:09 +02:00
unsigned have = 0 ;
2017-06-30 20:49:12 +02:00
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 )
2017-07-02 11:43:09 +02:00
return false ;
2017-06-30 20:49:12 +02:00
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 ) ;
2017-07-02 11:43:09 +02:00
return false ;
2017-06-30 20:49:12 +02:00
}
2017-07-02 11:43:09 +02:00
have + = CHUNK - strm . avail_out ;
2017-06-30 20:49:12 +02:00
} while ( strm . avail_out = = 0 ) ;
/* clean up and return */
( void ) inflateEnd ( & strm ) ;
2017-07-02 11:43:09 +02:00
switch ( ret ) {
case Z_OK :
return true ;
case Z_STREAM_END :
2017-07-30 10:29:11 +02:00
// Skip short streams - most likely false positives
2017-08-13 11:09:44 +02:00
unsigned less_than_skip = 32 ;
if ( use_brute_parameters ) less_than_skip = 1024 ;
2017-07-28 10:47:57 +02:00
return ( have > = less_than_skip ) ;
2017-07-02 11:43:09 +02:00
}
2017-12-28 22:14:09 +05:30
2017-07-02 11:43:09 +02:00
return false ;
2017-06-30 20:49:12 +02:00
}
2016-01-06 12:10:58 +01:00
/* 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 ;
}
2017-08-29 17:23:15 +02:00
int file_recompress ( FILE * origfile , int compression_level , int windowbits , int memlevel , int & decompressed_bytes_used , int decompressed_bytes_total , bool in_memory ) {
2016-01-06 12:10:58 +01:00
int retval ;
2017-08-29 17:23:15 +02:00
if ( ! in_memory ) {
ftempout = fopen ( tempfile1 , " rb " ) ;
if ( ftempout = = NULL ) {
error ( ERR_TEMP_FILE_DISAPPEARED ) ;
}
fseek ( ftempout , 0 , SEEK_SET ) ;
}
2017-12-28 22:14:09 +05:30
2017-08-29 17:23:15 +02:00
retval = def_compare ( origfile , compression_level , windowbits , memlevel , decompressed_bytes_used , decompressed_bytes_total , in_memory ) ;
2017-12-28 22:14:09 +05:30
2017-08-29 17:23:15 +02:00
if ( ! in_memory ) {
safe_fclose ( & ftempout ) ;
2016-01-06 12:10:58 +01:00
}
2016-06-02 07:07:05 +02:00
if ( retval < 0 ) return - 1 ;
2016-01-06 12:10:58 +01:00
return retval ;
}
2016-05-30 13:54:09 +02:00
int file_recompress_bzip2 ( FILE * origfile , int level , int & decompressed_bytes_used , int & decompressed_bytes_total ) {
2016-01-06 12:10:58 +01:00
int retval ;
ftempout = fopen ( tempfile1 , " rb " ) ;
2016-05-30 13:54:09 +02:00
fseek ( ftempout , 0 , SEEK_END ) ;
decompressed_bytes_total = ftell ( ftempout ) ;
2016-01-06 12:10:58 +01:00
if ( ftempout = = NULL ) {
error ( ERR_TEMP_FILE_DISAPPEARED ) ;
}
fseek ( ftempout , 0 , SEEK_SET ) ;
2016-06-02 07:07:05 +02:00
retval = def_compare_bzip2 ( ftempout , origfile , level , decompressed_bytes_used ) ;
2016-01-06 12:10:58 +01:00
safe_fclose ( & ftempout ) ;
2016-06-02 07:07:05 +02:00
if ( retval < 0 ) return - 1 ;
2016-01-06 12:10:58 +01:00
return retval ;
}
2017-10-11 06:07:18 +02:00
void write_decompressed_data ( long long byte_count , char * decompressed_file_name ) {
2017-08-29 17:23:15 +02:00
ftempout = fopen ( decompressed_file_name , " rb " ) ;
if ( ftempout = = NULL ) error ( ERR_TEMP_FILE_DISAPPEARED ) ;
2016-01-06 12:10:58 +01:00
fseek ( ftempout , 0 , SEEK_SET ) ;
fast_copy ( ftempout , fout , byte_count ) ;
safe_fclose ( & ftempout ) ;
}
2017-10-11 06:07:18 +02:00
void write_decompressed_data_io_buf ( long long byte_count , bool in_memory , char * decompressed_file_name ) {
2017-08-29 17:23:15 +02:00
if ( in_memory ) {
fast_copy ( decomp_io_buf , fout , byte_count ) ;
} else {
write_decompressed_data ( byte_count , decompressed_file_name ) ;
}
}
2016-01-06 12:10:58 +01:00
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 ] ;
2016-06-02 07:07:05 +02:00
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 ) {
2016-01-06 12:10:58 +01:00
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 ) ;
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
for ( i = 0 ; i < size1 ; i + + ) {
if ( input_bytes1 [ i ] = = input_bytes2 [ i ] ) {
same_byte_count + + ;
2016-06-02 07:07:05 +02:00
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 ;
2017-07-17 21:45:14 +05:30
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 ;
2016-06-02 07:07:05 +02:00
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 + + ;
2017-07-17 21:45:14 +05:30
2016-06-02 07:07:05 +02:00
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 ;
2016-01-06 12:10:58 +01:00
}
}
seek_64 ( file1 , old_pos ) ;
return same_byte_count ;
}
void start_uncompressed_data ( ) {
uncompressed_length = 0 ;
uncompressed_pos = input_file_pos ;
2016-01-26 12:35:25 +01:00
// uncompressed data
2016-01-06 12:10:58 +01:00
fout_fputc ( 0 ) ;
uncompressed_data_in_work = true ;
}
void end_uncompressed_data ( ) {
if ( ! uncompressed_data_in_work ) return ;
2016-02-14 11:46:09 +01:00
fout_fput64 ( uncompressed_length ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// fast copy of uncompressed data
2016-01-06 12:10:58 +01:00
seek_64 ( fin , uncompressed_pos ) ;
2017-06-16 07:31:37 +02:00
fast_copy ( fin , fout , uncompressed_length , true ) ;
2016-01-06 12:10:58 +01:00
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 ;
2016-01-26 12:54:24 +01:00
void init_decompression_variables ( ) {
2016-01-06 12:10:58 +01:00
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 ;
2016-01-26 12:54:24 +01:00
}
void try_decompression_pdf ( int windowbits , int pdf_header_length , int img_width , int img_height , int img_bpc ) {
init_decompression_variables ( ) ;
2016-01-26 12:35:25 +01:00
int bmp_header_type = 0 ; // 0 = none, 1 = 8-bit, 2 = 24-bit
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// try to decompress at current position
2016-06-05 11:49:48 +02:00
int compressed_stream_size = - 1 ;
2017-08-29 17:23:15 +02:00
bool in_memory ;
retval = try_to_decompress ( fin , windowbits , compressed_stream_size , in_memory ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
if ( retval > 0 ) { // seems to be a zLib-Stream
2016-01-06 12:10:58 +01:00
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 ) ;
2016-06-05 11:49:48 +02:00
printf ( " Compressed size: %i \n " , compressed_stream_size ) ;
2017-08-29 17:23:15 +02:00
printf ( " Can be decompressed to %i bytes \n " , retval ) ;
2016-01-06 12:10:58 +01:00
}
2017-12-25 11:14:05 +01:00
for ( int index = MTF . First ( ) ; index > = 0 ; index = MTF . Next ( ) ) {
2017-12-27 11:34:22 +01:00
if ( comp_mem_level_count [ index ] = = - 1 ) continue ;
2017-10-31 23:08:01 +01:00
int comp_level = ( index % 9 ) + 1 ;
int mem_level = ( index / 9 ) + 1 ;
2016-01-06 12:10:58 +01:00
2017-08-29 17:23:15 +02:00
try_recompress ( fin , comp_level , mem_level , windowbits , compressed_stream_size , retval , in_memory ) ;
2016-01-06 12:10:58 +01:00
2017-12-25 11:14:05 +01:00
if ( final_compression_found ) { MTF . Update ( ) ; break ; }
2016-01-06 12:10:58 +01:00
}
2016-06-05 11:49:48 +02:00
if ( ( best_identical_bytes > min_ident_size ) & & ( best_identical_bytes < best_identical_bytes_decomp ) ) {
2016-01-06 12:10:58 +01:00
recompressed_streams_count + + ;
recompressed_pdf_count + + ;
if ( DEBUG_MODE ) {
2016-06-10 22:58:17 +02:00
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 ) ;
2016-01-06 12:10:58 +01:00
}
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 ;
} 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 ;
}
}
2016-01-26 12:35:25 +01:00
// end uncompressed data
2016-01-06 12:10:58 +01:00
compressed_data_found = true ;
end_uncompressed_data ( ) ;
2016-01-26 12:35:25 +01:00
// write compressed data header (PDF) without 12 first bytes
// (/FlateDecode)
2016-01-06 12:10:58 +01:00
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 ) ;
}
2016-01-26 12:35:25 +01:00
fout_fputc ( 0 ) ; // PDF
2016-01-06 12:10:58 +01:00
fout_fputc ( ( ( ( - windowbits ) - 8 ) < < 4 ) + best_mem_level ) ;
pdf_header_length - = 12 ;
2016-03-19 09:13:54 +01:00
fout_fput24 ( pdf_header_length ) ;
2016-01-06 12:10:58 +01:00
own_fwrite ( in_buf + cb + 12 , 1 , pdf_header_length , fout ) ;
2016-01-26 12:35:25 +01:00
// store penalty bytes, if any
2016-01-06 12:10:58 +01:00
if ( best_penalty_bytes_len ! = 0 ) {
if ( DEBUG_MODE ) {
printf ( " Penalty bytes were used: %i bytes \n " , best_penalty_bytes_len ) ;
}
2016-03-19 09:13:54 +01:00
fout_fput32 ( best_penalty_bytes_len ) ;
2016-01-06 12:10:58 +01:00
for ( int pbc = 0 ; pbc < best_penalty_bytes_len ; pbc + + ) {
fout_fputc ( best_penalty_bytes [ pbc ] ) ;
}
}
2016-03-19 09:13:54 +01:00
fout_fput32 ( best_identical_bytes ) ;
fout_fput32 ( best_identical_bytes_decomp ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// eventually write BMP header
2016-01-06 12:10:58 +01:00
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 ;
}
2016-03-19 09:13:54 +01:00
fout_fput32_little_endian ( bmp_size ) ;
2016-01-06 12:10:58 +01:00
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 ) ;
2016-03-19 09:13:54 +01:00
fout_fput32_little_endian ( img_width ) ;
fout_fput32_little_endian ( img_height ) ;
2016-01-06 12:10:58 +01:00
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 ;
2016-03-19 09:13:54 +01:00
fout_fput32_little_endian ( datasize ) ;
2016-01-06 12:10:58 +01:00
for ( i = 0 ; i < 16 ; i + + ) {
fout_fputc ( 0 ) ;
}
if ( bmp_header_type = = 1 ) {
2016-01-26 12:35:25 +01:00
// write BMP palette
2016-01-06 12:10:58 +01:00
for ( i = 0 ; i < 1024 ; i + + ) {
fout_fputc ( 0 ) ;
}
}
}
2016-01-26 12:35:25 +01:00
// write decompressed data
2016-01-06 12:10:58 +01:00
if ( ( bmp_header_type = = 0 ) | | ( ( img_width % 4 ) = = 0 ) ) {
2017-10-11 06:07:18 +02:00
write_decompressed_data_io_buf ( best_identical_bytes_decomp , in_memory ) ;
2016-01-06 12:10:58 +01:00
} else {
2017-08-29 17:23:15 +02:00
if ( ! in_memory ) {
ftempout = fopen ( tempfile1 , " rb " ) ;
if ( ftempout = = NULL ) {
error ( ERR_TEMP_FILE_DISAPPEARED ) ;
}
2016-01-06 12:10:58 +01:00
2017-08-29 17:23:15 +02:00
fseek ( ftempout , 0 , SEEK_SET ) ;
2016-01-06 12:10:58 +01:00
}
2017-08-29 17:23:15 +02:00
unsigned char * buf_ptr = decomp_io_buf ;
2016-01-06 12:10:58 +01:00
for ( int y = 0 ; y < img_height ; y + + ) {
2017-08-29 17:23:15 +02:00
if ( in_memory ) {
fast_copy ( buf_ptr , fout , img_width ) ;
buf_ptr + = img_width ;
} else {
fast_copy ( ftempout , fout , img_width ) ;
}
2016-01-06 12:10:58 +01:00
for ( int i = 0 ; i < ( 4 - ( img_width % 4 ) ) ; i + + ) {
fout_fputc ( 0 ) ;
}
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
}
safe_fclose ( & ftempout ) ;
}
2016-01-26 12:35:25 +01:00
// start new uncompressed data
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// set input file pointer after recompressed data
2016-01-06 12:10:58 +01:00
input_file_pos + = best_identical_bytes - 1 ;
cb + = best_identical_bytes - 1 ;
} else {
2017-07-29 11:25:58 +02:00
if ( intense_mode_is_active ( ) ) intense_ignore_offsets - > insert ( input_file_pos - 2 ) ;
2017-12-28 22:14:09 +05:30
if ( brute_mode_is_active ( ) ) brute_ignore_offsets - > insert ( input_file_pos ) ;
2016-01-06 12:10:58 +01:00
if ( DEBUG_MODE ) {
printf ( " No matches \n " ) ;
}
}
}
}
void try_decompression_zip ( int zip_header_length ) {
2016-01-26 12:54:24 +01:00
init_decompression_variables ( ) ;
2016-01-06 12:10:58 +01:00
int windowbits ;
2016-01-26 12:35:25 +01:00
// try to decompress at current position
2016-06-05 11:49:48 +02:00
int compressed_stream_size = - 1 ;
2017-08-29 17:23:15 +02:00
bool in_memory ;
retval = try_to_decompress ( fin , - 15 , compressed_stream_size , in_memory ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
if ( retval > 0 ) { // seems to be a zLib-Stream
2016-01-06 12:10:58 +01:00
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 " ) ;
2016-06-05 11:49:48 +02:00
printf ( " Compressed size: %i \n " , compressed_stream_size ) ;
2017-08-29 17:23:15 +02:00
printf ( " Can be decompressed to %i bytes \n " , retval ) ;
2016-01-06 12:10:58 +01:00
}
2017-12-25 11:14:05 +01:00
2016-01-06 12:10:58 +01:00
for ( windowbits = - 15 ; windowbits < - 7 ; windowbits + + ) {
2017-12-25 11:14:05 +01:00
for ( int index = MTF . First ( ) ; index > = 0 ; index = MTF . Next ( ) ) {
2017-12-27 11:34:22 +01:00
if ( comp_mem_level_count [ index ] = = - 1 ) continue ;
2017-10-31 23:08:01 +01:00
int comp_level = ( index % 9 ) + 1 ;
int mem_level = ( index / 9 ) + 1 ;
2016-01-06 12:10:58 +01:00
2017-08-29 17:23:15 +02:00
try_recompress ( fin , comp_level , mem_level , windowbits , compressed_stream_size , retval , in_memory ) ;
2016-01-06 12:10:58 +01:00
2017-12-25 11:14:05 +01:00
if ( final_compression_found ) { MTF . Update ( ) ; break ; }
2016-01-06 12:10:58 +01:00
}
2016-05-20 16:12:58 +02:00
if ( final_compression_found ) break ;
2016-01-06 12:10:58 +01:00
}
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 ) {
2016-06-10 22:58:17 +02:00
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 ) ;
2016-01-06 12:10:58 +01:00
}
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 ;
} 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 ;
}
}
2016-01-26 12:35:25 +01:00
// end uncompressed data
2016-01-06 12:10:58 +01:00
compressed_data_found = true ;
end_uncompressed_data ( ) ;
2016-01-26 12:35:25 +01:00
// check recursion
2017-08-29 17:23:15 +02:00
write_ftempout_if_not_present ( best_identical_bytes_decomp , in_memory ) ;
2016-01-06 12:10:58 +01:00
recursion_result r = recursion_compress ( best_identical_bytes , best_identical_bytes_decomp ) ;
2016-01-26 12:35:25 +01:00
// write compressed data header (ZIP) without 4 first bytes (PK..)
2016-01-06 12:10:58 +01:00
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 ) ;
2016-01-26 12:35:25 +01:00
fout_fputc ( 1 ) ; // ZIP
2016-01-06 12:10:58 +01:00
fout_fputc ( ( ( ( - windowbits ) - 8 ) < < 4 ) + best_mem_level ) ;
zip_header_length - = 4 ;
2016-03-19 09:13:54 +01:00
fout_fput24 ( zip_header_length ) ;
2016-01-06 12:10:58 +01:00
own_fwrite ( in_buf + cb + 4 , 1 , zip_header_length , fout ) ;
2016-01-26 12:35:25 +01:00
// store penalty bytes, if any
2016-01-06 12:10:58 +01:00
if ( best_penalty_bytes_len ! = 0 ) {
if ( DEBUG_MODE ) {
printf ( " Penalty bytes were used: %i bytes \n " , best_penalty_bytes_len ) ;
}
2016-03-19 09:13:54 +01:00
fout_fput32 ( best_penalty_bytes_len ) ;
2016-01-06 12:10:58 +01:00
for ( int pbc = 0 ; pbc < best_penalty_bytes_len ; pbc + + ) {
fout_fputc ( best_penalty_bytes [ pbc ] ) ;
}
}
2016-03-19 09:13:54 +01:00
fout_fput32 ( best_identical_bytes ) ;
fout_fput32 ( best_identical_bytes_decomp ) ;
2016-01-06 12:10:58 +01:00
if ( r . success ) {
2016-03-19 09:13:54 +01:00
fout_fput64 ( r . file_length ) ;
2016-01-06 12:10:58 +01:00
}
2016-01-26 12:35:25 +01:00
// write decompressed data
2016-01-06 12:10:58 +01:00
if ( r . success ) {
write_decompressed_data ( r . file_length , r . file_name ) ;
remove ( r . file_name ) ;
delete [ ] r . file_name ;
} else {
2017-10-11 06:07:18 +02:00
write_decompressed_data_io_buf ( best_identical_bytes_decomp , in_memory ) ;
2016-01-06 12:10:58 +01:00
}
2016-01-26 12:35:25 +01:00
// set input file pointer after recompressed data
2016-01-06 12:10:58 +01:00
input_file_pos + = best_identical_bytes - 1 ;
cb + = best_identical_bytes - 1 ;
} else {
2017-12-28 22:14:09 +05:30
if ( brute_mode_is_active ( ) ) brute_ignore_offsets - > insert ( input_file_pos ) ;
2016-01-06 12:10:58 +01:00
if ( DEBUG_MODE ) {
printf ( " No matches \n " ) ;
}
}
}
}
void show_used_levels ( ) {
if ( ! anything_was_used ) {
if ( ! non_zlib_was_used ) {
2016-07-02 18:37:31 +02:00
if ( compression_otf_method = = OTF_NONE ) {
2016-01-06 12:10:58 +01:00
printf ( " \n None 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 ( " \n You can speed up Precomp for THIS FILE with these INI parameters: \n " ) ;
printf ( " Maximal_Recursion_Depth= " ) ;
# else
printf ( " \n You 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 ( " \n Maximal 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 ( " \n You can speed up Precomp for THIS FILE with these INI parameters: \n " ) ;
printf ( " zLib_Levels= " ) ;
# else
printf ( " \n You 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 + + ;
}
}
2017-07-24 12:59:43 +02:00
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 ' ;
2017-07-17 22:42:49 +05:30
if ( disable_methods . length ( ) > 0 ) {
2017-07-24 12:59:43 +02:00
# ifdef COMFORT
printf ( " \n Compression_Types_Disable=%s " , disable_methods . c_str ( ) ) ;
# else
2017-07-17 22:42:49 +05:30
printf ( " -t-%s " , disable_methods . c_str ( ) ) ;
2017-07-24 12:59:43 +02:00
# endif
2017-07-17 22:42:49 +05:30
}
2016-01-06 12:10:58 +01:00
if ( max_recursion_depth_reached ) {
printf ( " \n \n Maximal 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 ( " \n Maximal_Recursion_Depth= " ) ;
# else
printf ( " -d " ) ;
# endif
printf ( " %i " , max_recursion_depth_used ) ;
}
if ( ( level_count = = 1 ) & & ( ! fast_mode ) ) {
printf ( " \n \n Fast 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 ( ) ;
2017-07-28 10:37:08 +02:00
intense_ignore_offsets = new set < long long > ( ) ;
brute_ignore_offsets = new set < long long > ( ) ;
2017-08-30 06:46:26 +02:00
decomp_io_buf = new unsigned char [ MAX_IO_BUFFER_SIZE ] ;
2016-01-06 12:10:58 +01:00
global_min_percent = min_percent ;
global_max_percent = max_percent ;
if ( recursion_depth = = 0 ) write_header ( ) ;
uncompressed_length = - 1 ;
2017-06-16 07:31:37 +02:00
uncompressed_bytes_total = 0 ;
uncompressed_bytes_written = 0 ;
2016-01-06 12:10:58 +01:00
2017-06-16 07:31:37 +02:00
if ( ! DEBUG_MODE ) show_progress ( min_percent , ( recursion_depth > 0 ) , false ) ;
2016-01-06 12:10:58 +01:00
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 ;
2017-06-11 11:47:05 +02:00
if ( ! DEBUG_MODE ) {
2017-06-16 07:31:37 +02:00
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 ) ;
2017-06-11 11:47:05 +02:00
}
2016-01-06 12:10:58 +01:00
} 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 ) ) {
2016-01-26 12:35:25 +01:00
// local file header?
2016-01-06 12:10:58 +01:00
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 ;
}
}
}
}
2016-01-26 12:35:25 +01:00
if ( ( ! compressed_data_found ) & & ( use_gzip ) ) { // no ZIP header -> GZip header?
2016-01-06 12:10:58 +01:00
if ( ( in_buf [ cb ] = = 31 ) & & ( in_buf [ cb + 1 ] = = 139 ) ) {
2016-01-26 12:35:25 +01:00
// check zLib header in GZip header
2016-01-06 12:10:58 +01:00
int compression_method = ( in_buf [ cb + 2 ] & 15 ) ;
if ( ( compression_method = = 8 ) & &
2016-01-26 12:35:25 +01:00
( ( in_buf [ cb + 3 ] & 224 ) = = 0 ) // reserved FLG bits must be zero
2016-01-06 12:10:58 +01:00
) {
//((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 ) {
2016-01-26 12:35:25 +01:00
input_file_pos + = header_length ; // skip GZip header
2016-01-06 12:10:58 +01:00
try_decompression_gzip ( header_length ) ;
cb + = header_length ;
}
if ( ! compressed_data_found ) {
input_file_pos = saved_input_file_pos ;
cb = saved_cb ;
}
}
}
}
2016-01-26 12:35:25 +01:00
if ( ( ! compressed_data_found ) & & ( use_pdf ) ) { // no Gzip header -> PDF FlateDecode?
2016-01-06 12:10:58 +01:00
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 ) {
2016-01-26 12:35:25 +01:00
// check if the stream is an image and width and height are given
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// read 4096 bytes before stream
2016-01-06 12:10:58 +01:00
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 ;
}
2016-01-26 12:35:25 +01:00
// find "<<"
2016-01-06 12:10:58 +01:00
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 ;
2016-01-26 12:35:25 +01:00
// find "/Width"
2016-01-06 12:10:58 +01:00
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 ;
}
}
2016-01-26 12:35:25 +01:00
// find "/Height"
2016-01-06 12:10:58 +01:00
height_pos = ( unsigned char * ) strstr ( ( const char * ) ( type_buf + start_pos ) , " /Height " ) - type_buf ;
2017-07-17 21:45:14 +05:30
if ( height_pos > 0 )
2016-01-06 12:10:58 +01:00
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 ;
}
}
2016-01-26 12:35:25 +01:00
// find "/BitsPerComponent"
2016-01-06 12:10:58 +01:00
bpc_pos = ( unsigned char * ) strstr ( ( const char * ) ( type_buf + start_pos ) , " /BitsPerComponent " ) - type_buf ;
2017-07-17 21:45:14 +05:30
if ( bpc_pos > 0 )
2016-01-06 12:10:58 +01:00
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 ) ) {
2016-01-26 12:35:25 +01:00
// seems to be two byte EOL - zLib Header present?
2016-01-06 12:10:58 +01:00
if ( ( ( ( ( in_buf [ cb + act_search_pos + 8 ] < < 8 ) + in_buf [ cb + act_search_pos + 9 ] ) % 31 ) = = 0 ) & &
2016-01-26 12:35:25 +01:00
( ( in_buf [ cb + act_search_pos + 9 ] & 32 ) = = 0 ) ) { // FDICT must not be set
2016-01-06 12:10:58 +01:00
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 ;
2016-01-26 12:35:25 +01:00
input_file_pos + = act_search_pos + 10 ; // skip PDF part
2016-01-06 12:10:58 +01:00
try_decompression_pdf ( - windowbits , act_search_pos + 10 , width_val , height_val , bpc_val ) ;
cb + = act_search_pos + 10 ;
}
}
} else {
2016-01-26 12:35:25 +01:00
// seems to be one byte EOL - zLib Header present?
2016-01-06 12:10:58 +01:00
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 ;
2016-01-26 12:35:25 +01:00
input_file_pos + = act_search_pos + 9 ; // skip PDF part
2016-01-06 12:10:58 +01:00
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 ;
}
}
}
2016-01-26 12:35:25 +01:00
if ( ( ! compressed_data_found ) & & ( use_png ) ) { // no PDF header -> PNG IDAT?
2016-01-06 12:10:58 +01:00
if ( memcmp ( in_buf + cb , " IDAT " , 4 ) = = 0 ) {
2016-01-26 12:35:25 +01:00
// space for length and crc parts of IDAT chunks
2016-01-06 12:10:58 +01:00
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 ;
2016-01-26 12:35:25 +01:00
// get preceding length bytes
2016-01-06 12:10:58 +01:00
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 ) {
2016-01-26 12:35:25 +01:00
// check zLib header and get windowbits
2016-01-06 12:10:58 +01:00
zlib_header [ 0 ] = in [ 8 ] ;
zlib_header [ 1 ] = in [ 9 ] ;
if ( ( ( ( in [ 8 ] < < 8 ) + in [ 9 ] ) % 31 ) = = 0 ) {
if ( ( in [ 8 ] & 15 ) = = 8 ) {
2016-01-26 12:35:25 +01:00
if ( ( in [ 9 ] & 32 ) = = 0 ) { // FDICT must not be set
2016-01-06 12:10:58 +01:00
windowbits = ( in [ 8 ] > > 4 ) + 8 ;
zlib_header_correct = true ;
}
}
}
if ( zlib_header_correct ) {
idat_count + + ;
2016-01-26 12:35:25 +01:00
// go through additional IDATs
2016-01-06 12:10:58 +01:00
for ( ; ; ) {
seek_64 ( fin , tell_64 ( fin ) + idat_lengths [ idat_count - 1 ] ) ;
2016-01-26 12:35:25 +01:00
if ( fread ( in , 1 , 12 , fin ) ! = 12 ) { // CRC, length, "IDAT"
2016-01-06 12:10:58 +01:00
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 ) {
2016-01-26 12:35:25 +01:00
// try to recompress directly
2016-01-06 12:10:58 +01:00
input_file_pos + = 6 ;
try_decompression_png ( - windowbits ) ;
cb + = 6 ;
} else if ( idat_count > 1 ) {
2016-01-26 12:35:25 +01:00
// copy to temp0.dat before trying to recompress
2016-01-06 12:10:58 +01:00
remove ( tempfile0 ) ;
fpng = tryOpen ( tempfile0 , " w+b " ) ;
2016-01-26 12:35:25 +01:00
seek_64 ( fin , input_file_pos + 6 ) ; // start after zLib header
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
idat_lengths [ 0 ] - = 2 ; // zLib header length
2016-01-06 12:10:58 +01:00
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 ;
}
}
2016-01-26 12:35:25 +01:00
if ( ( ! compressed_data_found ) & & ( use_gif ) ) { // no PNG header -> GIF header?
2016-01-06 12:10:58 +01:00
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 ;
}
}
}
}
}
2017-08-14 12:36:20 +01:00
if ( ( ! compressed_data_found ) & & ( use_jpg ) ) { // no GIF header -> JPG header?
if ( ( in_buf [ cb ] = = 0xFF ) & & ( in_buf [ cb + 1 ] = = 0xD8 ) & & ( in_buf [ cb + 2 ] = = 0xFF ) & & (
( in_buf [ cb + 3 ] = = 0xC0 ) | | ( in_buf [ cb + 3 ] = = 0xC2 ) | | ( in_buf [ cb + 3 ] = = 0xC4 ) | | ( ( in_buf [ cb + 3 ] > = 0xDB ) & & ( in_buf [ cb + 3 ] < = 0xFE ) )
) ) { // SOI (FF D8) followed by a valid marker for Baseline/Progressive JPEGs
saved_input_file_pos = input_file_pos ;
saved_cb = cb ;
2017-12-28 22:14:09 +05:30
2017-08-14 12:36:20 +01:00
bool done = false , found = false ;
bool progressive_flag = ( in_buf [ cb + 3 ] = = 0xC2 ) ;
input_file_pos + = 2 ;
2017-12-28 22:14:09 +05:30
2017-08-14 12:36:20 +01:00
do {
seek_64 ( fin , input_file_pos ) ;
if ( ( fread ( in , 1 , 5 , fin ) ! = 5 ) | | ( in [ 0 ] ! = 0xFF ) )
break ;
2016-01-06 12:10:58 +01:00
2017-08-14 12:36:20 +01:00
switch ( in [ 1 ] ) {
case 0xDA : found = true ;
case 0xD9 : done = true ; break ; //EOI with no SOS?
case 0xC2 : progressive_flag = true ;
case 0xC0 : done = ( in [ 4 ] ! = 0x08 ) ;
default : input_file_pos + = in [ 2 ] * 256 + in [ 3 ] + 2 ;
2016-01-06 12:10:58 +01:00
}
2017-08-14 12:36:20 +01:00
}
while ( ! done ) ;
2017-12-28 22:14:09 +05:30
2017-08-14 12:36:20 +01:00
if ( found ) {
found = done = false ;
input_file_pos + = 5 ;
bool isMarker = ( in [ 4 ] = = 0xFF ) ;
size_t bytesRead = 0 ;
while ( ! done & & ( bytesRead = fread ( in , sizeof ( in [ 0 ] ) , CHUNK , fin ) ) ) {
for ( size_t i = 0 ; ! done & & ( i < bytesRead ) ; i + + ) {
input_file_pos + + ;
if ( ! isMarker ) {
isMarker = ( in [ i ] = = 0xFF ) ;
2016-01-06 12:10:58 +01:00
}
2017-08-14 12:36:20 +01:00
else {
done = ( in [ i ] & & ( ( in [ i ] & 0xF8 ) ! = 0xD0 ) & & ( ( progressive_flag ) ? ( in [ i ] ! = 0xC4 ) & & ( in [ i ] ! = 0xDA ) : true ) ) ;
found = ( in [ i ] = = 0xD9 ) ;
isMarker = false ;
2016-01-06 12:10:58 +01:00
}
}
}
2017-08-14 12:36:20 +01:00
}
2016-01-06 12:10:58 +01:00
2017-08-14 12:36:20 +01:00
if ( found ) {
long long jpg_length = input_file_pos - saved_input_file_pos ;
input_file_pos = saved_input_file_pos ;
try_decompression_jpg ( jpg_length , progressive_flag ) ;
2016-01-06 12:10:58 +01:00
}
2017-08-14 12:36:20 +01:00
if ( ! found | | ! compressed_data_found ) {
input_file_pos = saved_input_file_pos ;
cb = saved_cb ;
2017-12-28 22:14:09 +05:30
}
2016-01-06 12:10:58 +01:00
}
}
2016-01-26 12:35:25 +01:00
if ( ( ! compressed_data_found ) & & ( use_mp3 ) ) { // no JPG header -> MP3 header?
2016-01-21 15:39:31 +01:00
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 ;
2016-04-02 12:25:40 +02:00
int type = - 1 ;
2016-01-21 15:39:31 +01:00
int bits ;
int padding ;
int frame_size ;
int n = 0 ;
2016-05-06 12:12:36 +02:00
long long mp3_parsing_cache_second_frame_candidate = - 1 ;
long long mp3_parsing_cache_second_frame_candidate_size = - 1 ;
2016-01-21 15:39:31 +01:00
long long mp3_length = 0 ;
saved_input_file_pos = input_file_pos ;
saved_cb = cb ;
long long act_pos = input_file_pos ;
2017-07-17 21:45:14 +05:30
2016-01-21 15:39:31 +01:00
// parse frames until first invalid frame is found or end-of-file
seek_64 ( fin , act_pos ) ;
2016-04-29 16:23:40 +02:00
while ( fread ( in , 1 , 4 , fin ) = = 4 ) {
2016-01-21 15:39:31 +01:00
// 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 ;
2016-04-02 12:25:40 +02:00
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 ;
}
2016-04-11 13:26:35 +02:00
} else {
2016-05-06 12:12:36 +02:00
if ( n = = 1 ) {
mp3_parsing_cache_second_frame_candidate = act_pos ;
mp3_parsing_cache_second_frame_candidate_size = act_pos - saved_input_file_pos ;
}
2016-04-11 13:26:35 +02:00
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 ;
}
}
2016-01-21 15:39:31 +01:00
2016-03-19 09:13:54 +01:00
bits = ( in [ 2 ] > > 4 ) & 0xF ;
2016-01-21 15:39:31 +01:00
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 ;
2016-05-06 12:12:36 +02:00
// 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 ;
2017-07-17 21:45:14 +05:30
2016-05-06 12:12:36 +02:00
// update values
mp3_parsing_cache_second_frame = act_pos + frame_size ;
mp3_parsing_cache_n - = 1 ;
mp3_parsing_cache_mp3_length - = frame_size ;
2017-07-17 21:45:14 +05:30
2016-05-06 12:12:36 +02:00
break ;
}
2017-07-17 21:45:14 +05:30
}
2016-03-19 09:13:54 +01:00
n + + ;
2016-01-21 15:39:31 +01:00
mp3_length + = frame_size ;
act_pos + = frame_size ;
2016-04-29 16:23:40 +02:00
// if supported MP3 type, validate frames
if ( ( type = = MPEG1_LAYER_III ) & & ( frame_size > 4 ) ) {
unsigned char header2 = in [ 2 ] ;
unsigned char header3 = in [ 3 ] ;
2017-12-26 10:16:33 +01:00
if ( fread ( in , 1 , frame_size - 4 , fin ) ! = ( unsigned int ) ( frame_size - 4 ) ) {
// discard incomplete frame
n - - ;
mp3_length - = frame_size ;
break ;
}
2016-04-29 16:23:40 +02:00
if ( ! is_valid_mp3_frame ( in , header2 , header3 , protection ) ) {
n = 0 ;
break ;
}
} else {
seek_64 ( fin , act_pos ) ;
}
2016-01-21 15:39:31 +01:00
}
2016-04-29 16:23:40 +02:00
// conditions for proper first frame: 5 consecutive frames
2016-03-19 09:13:54 +01:00
if ( n > = 5 ) {
2016-05-06 12:12:36 +02:00
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 ;
}
2017-07-17 21:45:14 +05:30
2016-05-06 11:31:47 +02:00
long long position_length_sum = saved_input_file_pos + mp3_length ;
2017-07-17 21:45:14 +05:30
2016-04-02 12:25:40 +02:00
// type must be MPEG-1, Layer III, packMP3 won't process any other files
if ( type = = MPEG1_LAYER_III ) {
2016-05-06 11:31:47 +02:00
// 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 ) {
2016-04-02 12:25:40 +02:00
try_decompression_mp3 ( mp3_length ) ;
2016-05-06 11:31:47 +02:00
}
2016-04-02 12:25:40 +02:00
} else if ( type > 0 ) {
2016-05-06 11:31:47 +02:00
suppress_mp3_type_until [ type ] = position_length_sum ;
2016-04-02 12:25:40 +02:00
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 ] ) ;
}
}
2016-03-19 09:13:54 +01:00
}
2016-01-21 15:39:31 +01:00
if ( ! compressed_data_found ) {
input_file_pos = saved_input_file_pos ;
cb = saved_cb ;
}
}
}
2016-01-26 12:35:25 +01:00
if ( ( ! compressed_data_found ) & & ( use_swf ) ) { // no MP3 header -> SWF header?
2016-01-06 12:10:58 +01:00
// CWS = Compressed SWF file
if ( ( in_buf [ cb ] = = ' C ' ) & & ( in_buf [ cb + 1 ] = = ' W ' ) & & ( in_buf [ cb + 2 ] = = ' S ' ) ) {
2016-03-21 14:06:57 +01:00
// 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 ;
2016-01-06 12:10:58 +01:00
2016-03-21 14:06:57 +01:00
saved_input_file_pos = input_file_pos ;
saved_cb = cb ;
2016-01-06 12:10:58 +01:00
2016-03-21 14:06:57 +01:00
input_file_pos + = 10 ; // skip CWS and zLib header
2016-01-06 12:10:58 +01:00
2016-03-21 14:06:57 +01:00
try_decompression_swf ( - windowbits ) ;
2016-01-06 12:10:58 +01:00
2016-03-21 14:06:57 +01:00
cb + = 10 ;
2016-01-06 12:10:58 +01:00
2016-03-21 14:06:57 +01:00
if ( ! compressed_data_found ) {
input_file_pos = saved_input_file_pos ;
cb = saved_cb ;
2016-01-06 12:10:58 +01:00
}
}
}
}
}
2016-01-26 12:35:25 +01:00
if ( ( ! compressed_data_found ) & & ( use_base64 ) ) { // no SWF header -> Base64?
2016-01-06 12:10:58 +01:00
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 ) {
2016-01-26 12:35:25 +01:00
// search for double CRLF, all between is "header"
2016-01-06 12:10:58 +01:00
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 ;
2016-01-26 12:35:25 +01:00
// skip additional CRLFs
2016-01-06 12:10:58 +01:00
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 ) ) ;
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
if ( found_double_crlf ) {
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
saved_input_file_pos = input_file_pos ;
saved_cb = cb ;
2016-01-26 12:35:25 +01:00
input_file_pos + = base64_header_length ; // skip "header"
2016-01-06 12:10:58 +01:00
try_decompression_base64 ( base64_header_length ) ;
cb + = base64_header_length ;
if ( ! compressed_data_found ) {
input_file_pos = saved_input_file_pos ;
cb = saved_cb ;
}
}
}
}
}
2016-01-26 12:35:25 +01:00
if ( ( ! compressed_data_found ) & & ( use_bzip2 ) ) { // no Base64 header -> bZip2?
2016-01-06 12:10:58 +01:00
// 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 ;
}
}
}
}
2017-07-29 11:25:58 +02:00
// nothing so far -> if intense mode is active, look for raw zLib header
if ( intense_mode_is_active ( ) ) {
2016-01-06 12:10:58 +01:00
if ( ! compressed_data_found ) {
2017-07-27 15:11:21 +02:00
bool ignore_this_position = false ;
2017-07-28 10:37:08 +02:00
if ( intense_ignore_offsets - > size ( ) > 0 ) {
auto first = intense_ignore_offsets - > begin ( ) ;
2017-07-27 15:11:21 +02:00
while ( * first < input_file_pos ) {
2017-07-28 10:37:08 +02:00
intense_ignore_offsets - > erase ( first ) ;
if ( intense_ignore_offsets - > size ( ) = = 0 ) break ;
first = intense_ignore_offsets - > begin ( ) ;
2017-07-27 15:11:21 +02:00
}
2017-12-28 22:14:09 +05:30
2017-07-28 10:37:08 +02:00
if ( intense_ignore_offsets - > size ( ) > 0 ) {
2017-07-27 15:11:21 +02:00
if ( * first = = input_file_pos ) {
ignore_this_position = true ;
2017-07-28 10:37:08 +02:00
intense_ignore_offsets - > erase ( first ) ;
2017-07-27 15:11:21 +02:00
}
}
}
2017-12-28 22:14:09 +05:30
2017-07-27 15:11:21 +02:00
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 ;
2016-01-06 12:10:58 +01:00
2017-08-13 11:09:44 +02:00
if ( check_inf_result ( cb + 2 , - windowbits ) ) {
2017-07-27 15:11:21 +02:00
saved_input_file_pos = input_file_pos ;
saved_cb = cb ;
2016-01-06 12:10:58 +01:00
2017-07-27 15:11:21 +02:00
input_file_pos + = 2 ; // skip zLib header
2016-01-06 12:10:58 +01:00
2017-07-27 15:11:21 +02:00
try_decompression_zlib ( - windowbits ) ;
2016-01-06 12:10:58 +01:00
2017-07-27 15:11:21 +02:00
cb + = 2 ;
2016-01-06 12:10:58 +01:00
2017-07-27 15:11:21 +02:00
if ( ! compressed_data_found ) {
input_file_pos = saved_input_file_pos ;
cb = saved_cb ;
}
2017-06-30 20:49:12 +02:00
}
2016-01-06 12:10:58 +01:00
}
}
}
}
2017-08-14 07:11:58 +02:00
}
2016-01-06 12:10:58 +01:00
2017-07-29 11:25:58 +02:00
// nothing so far -> if brute mode is active, brute force for zLib streams
2017-08-14 07:11:58 +02:00
if ( brute_mode_is_active ( ) ) {
2016-01-06 12:10:58 +01:00
if ( ! compressed_data_found ) {
2017-07-27 15:11:21 +02:00
bool ignore_this_position = false ;
2017-07-28 10:37:08 +02:00
if ( brute_ignore_offsets - > size ( ) > 0 ) {
auto first = brute_ignore_offsets - > begin ( ) ;
2017-07-27 15:11:21 +02:00
while ( * first < input_file_pos ) {
2017-07-28 10:37:08 +02:00
brute_ignore_offsets - > erase ( first ) ;
if ( brute_ignore_offsets - > size ( ) = = 0 ) break ;
first = brute_ignore_offsets - > begin ( ) ;
2017-07-27 15:11:21 +02:00
}
2017-12-28 22:14:09 +05:30
2017-07-28 10:37:08 +02:00
if ( brute_ignore_offsets - > size ( ) > 0 ) {
2017-07-27 15:11:21 +02:00
if ( * first = = input_file_pos ) {
ignore_this_position = true ;
2017-07-28 10:37:08 +02:00
brute_ignore_offsets - > erase ( first ) ;
2017-07-27 15:11:21 +02:00
}
}
2017-07-02 11:14:40 +02:00
}
2017-12-28 22:14:09 +05:30
2017-07-27 15:11:21 +02:00
if ( ! ignore_this_position ) {
saved_input_file_pos = input_file_pos ;
saved_cb = cb ;
2017-08-13 11:09:44 +02:00
if ( check_inf_result ( cb , - 15 , true ) ) {
2017-07-27 15:11:21 +02:00
try_decompression_brute ( ) ;
}
2016-01-06 12:10:58 +01:00
2017-07-27 15:11:21 +02:00
if ( ! compressed_data_found ) {
input_file_pos = saved_input_file_pos ;
cb = saved_cb ;
}
2016-01-06 12:10:58 +01:00
}
}
}
}
if ( ! compressed_data_found ) {
if ( uncompressed_length = = - 1 ) {
start_uncompressed_data ( ) ;
}
uncompressed_length + + ;
2017-06-16 07:31:37 +02:00
uncompressed_bytes_total + + ;
2016-01-06 12:10:58 +01:00
}
}
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 ( ) ;
2016-07-02 18:37:31 +02:00
if ( compression_otf_method ! = OTF_NONE ) {
2016-01-06 12:10:58 +01:00
init_decompress_otf ( ) ;
}
2017-06-11 11:47:05 +02:00
if ( recursion_depth = = 0 ) {
2017-06-16 07:31:37 +02:00
if ( ! DEBUG_MODE ) show_progress ( 0 , false , false ) ;
2017-06-11 11:47:05 +02:00
read_header ( ) ;
2016-01-06 12:10:58 +01:00
}
fin_pos = tell_64 ( fin ) ;
while ( fin_pos < fin_length ) {
2017-06-11 11:47:05 +02:00
if ( ( recursion_depth = = 0 ) & & ( ! DEBUG_MODE ) ) {
float percent = ( fin_pos / ( float ) fin_length ) * 100 ;
2017-06-16 07:31:37 +02:00
show_progress ( percent , true , true ) ;
2016-01-06 12:10:58 +01:00
}
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
unsigned char header1 = fin_fgetc ( ) ;
2016-01-26 12:35:25 +01:00
if ( header1 = = 0 ) { // uncompressed data
2016-01-06 12:10:58 +01:00
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 ( ) ;
2016-01-26 12:35:25 +01:00
if ( uncompressed_data_length = = 0 ) break ; // end of PCF file, used by bZip2 compress-on-the-fly
2016-01-06 12:10:58 +01:00
if ( DEBUG_MODE ) {
printf ( " Uncompressed data, length= " ) ;
print64 ( uncompressed_data_length ) ;
printf ( " \n " ) ;
}
fast_copy ( fin , fout , uncompressed_data_length ) ;
2016-01-26 12:35:25 +01:00
} else { // decompressed data, recompress
2016-01-06 12:10:58 +01:00
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 ( ) ;
2016-01-26 12:35:25 +01:00
// restore PDF header
2016-01-06 12:10:58 +01:00
fprintf ( fout , " /FlateDecode " ) ;
own_fread ( in , 1 , pdf_header_length , fin ) ;
own_fwrite ( in , 1 , pdf_header_length , fout ) ;
2016-01-26 12:35:25 +01:00
// read penalty bytes
2016-01-06 12:10:58 +01:00
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 ) ;
}
2016-01-26 12:35:25 +01:00
// keep file position for penalty bytes
2016-01-06 12:10:58 +01:00
long long old_fout_pos = tell_64 ( fout ) ;
2016-01-26 12:35:25 +01:00
// read BMP header
2016-01-06 12:10:58 +01:00
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 ) ) {
2016-01-26 12:35:25 +01:00
// recompress directly to fout
2016-01-06 12:10:58 +01:00
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 ) ;
}
2016-01-26 12:35:25 +01:00
} else { // lines aligned to 4 byte, skip those bytes
// recompress directly to fout, but skipping bytes
2016-01-06 12:10:58 +01:00
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 ) ;
2016-01-26 12:35:25 +01:00
// read penalty bytes
2016-01-06 12:10:58 +01:00
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 ) ;
2016-01-26 12:35:25 +01:00
// read penalty bytes
2016-01-06 12:10:58 +01:00
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 ) ;
}
2016-01-26 12:35:25 +01:00
// restore IDAT
2016-01-06 12:10:58 +01:00
fprintf ( fout , " IDAT " ) ;
2016-01-26 12:35:25 +01:00
// restore zLib header (decrease by 1)
2016-01-06 12:10:58 +01:00
own_fread ( in , 1 , 2 , fin ) ;
unsigned char decchar = * ( in + 1 ) - 1 ;
own_fwrite ( in , 1 , 1 , fout ) ;
fputc ( decchar , fout ) ;
2016-01-26 12:35:25 +01:00
// read penalty bytes
2016-01-06 12:10:58 +01:00
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 ) ;
}
2016-01-26 12:35:25 +01:00
// restore first IDAT
2016-01-06 12:10:58 +01:00
fprintf ( fout , " IDAT " ) ;
2016-01-26 12:35:25 +01:00
// restore zLib header (decrease by 1)
2016-01-06 12:10:58 +01:00
own_fread ( in , 1 , 2 , fin ) ;
unsigned char decchar = * ( in + 1 ) - 1 ;
own_fwrite ( in , 1 , 1 , fout ) ;
fputc ( decchar , fout ) ;
2016-01-26 12:35:25 +01:00
// get IDAT count
2016-01-06 12:10:58 +01:00
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 ) ) ) ;
2016-01-26 12:35:25 +01:00
// get first IDAT length
2016-01-06 12:10:58 +01:00
own_fread ( in , 1 , 4 , fin ) ;
idat_lengths [ 0 ] = ( in [ 0 ] < < 24 ) + ( in [ 1 ] < < 16 ) + ( in [ 2 ] < < 8 ) + in [ 3 ] ;
2016-01-26 12:35:25 +01:00
idat_lengths [ 0 ] - = 2 ; // zLib header length
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// get IDAT chunk lengths and CRCs
2016-01-06 12:10:58 +01:00
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 ] ;
}
2016-01-26 12:35:25 +01:00
// read penalty bytes
2016-01-06 12:10:58 +01:00
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 ) ;
2016-01-26 12:35:25 +01:00
// recompress data
2016-01-06 12:10:58 +01:00
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 " ) ;
2017-01-02 11:32:08 +01:00
int remaining_bytes = recompressed_data_length ;
2016-01-06 12:10:58 +01:00
unsigned int act_idat_chunk = 0 ;
for ( ; ; ) {
2017-01-02 11:32:08 +01:00
if ( ( remaining_bytes + 2 ) > ( int ) idat_lengths [ act_idat_chunk ] ) {
2016-01-06 12:10:58 +01:00
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 ;
2016-01-26 12:35:25 +01:00
// read diff bytes
2016-01-06 12:10:58 +01:00
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 ;
2016-01-26 12:35:25 +01:00
// read penalty bytes
2016-01-06 12:10:58 +01:00
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 " ) ;
2016-01-26 12:35:25 +01:00
// recompress data
2016-01-06 12:10:58 +01:00
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 ) ;
}
2016-04-21 14:56:38 +02:00
char recompress_msg [ 256 ] ;
unsigned char * jpg_mem_in = NULL ;
unsigned char * jpg_mem_out = NULL ;
unsigned int jpg_mem_out_size = - 1 ;
2017-08-28 16:52:47 +02:00
bool in_memory = ( recompressed_data_length < = MAX_IO_BUFFER_SIZE ) ;
2016-04-21 14:56:38 +02:00
bool recompress_success = false ;
2016-01-06 12:10:58 +01:00
2016-04-21 14:56:38 +02:00
if ( in_memory ) {
jpg_mem_in = new unsigned char [ decompressed_data_length ] ;
2017-07-17 21:45:14 +05:30
2016-04-21 14:56:38 +02:00
fast_copy ( fin , jpg_mem_in , decompressed_data_length ) ;
2017-07-17 21:45:14 +05:30
2016-04-21 14:56:38 +02:00
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 " ) ;
2016-01-06 12:10:58 +01:00
2016-04-21 14:56:38 +02:00
fast_copy ( fin , ftempout , decompressed_data_length ) ;
2016-01-06 12:10:58 +01:00
2016-04-21 14:56:38 +02:00
safe_fclose ( & ftempout ) ;
2016-01-06 12:10:58 +01:00
2016-04-21 14:56:38 +02:00
remove ( tempfile2 ) ;
2016-01-06 12:10:58 +01:00
2016-04-21 14:56:38 +02:00
recompress_success = pjglib_convert_file2file ( tempfile1 , tempfile2 , recompress_msg ) ;
2016-01-06 12:10:58 +01:00
}
if ( ! recompress_success ) {
2016-04-21 14:56:38 +02:00
if ( DEBUG_MODE ) printf ( " packJPG error: %s \n " , recompress_msg ) ;
2016-01-06 12:10:58 +01:00
printf ( " Error recompressing data! " ) ;
exit ( 1 ) ;
}
2016-04-21 14:56:38 +02:00
if ( ! in_memory ) {
frecomp = tryOpen ( tempfile2 , " rb " ) ;
}
2016-01-06 12:10:58 +01:00
if ( mjpg_dht_used ) {
long long frecomp_pos = 0 ;
bool found_ffda = false ;
bool found_ff = false ;
int ffda_pos = - 1 ;
2016-04-21 14:56:38 +02:00
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 ) ;
}
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
if ( ( ! found_ffda ) | | ( ( ffda_pos - 1 - MJPGDHT_LEN ) < 0 ) ) {
printf ( " ERROR: Motion JPG stream corrupted \n " ) ;
exit ( 1 ) ;
}
2016-04-21 14:56:38 +02:00
// 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 ) ;
2016-01-06 12:10:58 +01:00
2016-04-21 14:56:38 +02:00
frecomp_pos + = ffda_pos - 1 ;
seek_64 ( frecomp , frecomp_pos ) ;
fast_copy ( frecomp , fout , ( recompressed_data_length + MJPGDHT_LEN ) - ( ffda_pos - 1 ) ) ;
}
2016-01-06 12:10:58 +01:00
} else {
2016-04-21 14:56:38 +02:00
if ( in_memory ) {
fast_copy ( jpg_mem_out , fout , recompressed_data_length ) ;
} else {
fast_copy ( frecomp , fout , recompressed_data_length ) ;
}
2016-01-06 12:10:58 +01:00
}
2016-04-21 14:56:38 +02:00
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 ) ;
2016-01-06 12:10:58 +01:00
2016-04-21 14:56:38 +02:00
remove ( tempfile2 ) ;
remove ( tempfile1 ) ;
}
2016-01-06 12:10:58 +01:00
} 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 ) ;
2016-01-26 12:35:25 +01:00
// get Flash version
2016-01-06 12:10:58 +01:00
char c = fin_fgetc ( ) ;
fputc ( c , fout ) ;
2016-01-26 12:35:25 +01:00
// get length from SWF header
2016-01-06 12:10:58 +01:00
for ( int i = 0 ; i < 4 ; i + + ) {
c = fin_fgetc ( ) ;
fputc ( c , fout ) ;
}
2016-01-26 12:35:25 +01:00
// restore zLib header (decrease by 1)
2016-01-06 12:10:58 +01:00
own_fread ( in , 1 , 2 , fin ) ;
unsigned char decchar = * ( in + 1 ) - 1 ;
own_fwrite ( in , 1 , 1 , fout ) ;
fputc ( decchar , fout ) ;
2016-01-26 12:35:25 +01:00
// read penalty bytes
2016-01-06 12:10:58 +01:00
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 ) ;
2016-01-26 12:35:25 +01:00
// restore Base64 "header"
2016-01-06 12:10:58 +01:00
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 ) ;
2016-01-26 12:35:25 +01:00
fputc ( * ( in ) + 1 , fout ) ; // first char was decreased
2016-01-06 12:10:58 +01:00
own_fwrite ( in + 1 , 1 , base64_header_length - 1 , fout ) ;
2016-01-26 12:35:25 +01:00
// read line length list
2016-01-06 12:10:58 +01:00
int line_count = fin_fgetc ( ) < < 8 ;
line_count + = fin_fgetc ( ) ;
2016-04-29 09:23:44 +02:00
unsigned int * base64_line_len = new unsigned int [ line_count ] ;
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
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 ) ;
}
}
2016-01-26 12:35:25 +01:00
// re-encode Base64
2016-01-06 12:10:58 +01:00
if ( recursion_used ) {
recursion_result r = recursion_decompress ( recursion_data_length ) ;
2016-04-29 09:23:44 +02:00
base64_reencode ( r . frecurse , fout , line_count , base64_line_len , r . file_length , decompressed_data_length ) ;
2016-01-06 12:10:58 +01:00
safe_fclose ( & r . frecurse ) ;
remove ( r . file_name ) ;
delete [ ] r . file_name ;
} else {
2016-04-29 09:23:44 +02:00
base64_reencode ( fin , fout , line_count , base64_line_len , recompressed_data_length , decompressed_data_length ) ;
2016-01-06 12:10:58 +01:00
}
2016-04-29 09:23:44 +02:00
delete [ ] base64_line_len ;
2016-01-06 12:10:58 +01:00
} 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 ) ;
}
2016-01-26 12:35:25 +01:00
// read penalty bytes
2016-01-06 12:10:58 +01:00
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 ) ;
}
2016-04-19 06:22:48 +02:00
} else if ( headertype = = 10 ) { // MP3 recompression
2016-01-06 12:10:58 +01:00
2016-01-21 15:39:31 +01:00
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 ) ;
}
2016-01-06 12:10:58 +01:00
2016-04-19 06:22:48 +02:00
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 ) ;
2016-01-21 15:39:31 +01:00
2016-04-19 06:22:48 +02:00
bool recompress_success = false ;
2017-07-17 21:45:14 +05:30
2016-04-19 06:22:48 +02:00
if ( in_memory ) {
mp3_mem_in = new unsigned char [ decompressed_data_length ] ;
2016-01-21 15:39:31 +01:00
2016-04-19 06:22:48 +02:00
fast_copy ( fin , mp3_mem_in , decompressed_data_length ) ;
2016-01-21 15:39:31 +01:00
2016-04-19 06:22:48 +02:00
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 " ) ;
2016-01-21 15:39:31 +01:00
2016-04-19 06:22:48 +02:00
fast_copy ( fin , ftempout , decompressed_data_length ) ;
2016-01-21 15:39:31 +01:00
2016-04-19 06:22:48 +02:00
safe_fclose ( & ftempout ) ;
remove ( tempfile2 ) ;
recompress_success = pmplib_convert_file2file ( tempfile1 , tempfile2 , recompress_msg ) ;
2016-01-21 15:39:31 +01:00
}
if ( ! recompress_success ) {
2016-04-19 06:22:48 +02:00
if ( DEBUG_MODE ) printf ( " packMP3 error: %s \n " , recompress_msg ) ;
2016-01-21 15:39:31 +01:00
printf ( " Error recompressing data! " ) ;
exit ( 1 ) ;
}
2016-04-19 06:22:48 +02:00
if ( in_memory ) {
fast_copy ( mp3_mem_out , fout , recompressed_data_length ) ;
2017-07-17 21:45:14 +05:30
2016-04-19 06:22:48 +02:00
if ( mp3_mem_in ! = NULL ) delete [ ] mp3_mem_in ;
if ( mp3_mem_out ! = NULL ) delete [ ] mp3_mem_out ;
} else {
frecomp = tryOpen ( tempfile2 , " rb " ) ;
2016-01-21 15:39:31 +01:00
2016-04-19 06:22:48 +02:00
fast_copy ( frecomp , fout , recompressed_data_length ) ;
2016-01-21 15:39:31 +01:00
2016-04-19 06:22:48 +02:00
safe_fclose ( & frecomp ) ;
2016-01-21 15:39:31 +01:00
2016-04-19 06:22:48 +02:00
remove ( tempfile2 ) ;
remove ( tempfile1 ) ;
}
2016-01-06 12:10:58 +01:00
} 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 ) ;
}
2016-01-26 12:35:25 +01:00
// read penalty bytes
2016-01-06 12:10:58 +01:00
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 ) ;
}
2016-01-26 12:35:25 +01:00
// restore zLib header (decrease by 1)
2016-01-06 12:10:58 +01:00
own_fread ( in , 1 , 2 , fin ) ;
unsigned char decchar = * ( in + 1 ) - 1 ;
own_fwrite ( in , 1 , 1 , fout ) ;
fputc ( decchar , fout ) ;
2016-01-26 12:35:25 +01:00
// read penalty bytes
2016-01-06 12:10:58 +01:00
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 ) ;
2016-07-02 18:37:31 +02:00
if ( compression_otf_method ! = OTF_NONE ) {
2016-01-06 12:10:58 +01:00
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 ;
2017-03-28 07:21:10 +02:00
init_compress_otf ( ) ;
init_decompress_otf ( ) ;
2017-07-17 21:45:14 +05:30
2017-06-16 07:31:37 +02:00
if ( ! DEBUG_MODE ) show_progress ( 0 , false , false ) ;
2016-01-06 12:10:58 +01:00
for ( ; ; ) {
bytes_read = own_fread ( copybuf , 1 , COPY_BUF_SIZE , fin ) ;
2016-07-02 18:24:23 +02:00
// truncate by 9 bytes (Precomp on-the-fly delimiter) if converting from compressed data
2016-07-02 18:37:31 +02:00
if ( ( conversion_from_method > OTF_NONE ) & & ( bytes_read < COPY_BUF_SIZE ) ) {
2016-01-06 12:10:58 +01:00
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 ) ;
2017-06-11 11:47:05 +02:00
if ( ! DEBUG_MODE ) {
float percent = ( input_file_pos / ( float ) fin_length ) * 100 ;
2017-06-16 07:31:37 +02:00
show_progress ( percent , true , true ) ;
2017-06-11 11:47:05 +02:00
}
2016-01-06 12:10:58 +01:00
}
2017-07-17 21:45:14 +05:30
own_fwrite ( convbuf , 1 , conv_bytes , fout ) ;
2016-01-06 12:10:58 +01:00
denit_compress_otf ( ) ;
denit_decompress_otf ( ) ;
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
denit_convert ( ) ;
}
2017-08-29 17:23:15 +02:00
int try_to_decompress ( FILE * file , int windowbits , int & compressed_stream_size , bool & in_memory ) {
int r , decompressed_stream_size ;
2016-01-06 12:10:58 +01:00
print_work_sign ( true ) ;
2017-08-30 06:46:26 +02:00
if ( file = = fin ) {
seek_64 ( file , input_file_pos ) ;
} else {
2017-12-26 10:16:33 +01:00
seek_64 ( file , 0 ) ;
2017-08-30 06:46:26 +02:00
}
2017-08-29 17:23:15 +02:00
in_memory = true ;
r = inf ( file , windowbits , compressed_stream_size , decompressed_stream_size , in_memory ) ;
if ( r = = Z_OK ) return decompressed_stream_size ;
2016-01-06 12:10:58 +01:00
return r ;
}
2016-06-05 11:49:48 +02:00
int try_to_decompress_bzip2 ( FILE * file , int compression_level , int & compressed_stream_size ) {
2016-01-06 12:10:58 +01:00
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 ;
}
2017-08-29 17:23:15 +02:00
void try_recompress ( FILE * origfile , int comp_level , int mem_level , int windowbits , int & compressed_stream_size , int decomp_bytes_total , bool in_memory ) {
2016-01-06 12:10:58 +01:00
print_work_sign ( true ) ;
2017-08-29 17:23:15 +02:00
identical_bytes = file_recompress ( origfile , comp_level , windowbits , mem_level , identical_bytes_decomp , decomp_bytes_total , in_memory ) ;
2016-01-26 12:35:25 +01:00
if ( identical_bytes > - 1 ) { // successfully recompressed?
2016-06-05 10:22:33 +02:00
if ( ( identical_bytes > best_identical_bytes ) | | ( ( identical_bytes = = best_identical_bytes ) & & ( penalty_bytes_len < best_penalty_bytes_len ) ) ) {
2016-01-06 12:10:58 +01:00
if ( identical_bytes > min_ident_size ) {
if ( DEBUG_MODE ) {
2016-06-05 11:49:48 +02:00
printf ( " Identical recompressed bytes: %i of %i \n " , identical_bytes , compressed_stream_size ) ;
2016-05-28 09:54:57 +02:00
printf ( " Identical decompressed bytes: %i of %i \n " , identical_bytes_decomp , decomp_bytes_total ) ;
2016-01-06 12:10:58 +01:00
}
2017-12-26 10:16:33 +01:00
bool enough_identical_compressed_bytes = ( identical_bytes = = compressed_stream_size ) ;
if ( ! enough_identical_compressed_bytes ) {
if ( ( identical_bytes > DEF_COMPARE_CHUNK ) & & ( identical_bytes + IDENTICAL_COMPRESSED_BYTES_TOLERANCE > = compressed_stream_size ) ) {
enough_identical_compressed_bytes = true ;
}
}
2017-08-30 08:17:31 +02:00
final_compression_found = ( identical_bytes_decomp = = decomp_bytes_total ) & & ( enough_identical_compressed_bytes ) & & ( penalty_bytes_len < PENALTY_BYTES_TOLERANCE ) ;
2016-01-06 12:10:58 +01:00
2017-12-28 22:14:09 +05:30
// Partial matches sometimes need all the decompressed bytes, but there are much less
2017-08-24 07:09:58 +02:00
// identical recompressed bytes - in these cases, all the decompressed bytes have to
// be stored together with the remaining recompressed bytes, so the result won't compress
// better than the original stream. What's important here is the ratio between recompressed ratio
// and decompressed ratio that shouldn't get too high.
// Example: A stream has 5 of 1000 identical recompressed bytes, but needs 1000 of 1000 decompressed bytes,
// so the ratio is (1000/1000)/(5/1000) = 200 which is too high. With 5 of 1000 decompressed bytes or
// 1000 of 1000 identical recompressed bytes, ratio would've been 1 and we'd accept it.
float partial_ratio = ( ( float ) identical_bytes_decomp / decomp_bytes_total ) / ( ( float ) identical_bytes / compressed_stream_size ) ;
if ( partial_ratio < 3.0f ) {
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 ;
}
} else {
if ( DEBUG_MODE ) {
printf ( " Not enough identical recompressed bytes \n " ) ;
}
}
2016-01-06 12:10:58 +01:00
}
}
}
}
2016-06-05 11:49:48 +02:00
void try_recompress_bzip2 ( FILE * origfile , int level , int & compressed_stream_size ) {
2016-01-06 12:10:58 +01:00
print_work_sign ( true ) ;
2016-05-30 13:54:09 +02:00
int decomp_bytes_total ;
identical_bytes = file_recompress_bzip2 ( origfile , level , identical_bytes_decomp , decomp_bytes_total ) ;
if ( identical_bytes > - 1 ) { // successfully recompressed?
2016-06-05 10:22:33 +02:00
if ( ( identical_bytes > best_identical_bytes ) | | ( ( identical_bytes = = best_identical_bytes ) & & ( penalty_bytes_len < best_penalty_bytes_len ) ) ) {
2016-01-06 12:10:58 +01:00
if ( identical_bytes > min_ident_size ) {
if ( DEBUG_MODE ) {
2016-06-05 11:49:48 +02:00
printf ( " Identical recompressed bytes: %i of %i \n " , identical_bytes , compressed_stream_size ) ;
2016-05-30 13:54:09 +02:00
printf ( " Identical decompressed bytes: %i of %i \n " , identical_bytes_decomp , decomp_bytes_total ) ;
2016-01-06 12:10:58 +01:00
}
2017-12-26 10:16:33 +01:00
bool enough_identical_compressed_bytes = ( identical_bytes = = compressed_stream_size ) ;
if ( ! enough_identical_compressed_bytes ) {
if ( ( identical_bytes > DEF_COMPARE_CHUNK ) & & ( identical_bytes + IDENTICAL_COMPRESSED_BYTES_TOLERANCE > = compressed_stream_size ) ) {
enough_identical_compressed_bytes = true ;
}
}
2017-08-30 08:17:31 +02:00
2017-12-26 10:16:33 +01:00
final_compression_found = ( identical_bytes_decomp = = decomp_bytes_total ) & & ( enough_identical_compressed_bytes ) & & ( penalty_bytes_len < PENALTY_BYTES_TOLERANCE ) ;
2016-01-06 12:10:58 +01:00
}
2016-06-01 06:56:43 +02:00
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 ;
2016-01-06 12:10:58 +01:00
}
}
}
}
void write_header ( ) {
char * input_file_name_without_path = new char [ strlen ( input_file_name ) + 1 ] ;
fprintf ( fout , " PCF " ) ;
2016-01-26 12:35:25 +01:00
// version number
2016-01-06 12:10:58 +01:00
fputc ( V_MAJOR , fout ) ;
fputc ( V_MINOR , fout ) ;
fputc ( V_MINOR2 , fout ) ;
2016-01-26 12:35:25 +01:00
// compression-on-the-fly method used
2016-01-06 12:10:58 +01:00
fputc ( compression_otf_method , fout ) ;
2016-01-26 12:35:25 +01:00
// write input file name without path
2016-01-06 12:10:58 +01:00
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 ;
2016-01-26 12:35:25 +01:00
// initialize compression-on-the-fly now
2016-07-02 18:37:31 +02:00
if ( compression_otf_method ! = OTF_NONE ) {
2016-01-06 12:10:58 +01:00
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 ) ;
}
2016-01-26 12:35:25 +01:00
// skip compression method
2016-01-06 12:10:58 +01:00
fread ( in , 1 , 1 , fin ) ;
string header_filename = " " ;
char c ;
do {
c = fgetc ( fin ) ;
if ( c ! = 0 ) header_filename + = c ;
} while ( c ! = 0 ) ;
2016-01-26 12:35:25 +01:00
// append output filename to the executable directory
2016-01-06 12:10:58 +01:00
char exec_dir [ 1024 ] ;
GetModuleFileName ( NULL , exec_dir , 1024 ) ;
2016-01-26 12:35:25 +01:00
// truncate to get directory of executable only
2016-01-06 12:10:58 +01:00
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 ) ;
}
2017-06-16 07:31:37 +02:00
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 ;
2017-07-17 21:45:14 +05:30
2017-06-16 07:31:37 +02:00
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 ) {
2016-01-06 12:10:58 +01:00
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 ) ;
2017-06-16 07:31:37 +02:00
own_fwrite ( copybuf , 1 , COPY_BUF_SIZE , file2 , false , update_progress ) ;
2016-01-06 12:10:58 +01:00
2017-06-16 07:31:37 +02:00
if ( ( ( i - 1 ) % FAST_COPY_WORK_SIGN_DIST ) = = 0 ) {
2016-01-06 12:10:58 +01:00
print_work_sign ( true ) ;
2017-06-16 07:31:37 +02:00
if ( ( update_progress ) & & ( ! DEBUG_MODE ) ) progress_update ( i * COPY_BUF_SIZE ) ;
}
2016-01-06 12:10:58 +01:00
}
if ( remaining_bytes ! = 0 ) {
own_fread ( copybuf , 1 , remaining_bytes , file1 ) ;
2017-06-16 07:31:37 +02:00
own_fwrite ( copybuf , 1 , remaining_bytes , file2 , false , update_progress ) ;
2016-01-06 12:10:58 +01:00
}
2017-07-17 21:45:14 +05:30
2017-06-16 07:31:37 +02:00
if ( ( update_progress ) & & ( ! DEBUG_MODE ) ) uncompressed_bytes_written + = bytecount ;
2016-04-18 14:13:10 +02:00
}
2016-04-19 06:22:48 +02:00
void fast_copy ( FILE * file , unsigned char * mem , long long bytecount ) {
2016-04-18 14:13:10 +02:00
if ( bytecount = = 0 ) return ;
2017-07-17 21:45:14 +05:30
2016-04-18 14:13:10 +02:00
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 ) ;
2016-01-06 12:10:58 +01:00
2017-06-16 07:31:37 +02:00
if ( ( ( i - 1 ) % FAST_COPY_WORK_SIGN_DIST ) = = 0 ) print_work_sign ( true ) ;
2016-04-18 14:13:10 +02:00
}
if ( remaining_bytes ! = 0 ) {
own_fread ( mem + maxi * COPY_BUF_SIZE , 1 , remaining_bytes , file ) ;
}
}
2016-04-19 06:22:48 +02:00
void fast_copy ( unsigned char * mem , FILE * file , long long bytecount ) {
2016-04-18 14:13:10 +02:00
if ( bytecount = = 0 ) return ;
2017-07-17 21:45:14 +05:30
2016-04-18 14:13:10 +02:00
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 ) ;
2017-06-16 07:31:37 +02:00
if ( ( ( i - 1 ) % FAST_COPY_WORK_SIGN_DIST ) = = 0 ) print_work_sign ( true ) ;
2016-04-18 14:13:10 +02:00
}
if ( remaining_bytes ! = 0 ) {
own_fwrite ( mem + maxi * COPY_BUF_SIZE , 1 , remaining_bytes , file ) ;
}
2016-01-06 12:10:58 +01:00
}
2017-06-16 07:31:37 +02:00
size_t own_fwrite ( const void * ptr , size_t size , size_t count , FILE * stream , bool final_byte , bool update_lzma_progress ) {
2016-01-06 12:10:58 +01:00
size_t result = 0 ;
bool use_otf = false ;
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
if ( comp_decomp_state = = P_CONVERT ) {
2016-07-02 18:37:31 +02:00
use_otf = ( conversion_to_method > OTF_NONE ) ;
2016-01-06 12:10:58 +01:00
if ( use_otf ) compression_otf_method = conversion_to_method ;
} else {
2016-07-02 18:37:31 +02:00
if ( ( stream ! = fout ) | | ( compression_otf_method = = OTF_NONE ) | | ( comp_decomp_state ! = P_COMPRESS ) ) {
2016-01-06 12:10:58 +01:00
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 ) {
2016-07-02 18:37:31 +02:00
case OTF_BZIP2 : { // bZip2
2016-01-06 12:10:58 +01:00
int flush , ret ;
unsigned have ;
print_work_sign ( true ) ;
2017-06-16 07:31:37 +02:00
flush = final_byte ? BZ_FINISH : BZ_RUN ;
2016-01-06 12:10:58 +01:00
otf_bz2_stream_c . avail_in = size * count ;
otf_bz2_stream_c . next_in = ( char * ) ptr ;
do {
otf_bz2_stream_c . avail_out = CHUNK ;
2016-11-09 16:39:33 +01:00
otf_bz2_stream_c . next_out = ( char * ) otf_out ;
2016-01-06 12:10:58 +01:00
ret = BZ2_bzCompress ( & otf_bz2_stream_c , flush ) ;
have = CHUNK - otf_bz2_stream_c . avail_out ;
2016-11-09 16:39:33 +01:00
if ( fwrite ( otf_out , 1 , have , stream ) ! = have | | ferror ( stream ) ) {
2016-01-06 12:10:58 +01:00
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 ;
}
2016-07-02 18:37:31 +02:00
case OTF_XZ_MT : {
2017-06-16 07:31:37 +02:00
lzma_action action = final_byte ? LZMA_FINISH : LZMA_RUN ;
2016-06-19 16:53:50 +08:00
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 ;
2016-11-09 16:39:33 +01:00
otf_xz_stream_c . next_out = ( uint8_t * ) otf_out ;
2016-06-19 16:53:50 +08:00
ret = lzma_code ( & otf_xz_stream_c , action ) ;
have = CHUNK - otf_xz_stream_c . avail_out ;
2016-11-09 16:39:33 +01:00
if ( fwrite ( otf_out , 1 , have , stream ) ! = have | | ferror ( stream ) ) {
2016-06-19 16:53:50 +08:00
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 ;
}
2016-12-29 18:31:47 +01:00
printf ( " ERROR: liblzma error: %s (error code %u) \n " , msg , ret ) ;
2016-06-19 16:53:50 +08:00
# ifdef COMFORT
wait_for_key ( ) ;
# endif // COMFORT
exit ( 1 ) ;
} // .avail_out == 0
2017-06-16 07:31:37 +02:00
if ( ( ! DEBUG_MODE ) & & ( update_lzma_progress ) ) lzma_progress_update ( ) ;
} while ( ( otf_xz_stream_c . avail_in > 0 ) | | ( final_byte & & ( ret ! = LZMA_STREAM_END ) ) ) ;
2016-06-19 16:53:50 +08:00
result = size * count ;
break ;
}
2016-01-06 12:10:58 +01:00
}
}
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
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 ) {
2016-07-02 18:37:31 +02:00
use_otf = ( conversion_from_method > OTF_NONE ) ;
2016-01-06 12:10:58 +01:00
if ( use_otf ) compression_otf_method = conversion_from_method ;
} else {
2016-07-02 18:37:31 +02:00
if ( ( stream ! = fin ) | | ( compression_otf_method = = OTF_NONE ) | | ( comp_decomp_state ! = P_DECOMPRESS ) ) {
2016-01-06 12:10:58 +01:00
use_otf = false ;
} else {
use_otf = true ;
}
}
if ( ! use_otf ) {
return fread ( ptr , size , count , stream ) ;
} else {
switch ( compression_otf_method ) {
2016-01-26 12:35:25 +01:00
case 1 : { // bZip2
2016-01-06 12:10:58 +01:00
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 ) {
2016-11-09 16:39:33 +01:00
otf_bz2_stream_d . avail_in = fread ( otf_in , 1 , CHUNK , fin ) ;
otf_bz2_stream_d . next_in = ( char * ) otf_in ;
2016-01-06 12:10:58 +01:00
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 ;
}
2016-07-02 18:37:31 +02:00
case OTF_XZ_MT : {
2016-07-02 04:45:05 +02:00
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 ;
2017-07-17 21:45:14 +05:30
2016-07-02 04:45:05 +02:00
do {
print_work_sign ( true ) ;
if ( ( otf_xz_stream_d . avail_in = = 0 ) & & ! feof ( fin ) ) {
2016-11-09 16:39:33 +01:00
otf_xz_stream_d . next_in = ( uint8_t * ) otf_in ;
otf_xz_stream_d . avail_in = fread ( otf_in , 1 , CHUNK , fin ) ;
2017-07-17 21:45:14 +05:30
2016-07-02 04:45:05 +02:00
if ( ferror ( fin ) ) {
2016-12-29 18:31:47 +01:00
printf ( " ERROR: Could not read input file \n " ) ;
2016-07-02 04:45:05 +02:00
exit ( 1 ) ;
}
}
ret = lzma_code ( & otf_xz_stream_d , action ) ;
if ( ret = = LZMA_STREAM_END ) {
decompress_otf_end = true ;
break ;
}
2017-07-17 21:45:14 +05:30
2016-07-02 04:45:05 +02:00
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 ;
}
2016-12-29 18:31:47 +01:00
printf ( " ERROR: liblzma error: %s (error code %u) \n " , msg , ret ) ;
2016-07-02 04:45:05 +02:00
# 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 ;
2016-06-19 16:53:50 +08:00
}
2016-01-06 12:10:58 +01:00
}
}
return 0 ;
}
void seek_64 ( FILE * f , unsigned long long pos ) {
2016-02-13 10:48:56 +01:00
# ifndef UNIX
2016-01-06 12:10:58 +01:00
fpos_t fpt_pos = pos ;
fsetpos ( f , & fpt_pos ) ;
# else
fseeko ( f , pos , SEEK_SET ) ;
# endif
}
unsigned long long tell_64 ( FILE * f ) {
2016-02-13 10:48:56 +01:00
# ifndef UNIX
2016-01-06 12:10:58 +01:00
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 ] ) {
2016-01-26 12:35:25 +01:00
same_byte_count_penalty - = 5 ; // 4 bytes = position, 1 byte = new byte
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// if same_byte_count_penalty is too low, stop
2016-01-06 12:10:58 +01:00
if ( ( long long ) ( same_byte_count_penalty + ( compare_end - same_byte_count ) ) < 0 ) {
endNow = true ;
break ;
}
2016-01-26 12:35:25 +01:00
// stop, if local_penalty_bytes_len gets too big
2016-01-06 12:10:58 +01:00
if ( ( local_penalty_bytes_len + 5 ) > = MAX_PENALTY_BYTES ) {
endNow = true ;
break ;
}
local_penalty_bytes_len + = 5 ;
2016-01-26 12:35:25 +01:00
// position
2016-01-06 12:10:58 +01:00
local_penalty_bytes [ local_penalty_bytes_len - 5 ] = ( same_byte_count > > 24 ) % 256 ;
2017-07-17 21:45:14 +05:30
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 ;
2016-01-06 12:10:58 +01:00
local_penalty_bytes [ local_penalty_bytes_len - 2 ] = same_byte_count % 256 ;
2016-01-26 12:35:25 +01:00
// new byte
2016-01-06 12:10:58 +01:00
local_penalty_bytes [ local_penalty_bytes_len - 1 ] = input_bytes1 [ i ] ;
} else {
same_byte_count_penalty + + ;
}
same_byte_count + + ;
2016-03-19 09:13:54 +01:00
if ( same_byte_count_penalty > rek_same_byte_count_penalty ) {
2016-01-06 12:10:58 +01:00
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 ) {
2016-01-26 12:54:24 +01:00
init_decompression_variables ( ) ;
2016-01-06 12:10:58 +01:00
int windowbits ;
2016-01-26 12:35:25 +01:00
// try to decompress at current position
2016-06-05 11:49:48 +02:00
int compressed_stream_size = - 1 ;
2017-08-29 17:23:15 +02:00
bool in_memory ;
retval = try_to_decompress ( fin , - 15 , compressed_stream_size , in_memory ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
if ( retval > 0 ) { // seems to be a zLib-Stream
2016-01-06 12:10:58 +01:00
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 " ) ;
2016-06-05 11:49:48 +02:00
printf ( " Compressed size: %i \n " , compressed_stream_size ) ;
2017-08-29 17:23:15 +02:00
printf ( " Can be decompressed to %i bytes \n " , retval ) ;
2016-01-06 12:10:58 +01:00
}
2017-12-25 11:14:05 +01:00
2016-01-06 12:10:58 +01:00
for ( windowbits = - 15 ; windowbits < - 7 ; windowbits + + ) {
2017-12-25 11:14:05 +01:00
for ( int index = MTF . First ( ) ; index > = 0 ; index = MTF . Next ( ) ) {
2017-12-27 11:34:22 +01:00
if ( comp_mem_level_count [ index ] = = - 1 ) continue ;
2017-10-31 23:08:01 +01:00
int comp_level = ( index % 9 ) + 1 ;
int mem_level = ( index / 9 ) + 1 ;
2016-01-06 12:10:58 +01:00
2017-08-29 17:23:15 +02:00
try_recompress ( fin , comp_level , mem_level , windowbits , compressed_stream_size , retval , in_memory ) ;
2016-01-06 12:10:58 +01:00
2017-12-25 11:14:05 +01:00
if ( final_compression_found ) { MTF . Update ( ) ; break ; }
2016-01-06 12:10:58 +01:00
}
2016-05-20 16:12:58 +02:00
if ( final_compression_found ) break ;
2016-01-06 12:10:58 +01:00
}
2016-06-05 11:49:48 +02:00
if ( ( best_identical_bytes > min_ident_size ) & & ( best_identical_bytes < best_identical_bytes_decomp ) ) {
2016-01-06 12:10:58 +01:00
recompressed_streams_count + + ;
recompressed_gzip_count + + ;
windowbits = best_windowbits ;
if ( DEBUG_MODE ) {
2016-06-10 22:58:17 +02:00
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 ) ;
2016-01-06 12:10:58 +01:00
}
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 ;
} 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 ;
}
}
2016-01-26 12:35:25 +01:00
// end uncompressed data
2016-01-06 12:10:58 +01:00
compressed_data_found = true ;
end_uncompressed_data ( ) ;
2016-01-26 12:35:25 +01:00
// check recursion
2017-08-29 17:23:15 +02:00
write_ftempout_if_not_present ( best_identical_bytes_decomp , in_memory ) ;
2016-01-06 12:10:58 +01:00
recursion_result r = recursion_compress ( best_identical_bytes , best_identical_bytes_decomp ) ;
2016-01-26 12:35:25 +01:00
// write compressed data header (GZip) without 2 first bytes
2016-01-06 12:10:58 +01:00
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 ) ;
2016-01-26 12:35:25 +01:00
fout_fputc ( 2 ) ; // GZip
2016-01-06 12:10:58 +01:00
fout_fputc ( ( ( ( - windowbits ) - 8 ) < < 4 ) + best_mem_level ) ;
gzip_header_length - = 2 ;
2016-03-19 09:13:54 +01:00
fout_fput24 ( gzip_header_length ) ;
2016-01-06 12:10:58 +01:00
own_fwrite ( in_buf + cb + 2 , 1 , gzip_header_length , fout ) ;
2016-01-26 12:35:25 +01:00
// store penalty bytes, if any
2016-01-06 12:10:58 +01:00
if ( best_penalty_bytes_len ! = 0 ) {
if ( DEBUG_MODE ) {
printf ( " Penalty bytes were used: %i bytes \n " , best_penalty_bytes_len ) ;
}
2016-03-19 09:13:54 +01:00
fout_fput32 ( best_penalty_bytes_len ) ;
2016-01-06 12:10:58 +01:00
for ( int pbc = 0 ; pbc < best_penalty_bytes_len ; pbc + + ) {
fout_fputc ( best_penalty_bytes [ pbc ] ) ;
}
}
2016-03-19 09:13:54 +01:00
fout_fput32 ( best_identical_bytes ) ;
fout_fput32 ( best_identical_bytes_decomp ) ;
2016-01-06 12:10:58 +01:00
if ( r . success ) {
2016-03-19 09:13:54 +01:00
fout_fput64 ( r . file_length ) ;
2016-01-06 12:10:58 +01:00
}
2016-01-26 12:35:25 +01:00
// write decompressed data
2016-01-06 12:10:58 +01:00
if ( r . success ) {
write_decompressed_data ( r . file_length , r . file_name ) ;
remove ( r . file_name ) ;
delete [ ] r . file_name ;
} else {
2017-10-11 06:07:18 +02:00
write_decompressed_data_io_buf ( best_identical_bytes_decomp , in_memory ) ;
2016-01-06 12:10:58 +01:00
}
2016-01-26 12:35:25 +01:00
// start new uncompressed data
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// set input file pointer after recompressed data
2016-01-06 12:10:58 +01:00
input_file_pos + = best_identical_bytes - 1 ;
cb + = best_identical_bytes - 1 ;
} else {
2017-12-28 22:14:09 +05:30
if ( brute_mode_is_active ( ) ) brute_ignore_offsets - > insert ( input_file_pos ) ;
2016-01-06 12:10:58 +01:00
if ( DEBUG_MODE ) {
printf ( " No matches \n " ) ;
}
}
}
}
void try_decompression_png ( int windowbits ) {
2016-01-26 12:54:24 +01:00
init_decompression_variables ( ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// try to decompress at current position
2016-06-05 11:49:48 +02:00
int compressed_stream_size = - 1 ;
2017-08-29 17:23:15 +02:00
bool in_memory ;
retval = try_to_decompress ( fin , windowbits , compressed_stream_size , in_memory ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
if ( retval > 0 ) { // seems to be a zLib-Stream
2016-01-06 12:10:58 +01:00
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 ) ;
2016-06-05 11:49:48 +02:00
printf ( " Compressed size: %i \n " , compressed_stream_size ) ;
2017-08-29 17:23:15 +02:00
printf ( " Can be decompressed to %i bytes \n " , retval ) ;
2016-01-06 12:10:58 +01:00
}
2017-12-25 11:14:05 +01:00
for ( int index = MTF . First ( ) ; index > = 0 ; index = MTF . Next ( ) ) {
2017-12-27 11:34:22 +01:00
if ( comp_mem_level_count [ index ] = = - 1 ) continue ;
2017-10-31 23:08:01 +01:00
int comp_level = ( index % 9 ) + 1 ;
int mem_level = ( index / 9 ) + 1 ;
2016-01-06 12:10:58 +01:00
2017-08-29 17:23:15 +02:00
try_recompress ( fin , comp_level , mem_level , windowbits , compressed_stream_size , retval , in_memory ) ;
2016-01-06 12:10:58 +01:00
2017-12-25 11:14:05 +01:00
if ( final_compression_found ) { MTF . Update ( ) ; break ; }
2016-01-06 12:10:58 +01:00
}
2016-06-05 11:49:48 +02:00
if ( ( best_identical_bytes > min_ident_size ) & & ( best_identical_bytes < best_identical_bytes_decomp ) ) {
2016-01-06 12:10:58 +01:00
recompressed_streams_count + + ;
recompressed_png_count + + ;
if ( DEBUG_MODE ) {
2016-06-10 22:58:17 +02:00
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 ) ;
2016-01-06 12:10:58 +01:00
}
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 ;
} 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 ;
}
}
2016-01-26 12:35:25 +01:00
// end uncompressed data
2016-01-06 12:10:58 +01:00
compressed_data_found = true ;
end_uncompressed_data ( ) ;
2016-01-26 12:35:25 +01:00
// write compressed data header (PNG)
2016-01-06 12:10:58 +01:00
if ( best_penalty_bytes_len = = 0 ) {
fout_fputc ( 1 + ( best_compression < < 2 ) ) ;
} else {
fout_fputc ( 1 + 2 + ( best_compression < < 2 ) ) ;
}
2016-01-26 12:35:25 +01:00
fout_fputc ( 3 ) ; // PNG
2016-01-06 12:10:58 +01:00
fout_fputc ( ( ( ( - windowbits ) - 8 ) < < 4 ) + best_mem_level ) ;
2016-01-26 12:35:25 +01:00
// store zLib header, but increased by 1 to prevent finding it
// again in the next pass
2016-01-06 12:10:58 +01:00
own_fwrite ( zlib_header , 1 , 1 , fout ) ;
unsigned char incchar = * ( zlib_header + 1 ) + 1 ;
fout_fputc ( incchar ) ;
2016-01-26 12:35:25 +01:00
// store penalty bytes, if any
2016-01-06 12:10:58 +01:00
if ( best_penalty_bytes_len ! = 0 ) {
if ( DEBUG_MODE ) {
printf ( " Penalty bytes were used: %i bytes \n " , best_penalty_bytes_len ) ;
}
2016-03-19 09:13:54 +01:00
fout_fput32 ( best_penalty_bytes_len ) ;
2016-01-06 12:10:58 +01:00
for ( int pbc = 0 ; pbc < best_penalty_bytes_len ; pbc + + ) {
fout_fputc ( best_penalty_bytes [ pbc ] ) ;
}
}
2016-03-19 09:13:54 +01:00
fout_fput32 ( best_identical_bytes ) ;
fout_fput32 ( best_identical_bytes_decomp ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// write decompressed data
2016-01-06 12:10:58 +01:00
2017-10-11 06:07:18 +02:00
write_decompressed_data_io_buf ( best_identical_bytes_decomp , in_memory ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// start new uncompressed data
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// set input file pointer after recompressed data
2016-01-06 12:10:58 +01:00
input_file_pos + = best_identical_bytes - 1 ;
cb + = best_identical_bytes - 1 ;
} else {
2017-07-29 11:25:58 +02:00
if ( intense_mode_is_active ( ) ) intense_ignore_offsets - > insert ( input_file_pos - 2 ) ;
2017-12-28 22:14:09 +05:30
if ( brute_mode_is_active ( ) ) brute_ignore_offsets - > insert ( input_file_pos ) ;
2016-01-06 12:10:58 +01:00
if ( DEBUG_MODE ) {
printf ( " No matches \n " ) ;
}
}
}
}
void try_decompression_png_multi ( int windowbits ) {
2016-01-26 12:54:24 +01:00
init_decompression_variables ( ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// try to decompress at current position
2016-06-05 11:49:48 +02:00
int compressed_stream_size = - 1 ;
2017-08-29 17:23:15 +02:00
bool in_memory ;
retval = try_to_decompress ( fpng , windowbits , compressed_stream_size , in_memory ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
if ( retval > 0 ) { // seems to be a zLib-Stream
2016-01-06 12:10:58 +01:00
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 ) ;
2016-06-05 11:49:48 +02:00
printf ( " Compressed size: %i \n " , compressed_stream_size ) ;
2017-08-29 17:23:15 +02:00
printf ( " Can be decompressed to %i bytes \n " , retval ) ;
2016-01-06 12:10:58 +01:00
}
2017-12-25 11:14:05 +01:00
for ( int index = MTF . First ( ) ; index > = 0 ; index = MTF . Next ( ) ) {
2017-12-27 11:34:22 +01:00
if ( comp_mem_level_count [ index ] = = - 1 ) continue ;
2017-10-31 23:08:01 +01:00
int comp_level = ( index % 9 ) + 1 ;
int mem_level = ( index / 9 ) + 1 ;
2016-01-06 12:10:58 +01:00
2017-10-31 23:08:01 +01:00
try_recompress ( fin , comp_level , mem_level , windowbits , compressed_stream_size , retval , in_memory ) ;
2016-01-06 12:10:58 +01:00
2017-12-25 11:14:05 +01:00
if ( final_compression_found ) { MTF . Update ( ) ; break ; }
2016-01-06 12:10:58 +01:00
}
2016-06-05 11:49:48 +02:00
if ( ( best_identical_bytes > min_ident_size ) & & ( best_identical_bytes < best_identical_bytes_decomp ) ) {
2016-01-06 12:10:58 +01:00
recompressed_streams_count + + ;
recompressed_png_multi_count + + ;
if ( DEBUG_MODE ) {
2016-06-10 22:58:17 +02:00
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 ) ;
2016-01-06 12:10:58 +01:00
}
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 ;
} 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 ;
}
}
2016-01-26 12:35:25 +01:00
// end uncompressed data
2016-01-06 12:10:58 +01:00
compressed_data_found = true ;
end_uncompressed_data ( ) ;
2016-01-26 12:35:25 +01:00
// write compressed data header (PNG)
2016-01-06 12:10:58 +01:00
if ( best_penalty_bytes_len = = 0 ) {
fout_fputc ( 1 + ( best_compression < < 2 ) ) ;
} else {
fout_fputc ( 1 + 2 + ( best_compression < < 2 ) ) ;
}
2016-01-26 12:35:25 +01:00
fout_fputc ( 4 ) ; // PNG multi
2016-01-06 12:10:58 +01:00
fout_fputc ( ( ( ( - windowbits ) - 8 ) < < 4 ) + best_mem_level ) ;
2016-01-26 12:35:25 +01:00
// store zLib header, but increased by 1 to prevent finding it
// again in the next pass
2016-01-06 12:10:58 +01:00
own_fwrite ( zlib_header , 1 , 1 , fout ) ;
unsigned char incchar = * ( zlib_header + 1 ) + 1 ;
fout_fputc ( incchar ) ;
2016-01-26 12:35:25 +01:00
// simulate IDAT write to get IDAT pairs count
2016-01-06 12:10:58 +01:00
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 ) ;
}
2016-01-26 12:35:25 +01:00
// store IDAT pairs count
2016-03-19 09:13:54 +01:00
fout_fput16 ( idat_pairs_written_count ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// store IDAT CRCs and lengths
2016-03-19 09:13:54 +01:00
fout_fput32 ( idat_lengths [ 0 ] ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// store IDAT CRCs and lengths
2016-01-06 12:10:58 +01:00
i = 1 ;
idat_pos = idat_lengths [ 0 ] - 2 ;
idat_pairs_written_count = 0 ;
if ( idat_pos < = best_identical_bytes ) {
do {
2016-03-19 09:13:54 +01:00
fout_fput32 ( idat_crcs [ i ] ) ;
fout_fput32 ( idat_lengths [ i ] ) ;
2016-01-06 12:10:58 +01:00
idat_pairs_written_count + + ;
idat_pos + = idat_lengths [ i ] ;
if ( idat_pos > best_identical_bytes ) break ;
i + + ;
} while ( i < idat_count ) ;
}
2016-01-26 12:35:25 +01:00
// store penalty bytes, if any
2016-01-06 12:10:58 +01:00
if ( best_penalty_bytes_len ! = 0 ) {
if ( DEBUG_MODE ) {
printf ( " Penalty bytes were used: %i bytes \n " , best_penalty_bytes_len ) ;
}
2016-03-19 09:13:54 +01:00
fout_fput32 ( best_penalty_bytes_len ) ;
2016-01-06 12:10:58 +01:00
for ( int pbc = 0 ; pbc < best_penalty_bytes_len ; pbc + + ) {
fout_fputc ( best_penalty_bytes [ pbc ] ) ;
}
}
2016-03-19 09:13:54 +01:00
fout_fput32 ( best_identical_bytes ) ;
fout_fput32 ( best_identical_bytes_decomp ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// write decompressed data
2016-01-06 12:10:58 +01:00
2017-10-11 06:07:18 +02:00
write_decompressed_data_io_buf ( best_identical_bytes_decomp , in_memory ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// start new uncompressed data
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// set input file pointer after recompressed data
2016-01-06 12:10:58 +01:00
input_file_pos + = best_identical_bytes - 1 ;
cb + = best_identical_bytes - 1 ;
2016-01-26 12:35:25 +01:00
// now add IDAT chunk overhead
2016-01-06 12:10:58 +01:00
input_file_pos + = ( idat_pairs_written_count * 12 ) ;
cb + = ( idat_pairs_written_count * 12 ) ;
} else {
2017-07-29 11:25:58 +02:00
if ( intense_mode_is_active ( ) ) intense_ignore_offsets - > insert ( input_file_pos - 2 ) ;
2017-12-28 22:14:09 +05:30
if ( brute_mode_is_active ( ) ) brute_ignore_offsets - > insert ( input_file_pos ) ;
2016-01-06 12:10:58 +01:00
if ( DEBUG_MODE ) {
printf ( " No matches \n " ) ;
}
}
}
}
2016-01-26 12:35:25 +01:00
// GIF functions
2016-01-06 12:10:58 +01:00
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
{
2016-03-19 09:13:54 +01:00
* ( short * ) dst = * ( short * ) src ;
src = ( unsigned char * ) src + 2 ;
dst = ( unsigned char * ) dst + 2 ;
count - = 2 ;
2016-01-06 12:10:58 +01:00
}
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 ) ;
2016-01-26 12:35:25 +01:00
// change PGF8xa to GIF8xa
2016-01-06 12:10:58 +01:00
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 ) ;
}
2016-01-26 12:35:25 +01:00
// this does send a clear code, so we pass g and gd
2017-06-07 07:01:58 +02:00
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 ;
}
2016-01-06 12:10:58 +01:00
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 ) ;
2016-01-26 12:35:25 +01:00
// change GIF8xa to PGF8xa
2016-01-06 12:10:58 +01:00
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 ) ;
2016-01-26 12:35:25 +01:00
// TODO: If this fails, write as much rows to dstfile
// as possible to support second decompression.
2016-01-06 12:10:58 +01:00
return false ;
}
}
}
2016-01-26 12:35:25 +01:00
// write to dstfile
2016-01-06 12:10:58 +01:00
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 ;
}
2016-01-26 12:35:25 +01:00
// write to dstfile
2016-01-06 12:10:58 +01:00
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 ) ;
2016-01-26 12:35:25 +01:00
// read GIF file
2016-01-06 12:10:58 +01:00
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 ) {
2016-06-01 09:32:51 +02:00
printf ( " Recompression failed \n " ) ;
2016-01-06 12:10:58 +01:00
}
} else {
if ( DEBUG_MODE ) {
printf ( " Recompression successful \n " ) ;
}
recompress_success_needed = true ;
2016-06-01 09:32:51 +02:00
if ( best_identical_bytes > min_ident_size ) {
recompressed_streams_count + + ;
recompressed_gif_count + + ;
non_zlib_was_used = true ;
2017-07-17 21:45:14 +05:30
2016-06-01 09:32:51 +02:00
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 ;
}
2016-01-06 12:10:58 +01:00
2016-06-01 09:32:51 +02:00
// end uncompressed data
2016-01-06 12:10:58 +01:00
2016-06-01 09:32:51 +02:00
compressed_data_found = true ;
end_uncompressed_data ( ) ;
2016-01-06 12:10:58 +01:00
2016-06-01 09:32:51 +02:00
// 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 ;
2016-01-06 12:10:58 +01:00
2016-06-01 09:32:51 +02:00
fout_fputc ( 1 + add_bits ) ;
fout_fputc ( 5 ) ; // GIF
2016-01-06 12:10:58 +01:00
2016-06-01 09:32:51 +02:00
// store diff bytes
fout_fput32 ( gDiff . GIFDiffIndex ) ;
if ( DEBUG_MODE ) {
if ( gDiff . GIFDiffIndex > 0 )
printf ( " Diff bytes were used: %i bytes \n " , gDiff . GIFDiffIndex ) ;
2016-01-06 12:10:58 +01:00
}
2016-06-01 09:32:51 +02:00
for ( int dbc = 0 ; dbc < gDiff . GIFDiffIndex ; dbc + + ) {
fout_fputc ( gDiff . GIFDiff [ dbc ] ) ;
2016-01-06 12:10:58 +01:00
}
2016-06-01 09:32:51 +02:00
// 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 ) ;
2016-01-06 12:10:58 +01:00
2016-06-01 09:32:51 +02:00
for ( int pbc = 0 ; pbc < best_penalty_bytes_len ; pbc + + ) {
fout_fputc ( best_penalty_bytes [ pbc ] ) ;
}
}
2016-01-06 12:10:58 +01:00
2016-06-01 09:32:51 +02:00
fout_fput32 ( best_identical_bytes ) ;
fout_fput32 ( decomp_length ) ;
2016-01-06 12:10:58 +01:00
2016-06-01 09:32:51 +02:00
// write decompressed data
write_decompressed_data ( decomp_length ) ;
2016-01-06 12:10:58 +01:00
2016-06-01 09:32:51 +02:00
// start new uncompressed data
2016-01-06 12:10:58 +01:00
2016-06-01 09:32:51 +02:00
// set input file pointer after recompressed data
input_file_pos + = gif_length - 1 ;
cb + = gif_length - 1 ;
}
2016-01-06 12:10:58 +01:00
}
2016-06-01 09:32:51 +02:00
2016-01-06 12:10:58 +01:00
} else {
if ( DEBUG_MODE ) {
printf ( " No matches \n " ) ;
}
safe_fclose ( & frecomp ) ;
safe_fclose ( & ftempout ) ;
}
GifDiffFree ( & gDiff ) ;
GifCodeFree ( & gCode ) ;
remove ( tempfile2 ) ;
remove ( tempfile1 ) ;
}
2016-01-26 12:35:25 +01:00
// JPG routines
2016-01-06 12:10:58 +01:00
2016-01-17 16:34:42 +01:00
void packjpg_mp3_dll_msg ( ) {
2016-01-06 12:10:58 +01:00
2016-01-25 15:15:50 +01:00
printf ( " Using packJPG for JPG recompression, packMP3 for MP3 recompression. \n " ) ;
2016-01-14 14:42:08 +01:00
printf ( " %s \n " , pjglib_version_info ( ) ) ;
2016-01-17 16:34:42 +01:00
printf ( " %s \n " , pmplib_version_info ( ) ) ;
2016-01-25 15:15:50 +01:00
printf ( " More about packJPG and packMP3 here: http://www.matthiasstirner.com \n \n " ) ;
2016-01-06 12:10:58 +01:00
}
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 " ) ;
2016-01-26 12:35:25 +01:00
// do not recompress non-progressive JPGs when prog_only is set
2016-01-06 12:10:58 +01:00
if ( ( ! progressive_jpg ) & & ( prog_only ) ) {
printf ( " Skipping (only progressive JPGs mode set) \n " ) ;
}
}
2016-01-26 12:35:25 +01:00
// do not recompress non-progressive JPGs when prog_only is set
2016-01-06 12:10:58 +01:00
if ( ( ! progressive_jpg ) & & ( prog_only ) ) return ;
bool jpg_success = false ;
bool recompress_success = false ;
bool mjpg_dht_used = false ;
2016-04-21 08:21:04 +02:00
char recompress_msg [ 256 ] ;
unsigned char * jpg_mem_in = NULL ;
unsigned char * jpg_mem_out = NULL ;
unsigned int jpg_mem_out_size = - 1 ;
2017-08-28 16:52:47 +02:00
bool in_memory = ( ( jpg_length + MJPGDHT_LEN ) < = MAX_IO_BUFFER_SIZE ) ;
2016-04-21 08:21:04 +02:00
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 ) ;
2017-07-17 21:45:14 +05:30
2016-04-21 08:21:04 +02:00
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 ) ;
}
2017-07-17 21:45:14 +05:30
2016-04-21 08:21:04 +02:00
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 ;
2017-07-17 21:45:14 +05:30
2016-04-21 08:21:04 +02:00
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 ) ;
2016-01-06 12:10:58 +01:00
2016-04-21 08:21:04 +02:00
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 {
2016-01-06 12:10:58 +01:00
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 ) ;
2016-01-26 12:35:25 +01:00
// insert MJPGDHT
2016-01-06 12:10:58 +01:00
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 ) ;
2016-04-21 08:21:04 +02:00
recompress_success = pjglib_convert_file2file ( tempfile3 , tempfile1 , recompress_msg ) ;
2016-01-06 12:10:58 +01:00
}
2017-07-17 21:45:14 +05:30
2016-04-21 08:21:04 +02:00
mjpg_dht_used = recompress_success ;
}
2017-07-17 21:45:14 +05:30
2016-04-21 08:21:04 +02:00
decompressed_streams_count + + ;
if ( progressive_jpg ) {
decompressed_jpg_prog_count + + ;
} else {
decompressed_jpg_count + + ;
}
2016-01-06 12:10:58 +01:00
2016-04-21 08:21:04 +02:00
if ( ! recompress_success ) {
if ( DEBUG_MODE ) printf ( " packJPG error: %s \n " , recompress_msg ) ;
}
2016-01-06 12:10:58 +01:00
2016-04-21 08:21:04 +02:00
if ( ! in_memory ) {
2016-01-06 12:10:58 +01:00
remove ( tempfile0 ) ;
}
if ( recompress_success ) {
2017-07-17 21:45:14 +05:30
int jpg_new_length = - 1 ;
2016-04-21 08:21:04 +02:00
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 ) ;
2017-07-17 21:45:14 +05:30
}
2016-01-06 12:10:58 +01:00
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 ) ;
}
2016-01-26 12:35:25 +01:00
// end uncompressed data
2016-01-06 12:10:58 +01:00
compressed_data_found = true ;
end_uncompressed_data ( ) ;
2016-01-26 12:35:25 +01:00
// write compressed data header (JPG)
2016-01-06 12:10:58 +01:00
if ( mjpg_dht_used ) {
2016-01-26 12:35:25 +01:00
fout_fputc ( 1 + 4 ) ; // no penalty bytes, Motion JPG DHT used
2016-01-06 12:10:58 +01:00
} else {
2016-01-26 12:35:25 +01:00
fout_fputc ( 1 ) ; // no penalty bytes
2016-01-06 12:10:58 +01:00
}
2016-01-26 12:35:25 +01:00
fout_fputc ( 6 ) ; // JPG
2016-01-06 12:10:58 +01:00
2016-03-19 09:13:54 +01:00
fout_fput32 ( best_identical_bytes ) ;
fout_fput32 ( best_identical_bytes_decomp ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// write compressed JPG
2016-04-21 08:21:04 +02:00
if ( in_memory ) {
fast_copy ( jpg_mem_out , fout , best_identical_bytes_decomp ) ;
} else {
write_decompressed_data ( best_identical_bytes_decomp ) ;
}
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// start new uncompressed data
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// set input file pointer after recompressed data
2016-01-06 12:10:58 +01:00
input_file_pos + = best_identical_bytes - 1 ;
cb + = best_identical_bytes - 1 ;
} else {
if ( DEBUG_MODE ) {
printf ( " No matches \n " ) ;
}
}
2016-04-21 08:21:04 +02:00
if ( jpg_mem_in ! = NULL ) delete [ ] jpg_mem_in ;
2017-07-17 21:45:14 +05:30
if ( jpg_mem_out ! = NULL ) delete [ ] jpg_mem_out ;
2016-01-06 12:10:58 +01:00
}
2016-01-21 15:39:31 +01:00
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 ;
2016-04-18 14:13:10 +02:00
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 ) ;
2016-04-19 06:22:48 +02:00
fast_copy ( fin , mp3_mem_in , mp3_length ) ;
2017-07-17 21:45:14 +05:30
2016-04-18 14:13:10 +02:00
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 ) ;
}
2017-07-17 21:45:14 +05:30
2016-04-18 14:13:10 +02:00
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 ) ;
2017-07-17 21:45:14 +05:30
2016-04-18 14:13:10 +02:00
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 {
2016-03-19 09:13:54 +01:00
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 ) ;
2016-04-18 14:13:10 +02:00
recompress_success = pmplib_convert_file2file ( tempfile0 , tempfile1 , recompress_msg ) ;
2016-03-19 09:13:54 +01:00
}
}
}
2016-05-06 11:31:47 +02:00
} 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 " ) ;
}
2016-04-18 14:13:10 +02:00
}
2017-07-17 21:45:14 +05:30
2016-04-18 14:13:10 +02:00
decompressed_streams_count + + ;
decompressed_mp3_count + + ;
2016-01-21 15:39:31 +01:00
2016-04-18 14:13:10 +02:00
if ( ! recompress_success ) {
if ( DEBUG_MODE ) printf ( " packMP3 error: %s \n " , recompress_msg ) ;
}
2016-01-21 15:39:31 +01:00
2016-04-18 14:13:10 +02:00
if ( ! in_memory ) {
2016-01-21 15:39:31 +01:00
remove ( tempfile0 ) ;
}
if ( recompress_success ) {
2016-04-18 14:13:10 +02:00
int mp3_new_length = - 1 ;
2017-07-17 21:45:14 +05:30
2016-04-18 14:13:10 +02:00
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 ) ;
}
2017-07-17 21:45:14 +05:30
2016-01-21 15:39:31 +01:00
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 ) ;
}
2016-01-26 12:35:25 +01:00
// end uncompressed data
2016-01-21 15:39:31 +01:00
compressed_data_found = true ;
end_uncompressed_data ( ) ;
2016-01-26 12:35:25 +01:00
// write compressed data header (MP3)
2016-01-21 15:39:31 +01:00
2016-01-26 12:35:25 +01:00
fout_fputc ( 1 ) ; // no penalty bytes
fout_fputc ( 10 ) ; // MP3
2016-01-21 15:39:31 +01:00
2016-03-19 09:13:54 +01:00
fout_fput32 ( best_identical_bytes ) ;
fout_fput32 ( best_identical_bytes_decomp ) ;
2016-01-21 15:39:31 +01:00
2016-01-26 12:35:25 +01:00
// write compressed MP3
2016-04-18 14:13:10 +02:00
if ( in_memory ) {
2016-04-19 06:22:48 +02:00
fast_copy ( mp3_mem_out , fout , best_identical_bytes_decomp ) ;
2016-04-18 14:13:10 +02:00
} else {
write_decompressed_data ( best_identical_bytes_decomp ) ;
}
2016-01-21 15:39:31 +01:00
2016-01-26 12:35:25 +01:00
// start new uncompressed data
2016-01-21 15:39:31 +01:00
2016-01-26 12:35:25 +01:00
// set input file pointer after recompressed data
2016-01-21 15:39:31 +01:00
input_file_pos + = best_identical_bytes - 1 ;
cb + = best_identical_bytes - 1 ;
} else {
if ( DEBUG_MODE ) {
printf ( " No matches \n " ) ;
}
}
2016-04-18 14:13:10 +02:00
if ( mp3_mem_in ! = NULL ) delete [ ] mp3_mem_in ;
if ( mp3_mem_out ! = NULL ) delete [ ] mp3_mem_out ;
2016-01-21 15:39:31 +01:00
}
2016-04-29 16:23:40 +02:00
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 ;
2017-07-17 21:45:14 +05:30
2016-04-29 16:23:40 +02:00
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 ;
}
}
2017-07-17 21:45:14 +05:30
2016-04-29 16:23:40 +02:00
abitreader * side_reader = new abitreader ( sideinfo , nsb ) ;
2017-07-17 21:45:14 +05:30
2016-04-29 16:23:40 +02:00
side_reader - > read ( ( nch = = 1 ) ? 18 : 20 ) ;
2017-07-17 21:45:14 +05:30
2016-04-29 16:23:40 +02:00
// 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 ) ;
}
2017-07-17 21:45:14 +05:30
}
2016-04-29 16:23:40 +02:00
delete ( side_reader ) ;
2017-07-17 21:45:14 +05:30
2016-04-29 16:23:40 +02:00
return true ;
}
/* -----------------------------------------------
2017-12-26 10:16:33 +01:00
calculate frame crc
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2016-04-29 16:23:40 +02:00
inline unsigned short mp3_calc_layer3_crc ( unsigned char header2 , unsigned char header3 , unsigned char * sideinfo , int sidesize )
{
2017-12-26 10:16:33 +01:00
// crc has a start value of 0xFFFF
unsigned short crc = 0xFFFF ;
2017-07-17 21:45:14 +05:30
2017-12-26 10:16:33 +01:00
// 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 ] ] ;
2017-07-17 21:45:14 +05:30
2017-12-26 10:16:33 +01:00
return crc ;
2016-04-29 16:23:40 +02:00
}
2016-01-06 12:10:58 +01:00
void try_decompression_zlib ( int windowbits ) {
2016-01-26 12:54:24 +01:00
init_decompression_variables ( ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// try to decompress at current position
2016-06-05 11:49:48 +02:00
int compressed_stream_size = - 1 ;
2017-08-29 17:23:15 +02:00
bool in_memory ;
retval = try_to_decompress ( fin , windowbits , compressed_stream_size , in_memory ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
if ( retval > 0 ) { // seems to be a zLib-Stream
2016-01-06 12:10:58 +01:00
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 ) ;
2016-06-05 11:49:48 +02:00
printf ( " Compressed size: %i \n " , compressed_stream_size ) ;
2017-08-29 17:23:15 +02:00
printf ( " Can be decompressed to %i bytes \n " , retval ) ;
2016-06-07 10:58:33 +02:00
}
2017-12-25 11:14:05 +01:00
for ( int index = MTF . First ( ) ; index > = 0 ; index = MTF . Next ( ) ) {
2017-12-27 11:34:22 +01:00
if ( comp_mem_level_count [ index ] = = - 1 ) continue ;
2017-10-31 23:08:01 +01:00
int comp_level = ( index % 9 ) + 1 ;
int mem_level = ( index / 9 ) + 1 ;
2016-01-06 12:10:58 +01:00
2017-08-29 17:23:15 +02:00
try_recompress ( fin , comp_level , mem_level , windowbits , compressed_stream_size , retval , in_memory ) ;
2016-01-06 12:10:58 +01:00
2017-12-25 11:14:05 +01:00
if ( final_compression_found ) { MTF . Update ( ) ; break ; }
2016-01-06 12:10:58 +01:00
}
2017-07-29 11:10:27 +02:00
if ( ( best_identical_bytes > min_ident_size_intense_brute_mode ) & & ( best_identical_bytes < best_identical_bytes_decomp ) ) {
2016-01-06 12:10:58 +01:00
recompressed_streams_count + + ;
recompressed_zlib_count + + ;
if ( DEBUG_MODE ) {
2016-06-10 22:58:17 +02:00
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 ) ;
2016-01-06 12:10:58 +01:00
}
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 ;
} 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 ;
}
}
2016-01-26 12:35:25 +01:00
// end uncompressed data
2016-01-06 12:10:58 +01:00
compressed_data_found = true ;
end_uncompressed_data ( ) ;
2016-01-26 12:35:25 +01:00
// check recursion
2017-08-29 17:23:15 +02:00
write_ftempout_if_not_present ( best_identical_bytes_decomp , in_memory ) ;
2016-01-06 12:10:58 +01:00
recursion_result r = recursion_compress ( best_identical_bytes , best_identical_bytes_decomp ) ;
2016-01-26 12:35:25 +01:00
// write compressed data header (zLib)
2016-01-06 12:10:58 +01:00
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 ) ;
2016-01-26 12:35:25 +01:00
fout_fputc ( 255 ) ; // raw zLib
2016-01-06 12:10:58 +01:00
fout_fputc ( ( ( ( - windowbits ) - 8 ) < < 4 ) + best_mem_level ) ;
2016-01-26 12:35:25 +01:00
// store zLib header, but increased by 1 to prevent finding it
// again in the next pass
2016-01-06 12:10:58 +01:00
own_fwrite ( in_buf + cb , 1 , 1 , fout ) ;
unsigned char incchar = * ( in_buf + cb + 1 ) + 1 ;
fout_fputc ( incchar ) ;
2016-01-26 12:35:25 +01:00
// store penalty bytes, if any
2016-01-06 12:10:58 +01:00
if ( best_penalty_bytes_len ! = 0 ) {
if ( DEBUG_MODE ) {
printf ( " Penalty bytes were used: %i bytes \n " , best_penalty_bytes_len ) ;
}
2016-03-19 09:13:54 +01:00
fout_fput32 ( best_penalty_bytes_len ) ;
2016-01-06 12:10:58 +01:00
for ( int pbc = 0 ; pbc < best_penalty_bytes_len ; pbc + + ) {
fout_fputc ( best_penalty_bytes [ pbc ] ) ;
}
}
2016-03-19 09:13:54 +01:00
fout_fput32 ( best_identical_bytes ) ;
fout_fput32 ( best_identical_bytes_decomp ) ;
2016-01-06 12:10:58 +01:00
if ( r . success ) {
2016-03-19 09:13:54 +01:00
fout_fput64 ( r . file_length ) ;
2016-01-06 12:10:58 +01:00
}
2016-01-26 12:35:25 +01:00
// write decompressed data
2016-01-06 12:10:58 +01:00
if ( r . success ) {
write_decompressed_data ( r . file_length , r . file_name ) ;
remove ( r . file_name ) ;
delete [ ] r . file_name ;
} else {
2017-10-11 06:07:18 +02:00
write_decompressed_data_io_buf ( best_identical_bytes_decomp , in_memory ) ;
2016-01-06 12:10:58 +01:00
}
2016-01-26 12:35:25 +01:00
// start new uncompressed data
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// set input file pointer after recompressed data
2016-01-06 12:10:58 +01:00
input_file_pos + = best_identical_bytes - 1 ;
cb + = best_identical_bytes - 1 ;
} else {
2017-12-28 22:14:09 +05:30
if ( brute_mode_is_active ( ) ) brute_ignore_offsets - > insert ( input_file_pos ) ;
2016-01-06 12:10:58 +01:00
if ( DEBUG_MODE ) {
printf ( " No matches \n " ) ;
}
}
}
}
void try_decompression_brute ( ) {
2016-01-26 12:54:24 +01:00
init_decompression_variables ( ) ;
2016-01-06 12:10:58 +01:00
int windowbits ;
2016-01-26 12:35:25 +01:00
// try to decompress at current position
2016-06-05 11:49:48 +02:00
int compressed_stream_size = - 1 ;
2017-08-29 17:23:15 +02:00
bool in_memory ;
retval = try_to_decompress ( fin , - 15 , compressed_stream_size , in_memory ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
if ( retval > 0 ) { // seems to be a zLib-Stream
2016-01-06 12:10:58 +01:00
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 " ) ;
2016-06-05 11:49:48 +02:00
printf ( " Compressed size: %i \n " , compressed_stream_size ) ;
2017-08-29 17:23:15 +02:00
printf ( " Can be decompressed to %i bytes \n " , retval ) ;
2016-06-07 10:58:33 +02:00
}
2017-12-25 11:14:05 +01:00
2016-01-25 15:03:31 +01:00
for ( windowbits = - 15 ; windowbits < - 7 ; windowbits + + ) {
2017-12-25 11:14:05 +01:00
for ( int index = MTF . First ( ) ; index > = 0 ; index = MTF . Next ( ) ) {
2017-12-27 11:34:22 +01:00
if ( comp_mem_level_count [ index ] = = - 1 ) continue ;
2017-10-31 23:08:01 +01:00
int comp_level = ( index % 9 ) + 1 ;
int mem_level = ( index / 9 ) + 1 ;
2016-01-06 12:10:58 +01:00
2017-08-29 17:23:15 +02:00
try_recompress ( fin , comp_level , mem_level , windowbits , compressed_stream_size , retval , in_memory ) ;
2016-01-06 12:10:58 +01:00
2017-12-25 11:14:05 +01:00
if ( final_compression_found ) { MTF . Update ( ) ; break ; }
2016-01-06 12:10:58 +01:00
}
2016-05-20 16:12:58 +02:00
if ( final_compression_found ) break ;
2016-01-06 12:10:58 +01:00
}
2017-07-29 11:10:27 +02:00
if ( ( best_identical_bytes > min_ident_size_intense_brute_mode ) & & ( best_identical_bytes < best_identical_bytes_decomp ) ) {
2016-01-06 12:10:58 +01:00
recompressed_streams_count + + ;
recompressed_brute_count + + ;
windowbits = best_windowbits ;
if ( DEBUG_MODE ) {
2016-06-10 22:58:17 +02:00
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 ) ;
2016-01-06 12:10:58 +01:00
}
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 ;
} 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 ;
}
}
2016-01-26 12:35:25 +01:00
// end uncompressed data
2016-01-06 12:10:58 +01:00
compressed_data_found = true ;
end_uncompressed_data ( ) ;
2016-01-26 12:35:25 +01:00
// check recursion
2017-08-29 17:23:15 +02:00
write_ftempout_if_not_present ( best_identical_bytes_decomp , in_memory ) ;
2016-01-06 12:10:58 +01:00
recursion_result r = recursion_compress ( best_identical_bytes , best_identical_bytes_decomp ) ;
2016-01-26 12:35:25 +01:00
// write compressed data header (brute)
2016-01-06 12:10:58 +01:00
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 ) ;
2016-01-26 12:35:25 +01:00
fout_fputc ( 254 ) ; // brute
2016-01-06 12:10:58 +01:00
fout_fputc ( ( ( ( - windowbits ) - 8 ) < < 4 ) + best_mem_level ) ;
2016-01-26 12:35:25 +01:00
// store penalty bytes, if any
2016-01-06 12:10:58 +01:00
if ( best_penalty_bytes_len ! = 0 ) {
if ( DEBUG_MODE ) {
printf ( " Penalty bytes were used: %i bytes \n " , best_penalty_bytes_len ) ;
}
2016-03-19 09:13:54 +01:00
fout_fput32 ( best_penalty_bytes_len ) ;
2016-01-06 12:10:58 +01:00
for ( int pbc = 0 ; pbc < best_penalty_bytes_len ; pbc + + ) {
fout_fputc ( best_penalty_bytes [ pbc ] ) ;
}
}
2016-03-19 09:13:54 +01:00
fout_fput32 ( best_identical_bytes ) ;
fout_fput32 ( best_identical_bytes_decomp ) ;
2016-01-06 12:10:58 +01:00
if ( r . success ) {
2016-03-19 09:13:54 +01:00
fout_fput64 ( r . file_length ) ;
2016-01-06 12:10:58 +01:00
}
2016-01-26 12:35:25 +01:00
// write decompressed data
2016-01-06 12:10:58 +01:00
if ( r . success ) {
write_decompressed_data ( r . file_length , r . file_name ) ;
remove ( r . file_name ) ;
delete [ ] r . file_name ;
} else {
2017-10-11 06:07:18 +02:00
write_decompressed_data_io_buf ( best_identical_bytes_decomp , in_memory ) ;
2016-01-06 12:10:58 +01:00
}
2016-01-26 12:35:25 +01:00
// set input file pointer after recompressed data
2016-01-06 12:10:58 +01:00
input_file_pos + = best_identical_bytes - 1 ;
cb + = best_identical_bytes - 1 ;
} else {
if ( DEBUG_MODE ) {
printf ( " No matches \n " ) ;
}
}
}
}
2016-03-21 14:06:57 +01:00
void try_decompression_swf ( int windowbits ) {
2016-01-26 12:54:24 +01:00
init_decompression_variables ( ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// try to decompress at current position
2016-06-05 11:49:48 +02:00
int compressed_stream_size = - 1 ;
2017-08-29 17:23:15 +02:00
bool in_memory ;
retval = try_to_decompress ( fin , windowbits , compressed_stream_size , in_memory ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
if ( retval > 0 ) { // seems to be a zLib-Stream
2016-01-06 12:10:58 +01:00
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 ) ;
2016-06-05 11:49:48 +02:00
printf ( " Compressed size: %i \n " , compressed_stream_size ) ;
2017-08-29 17:23:15 +02:00
printf ( " Can be decompressed to %i bytes \n " , retval ) ;
2016-01-06 12:10:58 +01:00
}
2017-12-25 11:14:05 +01:00
for ( int index = MTF . First ( ) ; index > = 0 ; index = MTF . Next ( ) ) {
2017-12-27 11:34:22 +01:00
if ( comp_mem_level_count [ index ] = = - 1 ) continue ;
2017-10-31 23:08:01 +01:00
int comp_level = ( index % 9 ) + 1 ;
int mem_level = ( index / 9 ) + 1 ;
2016-01-06 12:10:58 +01:00
2017-08-29 17:23:15 +02:00
try_recompress ( fin , comp_level , mem_level , windowbits , compressed_stream_size , retval , in_memory ) ;
2016-01-06 12:10:58 +01:00
2017-12-25 11:14:05 +01:00
if ( final_compression_found ) { MTF . Update ( ) ; break ; }
2016-01-06 12:10:58 +01:00
}
2016-06-05 11:49:48 +02:00
if ( ( best_identical_bytes > min_ident_size ) & & ( best_identical_bytes < best_identical_bytes_decomp ) ) {
2016-01-06 12:10:58 +01:00
recompressed_streams_count + + ;
recompressed_swf_count + + ;
if ( DEBUG_MODE ) {
2016-06-10 22:58:17 +02:00
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 ) ;
2016-01-06 12:10:58 +01:00
}
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 ;
} 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 ;
}
}
2016-01-26 12:35:25 +01:00
// end uncompressed data
2016-01-06 12:10:58 +01:00
compressed_data_found = true ;
end_uncompressed_data ( ) ;
2016-01-26 12:35:25 +01:00
// check recursion
2017-08-29 17:23:15 +02:00
write_ftempout_if_not_present ( best_identical_bytes_decomp , in_memory ) ;
2016-01-06 12:10:58 +01:00
recursion_result r = recursion_compress ( best_identical_bytes , best_identical_bytes_decomp ) ;
2016-01-26 12:35:25 +01:00
// write compressed data header (SWF)
2016-01-06 12:10:58 +01:00
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 ) ;
2016-03-21 14:06:57 +01:00
// store version and length from SWF header
own_fwrite ( in_buf + cb + 3 , 1 , 5 , fout ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// store zLib header, but increased by 1 to prevent finding it
// again in the next pass
2016-01-06 12:10:58 +01:00
own_fwrite ( in_buf + cb + 8 , 1 , 1 , fout ) ;
unsigned char incchar = * ( in_buf + cb + 9 ) + 1 ;
fout_fputc ( incchar ) ;
2016-01-26 12:35:25 +01:00
// store penalty bytes, if any
2016-01-06 12:10:58 +01:00
if ( best_penalty_bytes_len ! = 0 ) {
if ( DEBUG_MODE ) {
printf ( " Penalty bytes were used: %i bytes \n " , best_penalty_bytes_len ) ;
}
2016-03-19 09:13:54 +01:00
fout_fput32 ( best_penalty_bytes_len ) ;
2016-01-06 12:10:58 +01:00
for ( int pbc = 0 ; pbc < best_penalty_bytes_len ; pbc + + ) {
fout_fputc ( best_penalty_bytes [ pbc ] ) ;
}
}
2016-03-19 09:13:54 +01:00
fout_fput32 ( best_identical_bytes ) ;
fout_fput32 ( best_identical_bytes_decomp ) ;
2016-01-06 12:10:58 +01:00
if ( r . success ) {
2016-03-19 09:13:54 +01:00
fout_fput64 ( r . file_length ) ;
2016-01-06 12:10:58 +01:00
}
2016-01-26 12:35:25 +01:00
// write decompressed data
2016-01-06 12:10:58 +01:00
if ( r . success ) {
write_decompressed_data ( r . file_length , r . file_name ) ;
remove ( r . file_name ) ;
delete [ ] r . file_name ;
} else {
2017-10-11 06:07:18 +02:00
write_decompressed_data_io_buf ( best_identical_bytes_decomp , in_memory ) ;
2016-01-06 12:10:58 +01:00
}
2016-01-26 12:35:25 +01:00
// start new uncompressed data
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// set input file pointer after recompressed data
2016-01-06 12:10:58 +01:00
input_file_pos + = best_identical_bytes - 1 ;
cb + = best_identical_bytes - 1 ;
} else {
2017-07-29 11:25:58 +02:00
if ( intense_mode_is_active ( ) ) intense_ignore_offsets - > insert ( input_file_pos - 2 ) ;
2017-12-28 22:14:09 +05:30
if ( brute_mode_is_active ( ) ) brute_ignore_offsets - > insert ( input_file_pos ) ;
2016-01-06 12:10:58 +01:00
if ( DEBUG_MODE ) {
printf ( " No matches \n " ) ;
}
}
}
}
void try_decompression_bzip2 ( int compression_level ) {
2016-01-26 12:54:24 +01:00
init_decompression_variables ( ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// try to decompress at current position
2016-06-05 11:49:48 +02:00
int compressed_stream_size = - 1 ;
retval = try_to_decompress_bzip2 ( fin , compression_level , compressed_stream_size ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
if ( retval > 0 ) { // seems to be a zLib-Stream
2016-01-06 12:10:58 +01:00
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 ) ;
2016-06-05 11:49:48 +02:00
printf ( " Compressed size: %i \n " , compressed_stream_size ) ;
2016-01-06 12:10:58 +01:00
ftempout = tryOpen ( tempfile1 , " rb " ) ;
fseek ( ftempout , 0 , SEEK_END ) ;
printf ( " Can be decompressed to %li bytes \n " , ftell ( ftempout ) ) ;
safe_fclose ( & ftempout ) ;
}
2016-06-05 11:49:48 +02:00
try_recompress_bzip2 ( fin , compression_level , compressed_stream_size ) ;
2016-01-06 12:10:58 +01:00
2016-06-05 11:49:48 +02:00
if ( ( best_identical_bytes > min_ident_size ) & & ( best_identical_bytes < best_identical_bytes_decomp ) ) {
2016-01-06 12:10:58 +01:00
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 ;
2016-01-26 12:35:25 +01:00
// end uncompressed data
2016-01-06 12:10:58 +01:00
compressed_data_found = true ;
end_uncompressed_data ( ) ;
2016-01-26 12:35:25 +01:00
// check recursion
2016-01-06 12:10:58 +01:00
recursion_result r = recursion_compress ( best_identical_bytes , best_identical_bytes_decomp ) ;
2016-01-26 12:35:25 +01:00
// write compressed data header (bZip2)
2016-01-06 12:10:58 +01:00
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 ) ;
2016-01-26 12:35:25 +01:00
// store penalty bytes, if any
2016-01-06 12:10:58 +01:00
if ( best_penalty_bytes_len ! = 0 ) {
if ( DEBUG_MODE ) {
printf ( " Penalty bytes were used: %i bytes \n " , best_penalty_bytes_len ) ;
}
2016-03-19 09:13:54 +01:00
fout_fput32 ( best_penalty_bytes_len ) ;
2016-01-06 12:10:58 +01:00
for ( int pbc = 0 ; pbc < best_penalty_bytes_len ; pbc + + ) {
fout_fputc ( best_penalty_bytes [ pbc ] ) ;
}
}
2016-03-19 09:13:54 +01:00
fout_fput32 ( best_identical_bytes ) ;
fout_fput32 ( best_identical_bytes_decomp ) ;
2016-01-06 12:10:58 +01:00
if ( r . success ) {
2016-03-19 09:13:54 +01:00
fout_fput64 ( r . file_length ) ;
2016-01-06 12:10:58 +01:00
}
2016-01-26 12:35:25 +01:00
// write decompressed data
2016-01-06 12:10:58 +01:00
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 ) ;
}
2016-01-26 12:35:25 +01:00
// start new uncompressed data
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// set input file pointer after recompressed data
2016-01-06 12:10:58 +01:00
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
2016-01-26 12:35:25 +01:00
return 65 ; // invalid
2016-01-06 12:10:58 +01:00
}
2016-04-29 09:23:44 +02:00
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 ) {
2016-01-06 12:10:58 +01:00
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 ;
2016-01-26 12:35:25 +01:00
// make sure avail_in mod 3 = 0, pad with 0 bytes
2016-01-06 12:10:58 +01:00
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 + + ;
2016-01-26 12:35:25 +01:00
if ( act_line_len = = base64_line_len [ line_nr ] ) { // end of line, write CRLF
2016-01-06 12:10:58 +01:00
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 + + ;
2016-01-26 12:35:25 +01:00
if ( act_line_len = = base64_line_len [ line_nr ] ) { // end of line, write CRLF
2016-01-06 12:10:58 +01:00
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 + + ;
2016-01-26 12:35:25 +01:00
if ( act_line_len = = base64_line_len [ line_nr ] ) { // end of line, write CRLF
2016-01-06 12:10:58 +01:00
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 + + ;
2016-01-26 12:35:25 +01:00
if ( act_line_len = = base64_line_len [ line_nr ] ) { // end of line, write CRLF
2016-01-06 12:10:58 +01:00
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 ) {
2016-01-26 12:54:24 +01:00
init_decompression_variables ( ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// try to decode at current position
2016-01-06 12:10:58 +01:00
remove ( tempfile1 ) ;
ftempout = tryOpen ( tempfile1 , " wb " ) ;
seek_64 ( fin , input_file_pos ) ;
unsigned char base64_data [ CHUNK > > 2 ] ;
2016-04-29 09:23:44 +02:00
unsigned int * base64_line_len = new unsigned int [ 65536 ] ;
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
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 ;
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
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 + + ) {
2016-01-26 12:35:25 +01:00
// are these valid base64 chars?
2016-01-06 12:10:58 +01:00
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 + + ;
2016-01-26 12:35:25 +01:00
if ( cr_count = = 2 ) { // double CRLF -> base64 end
2016-01-06 12:10:58 +01:00
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 ;
2016-01-26 12:35:25 +01:00
// check line case
2016-01-06 12:10:58 +01:00
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 ) ;
}
2016-01-26 12:35:25 +01:00
// try to re-encode Base64 data
2016-01-06 12:10:58 +01:00
ftempout = fopen ( tempfile1 , " rb " ) ;
if ( ftempout = = NULL ) {
error ( ERR_TEMP_FILE_DISAPPEARED ) ;
}
remove ( tempfile2 ) ;
frecomp = tryOpen ( tempfile2 , " w+b " ) ;
2016-04-29 09:23:44 +02:00
base64_reencode ( ftempout , frecomp , line_count , base64_line_len ) ;
2016-01-06 12:10:58 +01:00
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 ) ;
}
2016-01-26 12:35:25 +01:00
// end uncompressed data
2016-01-06 12:10:58 +01:00
compressed_data_found = true ;
end_uncompressed_data ( ) ;
2016-01-26 12:35:25 +01:00
// check recursion
2016-01-06 12:10:58 +01:00
recursion_result r = recursion_compress ( identical_bytes_decomp , identical_bytes ) ;
2016-01-26 12:35:25 +01:00
// write compressed data header (Base64)
2016-01-06 12:10:58 +01:00
int header_byte = 1 + ( line_case < < 2 ) ;
if ( r . success ) {
header_byte + = 128 ;
}
fout_fputc ( header_byte ) ;
2016-01-26 12:35:25 +01:00
fout_fputc ( 8 ) ; // Base64
2016-01-06 12:10:58 +01:00
2016-03-19 09:13:54 +01:00
fout_fput16 ( base64_header_length ) ;
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// write "header", but change first char to prevent re-detection
2016-01-06 12:10:58 +01:00
fout_fputc ( in_buf [ cb ] - 1 ) ;
own_fwrite ( in_buf + cb + 1 , 1 , base64_header_length - 1 , fout ) ;
2016-03-19 09:13:54 +01:00
fout_fput16 ( line_count ) ;
2016-01-06 12:10:58 +01:00
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 ] ) ;
}
2016-04-29 09:23:44 +02:00
delete [ ] base64_line_len ;
2017-07-17 21:45:14 +05:30
2016-03-19 09:13:54 +01:00
fout_fput32 ( identical_bytes ) ;
fout_fput32 ( identical_bytes_decomp ) ;
2016-01-06 12:10:58 +01:00
if ( r . success ) {
2016-03-19 09:13:54 +01:00
fout_fput64 ( r . file_length ) ;
2016-01-06 12:10:58 +01:00
}
2016-01-26 12:35:25 +01:00
// write decompressed data
2016-01-06 12:10:58 +01:00
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 ) ;
}
2016-01-26 12:35:25 +01:00
// start new uncompressed data
2016-01-06 12:10:58 +01:00
2016-01-26 12:35:25 +01:00
// set input file pointer after recompressed data
2016-01-06 12:10:58 +01:00
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 ( " \n Press any key to continue \n " ) ;
2016-01-26 12:35:25 +01:00
// wait for key
2016-01-06 12:10:58 +01:00
do {
2016-06-19 16:53:50 +08:00
Sleep ( 55 ) ; // lower CPU cost
2016-01-06 12:10:58 +01:00
} while ( ! kbhit ( ) ) ;
}
# endif
void error ( int error_nr ) {
printf ( " \n ERROR %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 " ) ;
2016-01-26 12:35:25 +01:00
// delete output file
2016-01-06 12:10:58 +01:00
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 ;
2017-04-05 16:49:58 +02:00
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 " ) ;
2017-07-17 21:45:14 +05:30
break ;
2016-01-06 12:10:58 +01:00
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 ;
}
2016-01-13 15:55:09 +01:00
# 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
2016-01-06 12:10:58 +01:00
long long fileSize64 ( char * filename ) {
2016-02-13 10:48:56 +01:00
# ifndef UNIX
2016-01-06 12:10:58 +01:00
unsigned long s1 = 0 , s2 = 0 ;
2016-01-13 15:55:09 +01:00
# 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
2016-01-06 12:10:58 +01:00
HANDLE h = CreateFile ( filename , 0 , ( FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE ) , NULL , OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL ) ;
2016-01-13 15:55:09 +01:00
# endif
2016-01-06 12:10:58 +01:00
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 ;
2016-02-13 10:48:56 +01:00
# endif // UNIX
2016-01-06 12:10:58 +01:00
}
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 ;
}
2016-01-26 12:35:25 +01:00
// create meta file
2016-01-06 12:10:58 +01:00
FILE * f = fopen ( metatempfile , " wb " ) ;
safe_fclose ( & f ) ;
2016-01-26 12:35:25 +01:00
// update temporary file list
2016-01-06 12:10:58 +01:00
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 ) ;
2016-01-26 12:35:25 +01:00
// recursion input file
2016-01-06 12:10:58 +01:00
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 ) ) ;
2017-06-16 07:31:37 +02:00
recursion_stack_push ( & uncompressed_bytes_total , sizeof ( uncompressed_bytes_total ) ) ;
recursion_stack_push ( & uncompressed_bytes_written , sizeof ( uncompressed_bytes_written ) ) ;
2016-01-06 12:10:58 +01:00
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 ) ) ;
2016-01-21 15:39:31 +01:00
recursion_stack_push ( & fmp3 , sizeof ( fmp3 ) ) ;
2016-01-06 12:10:58 +01:00
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 ) ) ;
2016-04-02 12:25:40 +02:00
recursion_stack_push ( & suppress_mp3_type_until [ 0 ] , sizeof ( suppress_mp3_type_until [ 0 ] ) * 16 ) ;
2016-05-06 11:31:47 +02:00
recursion_stack_push ( & suppress_mp3_big_value_pairs_sum , sizeof ( suppress_mp3_big_value_pairs_sum ) ) ;
2016-05-06 12:12:36 +02:00
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 ) ) ;
2017-07-28 10:37:08 +02:00
recursion_stack_push ( & intense_ignore_offsets , sizeof ( intense_ignore_offsets ) ) ;
recursion_stack_push ( & brute_ignore_offsets , sizeof ( brute_ignore_offsets ) ) ;
2017-08-29 17:23:15 +02:00
recursion_stack_push ( & decomp_io_buf , sizeof ( decomp_io_buf ) ) ;
2017-07-17 21:45:14 +05:30
2016-01-06 12:10:58 +01:00
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 ) ) ;
2017-08-29 17:23:15 +02:00
recursion_stack_pop ( & decomp_io_buf , sizeof ( decomp_io_buf ) ) ;
2017-07-28 10:37:08 +02:00
recursion_stack_pop ( & brute_ignore_offsets , sizeof ( brute_ignore_offsets ) ) ;
recursion_stack_pop ( & intense_ignore_offsets , sizeof ( intense_ignore_offsets ) ) ;
2016-05-06 12:12:36 +02:00
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 ) ) ;
2016-05-06 11:31:47 +02:00
recursion_stack_pop ( & suppress_mp3_big_value_pairs_sum , sizeof ( suppress_mp3_big_value_pairs_sum ) ) ;
2016-04-02 12:25:40 +02:00
recursion_stack_pop ( & suppress_mp3_type_until [ 0 ] , sizeof ( suppress_mp3_type_until [ 0 ] ) * 16 ) ;
2016-01-06 12:10:58 +01:00
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 ) ;
2016-01-21 15:39:31 +01:00
recursion_stack_pop ( & fmp3 , sizeof ( fmp3 ) ) ;
2016-01-06 12:10:58 +01:00
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 ) ) ;
2017-06-16 07:31:37 +02:00
recursion_stack_pop ( & uncompressed_bytes_written , sizeof ( uncompressed_bytes_written ) ) ;
recursion_stack_pop ( & uncompressed_bytes_total , sizeof ( uncompressed_bytes_total ) ) ;
2016-01-06 12:10:58 +01:00
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 ) ) ;
}
2017-08-29 17:23:15 +02:00
void write_ftempout_if_not_present ( int byte_count , bool in_memory , bool leave_open ) {
if ( in_memory ) {
2017-08-30 17:18:20 +02:00
ftempout = tryOpen ( tempfile1 , " wb " ) ;
2017-08-29 17:23:15 +02:00
fast_copy ( decomp_io_buf , ftempout , byte_count ) ;
if ( ! leave_open ) safe_fclose ( & ftempout ) ;
}
}
2016-01-06 12:10:58 +01:00
recursion_result recursion_compress ( int compressed_bytes , int decompressed_bytes ) {
FILE * recursion_fout ;
recursion_result tmp_r ;
tmp_r . success = false ;
2017-06-16 07:31:37 +02:00
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 ;
2016-01-06 12:10:58 +01:00
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 ( ) ;
2016-01-26 12:35:25 +01:00
// shorten tempfile1 to decompressed_bytes
2016-01-06 12:10:58 +01:00
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 ] ;
2017-12-28 22:14:09 +05:30
2017-07-28 10:37:08 +02:00
intense_ignore_offsets = new set < long long > ( ) ;
2017-12-28 22:14:09 +05:30
brute_ignore_offsets = new set < long long > ( ) ;
2016-01-06 12:10:58 +01:00
2016-05-06 11:31:47 +02:00
// init MP3 suppression
2016-04-02 12:25:40 +02:00
for ( int i = 0 ; i < 16 ; i + + ) {
suppress_mp3_type_until [ i ] = - 1 ;
}
2016-05-06 11:31:47 +02:00
suppress_mp3_big_value_pairs_sum = - 1 ;
2016-05-06 12:12:36 +02:00
mp3_parsing_cache_second_frame = - 1 ;
2016-04-02 12:25:40 +02:00
2016-01-26 12:35:25 +01:00
// disable compression-on-the-fly in recursion - we don't want compressed compressed streams
2016-07-02 18:37:31 +02:00
compression_otf_method = OTF_NONE ;
2016-01-06 12:10:58 +01:00
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 ) ;
2017-07-17 21:45:14 +05:30
if ( anything_was_used )
2016-01-06 12:10:58 +01:00
rescue_anything_was_used = true ;
2017-07-17 21:45:14 +05:30
if ( non_zlib_was_used )
2016-01-06 12:10:58 +01:00
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 ) ;
2016-01-26 12:35:25 +01:00
// get recursion file size
2016-01-06 12:10:58 +01:00
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 ] ;
2016-01-26 12:35:25 +01:00
// disable compression-on-the-fly in recursion - we don't want compressed compressed streams
2016-07-02 18:37:31 +02:00
compression_otf_method = OTF_NONE ;
2016-01-06 12:10:58 +01:00
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 ) ;
}
2016-01-26 12:35:25 +01:00
// get recursion file size
2016-01-06 12:10:58 +01:00
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 ) {
2016-07-02 18:37:31 +02:00
use_otf = ( conversion_to_method > OTF_NONE ) ;
2016-01-06 12:10:58 +01:00
if ( use_otf ) compression_otf_method = conversion_to_method ;
} else {
2016-07-02 18:37:31 +02:00
if ( ( f ! = fout ) | | ( compression_otf_method = = OTF_NONE ) ) {
2016-01-06 12:10:58 +01:00
use_otf = false ;
} else {
use_otf = true ;
}
}
if ( ! use_otf ) {
fputc ( c , f ) ;
} else {
fout_fputc ( c ) ;
}
}
void fout_fputc ( char c ) {
2016-07-02 18:37:31 +02:00
if ( compression_otf_method = = OTF_NONE ) { // uncompressed
2016-07-02 18:24:23 +02:00
fputc ( c , fout ) ;
} else {
unsigned char temp_buf [ 1 ] ;
temp_buf [ 0 ] = c ;
own_fwrite ( temp_buf , 1 , 1 , fout ) ;
2016-01-06 12:10:58 +01:00
}
}
2016-02-14 11:46:09 +01:00
void fout_fput16 ( int v ) {
fout_fputc ( ( v > > 8 ) % 256 ) ;
2016-03-19 09:13:54 +01:00
fout_fputc ( v % 256 ) ;
2016-02-14 11:46:09 +01:00
}
void fout_fput24 ( int v ) {
fout_fputc ( ( v > > 16 ) % 256 ) ;
fout_fputc ( ( v > > 8 ) % 256 ) ;
2016-03-19 09:13:54 +01:00
fout_fputc ( v % 256 ) ;
2016-02-14 11:46:09 +01:00
}
void fout_fput32_little_endian ( int v ) {
2016-03-19 09:13:54 +01:00
fout_fputc ( v % 256 ) ;
2016-02-14 11:46:09 +01:00
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 ) ;
2016-03-19 09:13:54 +01:00
fout_fputc ( v % 256 ) ;
2016-02-14 11:46:09 +01:00
}
void fout_fput32 ( unsigned int v ) {
fout_fputc ( ( v > > 24 ) % 256 ) ;
fout_fputc ( ( v > > 16 ) % 256 ) ;
fout_fputc ( ( v > > 8 ) % 256 ) ;
2016-03-19 09:13:54 +01:00
fout_fputc ( v % 256 ) ;
2016-02-14 11:46:09 +01:00
}
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 ) ;
2016-03-19 09:13:54 +01:00
fout_fputc ( v % 256 ) ;
2016-02-14 11:46:09 +01:00
}
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 ) ;
2016-03-19 09:13:54 +01:00
fout_fputc ( v % 256 ) ;
2016-02-14 11:46:09 +01:00
}
2016-01-06 12:10:58 +01:00
unsigned char fin_fgetc ( ) {
if ( comp_decomp_state = = P_CONVERT ) compression_otf_method = conversion_from_method ;
2016-07-02 18:37:31 +02:00
if ( compression_otf_method = = OTF_NONE ) {
2016-07-02 18:24:23 +02:00
return fgetc ( fin ) ;
} else {
unsigned char temp_buf [ 1 ] ;
own_fread ( temp_buf , 1 , 1 , fin ) ;
return temp_buf [ 0 ] ;
2016-01-06 12:10:58 +01:00
}
}
void init_compress_otf ( ) {
if ( comp_decomp_state = = P_CONVERT ) compression_otf_method = conversion_to_method ;
switch ( compression_otf_method ) {
2016-07-02 18:37:31 +02:00
case OTF_BZIP2 : { // bZip2
2016-01-06 12:10:58 +01:00
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 ;
}
2016-07-02 18:37:31 +02:00
case OTF_XZ_MT : {
2016-12-28 11:14:41 +01:00
uint64_t memory_usage = 0 ;
2017-12-26 10:16:33 +01:00
uint64_t block_size = 0 ;
2017-04-05 16:49:58 +02:00
uint64_t max_memory = compression_otf_max_memory * 1024 * 1024LL ;
int threads = compression_otf_thread_count ;
2017-07-17 21:45:14 +05:30
2017-04-05 15:30:02 +02:00
if ( max_memory = = 0 ) {
2017-04-05 16:49:58 +02:00
max_memory = lzma_max_memory_default ( ) * 1024 * 1024LL ;
2017-04-05 15:30:02 +02:00
}
if ( threads = = 0 ) {
2017-04-05 16:49:58 +02:00
threads = auto_detected_thread_count ( ) ;
2017-04-05 15:30:02 +02:00
}
2017-07-17 21:45:14 +05:30
2017-04-05 13:44:45 +02:00
if ( ! init_encoder_mt ( & otf_xz_stream_c , threads , max_memory , memory_usage , block_size ) ) {
2016-06-19 16:53:50 +08:00
printf ( " ERROR: xz Multi-Threaded init failed \n " ) ;
exit ( 1 ) ;
}
2017-07-17 21:45:14 +05:30
2017-04-05 16:49:58 +02:00
string plural = " " ;
if ( threads > 1 ) {
plural = " s " ;
}
printf ( " Compressing with LZMA, %i thread%s, memory usage: " , threads , plural . c_str ( ) ) ;
2016-12-29 18:34:34 +01:00
print64 ( memory_usage / ( 1024 * 1024 ) ) ;
2017-04-05 13:44:45 +02:00
printf ( " MiB, block size: " ) ;
2017-12-26 10:16:33 +01:00
print64 ( block_size / ( 1024 * 1024 ) ) ;
printf ( " MiB \n \n " ) ;
2016-06-19 16:53:50 +08:00
break ;
}
2016-01-06 12:10:58 +01:00
}
}
2017-04-05 16:49:58 +02:00
int auto_detected_thread_count ( ) {
int threads = std : : thread : : hardware_concurrency ( ) ;
if ( threads = = 0 ) threads = 2 ;
2017-07-17 21:45:14 +05:30
2017-04-05 16:49:58 +02:00
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 ;
}
2016-01-06 12:10:58 +01:00
void denit_compress_otf ( ) {
if ( comp_decomp_state = = P_CONVERT ) compression_otf_method = conversion_to_method ;
2016-07-02 18:37:31 +02:00
if ( compression_otf_method > OTF_NONE ) {
2016-01-06 12:10:58 +01:00
2016-07-02 18:24:23 +02:00
// uncompressed data of length 0 ends compress-on-the-fly data
2016-01-06 12:10:58 +01:00
char final_buf [ 9 ] ;
for ( int i = 0 ; i < 9 ; i + + ) {
final_buf [ i ] = 0 ;
}
2017-06-16 07:31:37 +02:00
own_fwrite ( final_buf , 1 , 9 , fout , true , true ) ;
2016-06-19 16:53:50 +08:00
}
switch ( compression_otf_method ) {
2016-07-02 18:37:31 +02:00
case OTF_BZIP2 : { // bZip2
2016-01-06 12:10:58 +01:00
( void ) BZ2_bzCompressEnd ( & otf_bz2_stream_c ) ;
break ;
}
2016-07-02 18:37:31 +02:00
case OTF_XZ_MT : {
2016-06-19 16:53:50 +08:00
( void ) lzma_end ( & otf_xz_stream_c ) ;
break ;
}
2016-01-06 12:10:58 +01:00
}
}
void init_decompress_otf ( ) {
if ( comp_decomp_state = = P_CONVERT ) compression_otf_method = conversion_from_method ;
switch ( compression_otf_method ) {
2016-07-02 18:37:31 +02:00
case OTF_BZIP2 : {
2016-01-06 12:10:58 +01:00
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 ;
}
2016-07-02 18:37:31 +02:00
case OTF_XZ_MT : {
2016-06-19 16:53:50 +08:00
if ( ! init_decoder ( & otf_xz_stream_d ) ) {
printf ( " ERROR: liblzma init failed \n " ) ;
exit ( 1 ) ;
}
}
2016-01-06 12:10:58 +01:00
}
decompress_otf_end = false ;
}
void denit_decompress_otf ( ) {
if ( comp_decomp_state = = P_CONVERT ) compression_otf_method = conversion_from_method ;
switch ( compression_otf_method ) {
2016-07-02 18:37:31 +02:00
case OTF_BZIP2 : { // bZip2
2016-01-06 12:10:58 +01:00
( void ) BZ2_bzDecompressEnd ( & otf_bz2_stream_d ) ;
break ;
}
2016-12-29 18:31:47 +01:00
case OTF_XZ_MT : { // lzma2 multithreaded
2016-06-19 16:53:50 +08:00
( void ) lzma_end ( & otf_xz_stream_d ) ;
break ;
}
2016-01-06 12:10:58 +01:00
}
}
2016-01-26 12:35:25 +01:00
// get current time in ms
2016-01-06 12:10:58 +01:00
long long get_time_ms ( ) {
2016-02-13 10:48:56 +01:00
# ifndef UNIX
2016-01-06 12:10:58 +01:00
return GetTickCount ( ) ;
# else
timeval t ;
gettimeofday ( & t , NULL ) ;
return ( t . tv_sec * 1000 ) + ( t . tv_usec / 1000 ) ;
# endif
}
2016-01-26 12:35:25 +01:00
// nice time output, input t in ms
2016-01-06 12:10:58 +01:00
// 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 ( ) {
2016-02-13 10:48:56 +01:00
# ifndef UNIX
2016-01-06 12:10:58 +01:00
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 ) {
2017-06-16 07:31:37 +02:00
if ( ( get_time_ms ( ) - work_sign_start_time ) > = 250 ) {
2016-01-06 12:10:58 +01:00
work_sign_var = ( work_sign_var + 1 ) % 4 ;
work_sign_start_time = get_time_ms ( ) ;
2017-06-16 07:31:37 +02:00
if ( with_backspace ) printf ( " \b \b \b \b \b \b " ) ;
printf ( " %c " , work_signs [ work_sign_var ] ) ;
2016-01-06 12:10:58 +01:00
fflush ( stdout ) ;
} else if ( ! with_backspace ) {
2017-06-16 07:31:37 +02:00
printf ( " %c " , work_signs [ work_sign_var ] ) ;
2016-01-06 12:10:58 +01:00
fflush ( stdout ) ;
}
}
}
void print_debug_percent ( ) {
printf ( " (%.2f%%) " , ( input_file_pos / ( float ) fin_length ) * ( global_max_percent - global_min_percent ) + global_min_percent ) ;
}
2017-06-16 07:31:37 +02:00
void show_progress ( float percent , bool use_backspaces , bool check_time ) {
if ( ! check_time | | ( ( get_time_ms ( ) - sec_time ) > = 250 ) ) {
2017-06-11 11:47:05 +02:00
if ( use_backspaces ) {
2017-06-16 07:31:37 +02:00
printf ( string ( 6 , ' \b ' ) . c_str ( ) ) ; // backspace to remove work sign and 5 extra spaces
2017-06-11 11:47:05 +02:00
}
2017-06-16 07:31:37 +02:00
bool new_lzma_text = false ;
2017-06-27 07:16:05 +02:00
if ( ( show_lzma_progress ) & & ( ( comp_decomp_state = = P_COMPRESS ) | | ( ( comp_decomp_state = = P_CONVERT ) & & ( conversion_to_method = = OTF_XZ_MT ) ) ) ) {
2017-06-16 07:31:37 +02:00
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 ;
}
}
2017-07-17 21:45:14 +05:30
2017-06-11 11:47:05 +02:00
if ( use_backspaces ) {
2017-06-16 07:31:37 +02:00
printf ( " %s " , string ( 8 , ' \b ' ) . c_str ( ) ) ; // backspaces to remove output from %6.2f%
2017-06-11 11:47:05 +02:00
}
printf ( " %6.2f%% " , percent ) ;
2017-06-16 07:31:37 +02:00
if ( new_lzma_text ) {
printf ( " %s " , lzma_progress_text ) ;
}
2017-06-11 11:47:05 +02:00
print_work_sign ( false ) ;
sec_time = get_time_ms ( ) ;
}
}
2016-01-06 12:10:58 +01:00
void ctrl_c_handler ( int sig ) {
printf ( " \n \n CTRL-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 ) ;
2017-07-17 21:45:14 +05:30
}