1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
|
/* Lzcheck - A test program for the lzlib library
Copyright (C) 2009, 2010, 2011, 2012 Antonio Diaz Diaz.
This program is free software: you have unlimited permission
to copy, distribute and modify it.
Usage is:
lzcheck filename.txt
This program reads the specified text file and then compresses it,
line by line, to test the flushing mechanism and the member
restart/reset/sync functions.
*/
#define _FILE_OFFSET_BITS 64
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "lzlib.h"
#ifndef LLONG_MAX
#define LLONG_MAX 0x7FFFFFFFFFFFFFFFLL
#endif
#ifndef LLONG_MIN
#define LLONG_MIN (-LLONG_MAX - 1LL)
#endif
#ifndef ULLONG_MAX
#define ULLONG_MAX 0xFFFFFFFFFFFFFFFFULL
#endif
#ifndef min
#define min(x,y) ((x) <= (y) ? (x) : (y))
#endif
enum { buffer_size = 32768 };
uint8_t in_buffer[buffer_size];
uint8_t mid_buffer[buffer_size];
uint8_t out_buffer[buffer_size];
int main( const int argc, const char * const argv[] )
{
if( argc < 2 )
{
fprintf( stderr, "Usage: lzcheck filename.txt\n" );
return 1;
}
FILE *file = fopen( argv[1], "rb" );
if( !file )
{
fprintf( stderr, "lzcheck: Can't open file '%s' for reading\n", argv[1] );
return 1;
}
/* fprintf( stderr, "lzcheck: Testing file '%s'\n", argv[1] ); */
const int dictionary_size = 1 << 20;
const int match_len_limit = 36;
const long long member_size = LLONG_MAX;
struct LZ_Encoder * const encoder =
LZ_compress_open( dictionary_size, match_len_limit, member_size );
if( !encoder || LZ_compress_errno( encoder ) != LZ_ok )
{
const bool mem_error = ( LZ_compress_errno( encoder ) == LZ_mem_error );
LZ_compress_close( encoder );
if( mem_error )
{
fprintf( stderr, "lzcheck: Not enough memory.\n" );
return 1;
}
fprintf( stderr, "lzcheck: internal error: Invalid argument to encoder.\n" );
return 3;
}
struct LZ_Decoder * const decoder = LZ_decompress_open();
if( !decoder || LZ_decompress_errno( decoder ) != LZ_ok )
{
LZ_decompress_close( decoder );
fprintf( stderr, "lzcheck: Not enough memory.\n" );
return 1;
}
int retval = 0;
while( retval <= 1 )
{
int i, l, r;
const int read_size = fread( in_buffer, 1, buffer_size, file );
if( read_size <= 0 ) break; /* end of file */
for( l = 0, r = 1; r <= read_size; l = r, ++r )
{
while( r < read_size && in_buffer[r-1] != '\n' ) ++r;
const int in_size = LZ_compress_write( encoder, in_buffer + l, r - l );
if( in_size < r - l ) r = l + in_size;
LZ_compress_sync_flush( encoder );
const int mid_size = LZ_compress_read( encoder, mid_buffer, buffer_size );
if( mid_size < 0 )
{
fprintf( stderr, "lzcheck: LZ_compress_read error: %s.\n",
LZ_strerror( LZ_compress_errno( encoder ) ) );
retval = 3; break;
}
LZ_decompress_write( decoder, mid_buffer, mid_size );
const int out_size = LZ_decompress_read( decoder, out_buffer, buffer_size );
if( out_size < 0 )
{
fprintf( stderr, "lzcheck: LZ_decompress_read error: %s.\n",
LZ_strerror( LZ_decompress_errno( decoder ) ) );
retval = 3; break;
}
if( out_size != in_size || memcmp( in_buffer + l, out_buffer, out_size ) )
{
fprintf( stderr, "lzcheck: Sync error at pos %d. in_size = %d, out_size = %d\n",
l, in_size, out_size );
for( i = 0; i < in_size; ++i )
fputc( in_buffer[l+i], stderr );
if( in_buffer[l+in_size-1] != '\n' )
fputc( '\n', stderr );
for( i = 0; i < out_size; ++i )
fputc( out_buffer[i], stderr );
fputc( '\n', stderr );
retval = 1;
}
}
}
if( retval <= 1 )
{
rewind( file );
if( LZ_compress_finish( encoder ) < 0 ||
LZ_decompress_write( decoder, mid_buffer, LZ_compress_read( encoder, mid_buffer, buffer_size ) ) < 0 ||
LZ_decompress_read( decoder, out_buffer, buffer_size ) != 0 ||
LZ_compress_restart_member( encoder, member_size ) < 0 )
{
fprintf( stderr, "lzcheck: Can't finish member: %s.\n",
LZ_strerror( LZ_decompress_errno( decoder ) ) );
retval = 3;
}
}
while( retval <= 1 )
{
int i, l, r;
const int read_size = fread( in_buffer, 1, buffer_size / 2, file );
if( read_size <= 0 ) break; /* end of file */
for( l = 0, r = 1; r <= read_size; l = r, ++r )
{
while( r < read_size && in_buffer[r-1] != '\n' ) ++r;
const int leading_garbage = (l == 0) ? min( r, read_size / 2 ) : 0;
const int in_size = LZ_compress_write( encoder, in_buffer + l, r - l );
if( in_size < r - l ) r = l + in_size;
LZ_compress_sync_flush( encoder );
if( leading_garbage )
memset( mid_buffer, in_buffer[0], leading_garbage );
const int mid_size = LZ_compress_read( encoder,
mid_buffer + leading_garbage,
buffer_size - leading_garbage );
if( mid_size < 0 )
{
fprintf( stderr, "lzcheck: LZ_compress_read error: %s.\n",
LZ_strerror( LZ_compress_errno( encoder ) ) );
retval = 3; break;
}
LZ_decompress_write( decoder, mid_buffer, mid_size + leading_garbage );
int out_size = LZ_decompress_read( decoder, out_buffer, buffer_size );
if( out_size < 0 )
{
if( LZ_decompress_errno( decoder ) == LZ_header_error ||
LZ_decompress_errno( decoder ) == LZ_data_error )
{
LZ_decompress_sync_to_member( decoder ); /* remove leading garbage */
out_size = LZ_decompress_read( decoder, out_buffer, buffer_size );
}
if( out_size < 0 )
{
fprintf( stderr, "lzcheck: LZ_decompress_read error: %s.\n",
LZ_strerror( LZ_decompress_errno( decoder ) ) );
retval = 3; break;
}
}
if( out_size != in_size || memcmp( in_buffer + l, out_buffer, out_size ) )
{
fprintf( stderr, "lzcheck: Sync error at pos %d. in_size = %d, out_size = %d\n",
l, in_size, out_size );
for( i = 0; i < in_size; ++i )
fputc( in_buffer[l+i], stderr );
if( in_buffer[l+in_size-1] != '\n' )
fputc( '\n', stderr );
for( i = 0; i < out_size; ++i )
fputc( out_buffer[i], stderr );
fputc( '\n', stderr );
retval = 1;
}
}
if( retval >= 3 ) break;
if( LZ_compress_finish( encoder ) < 0 ||
LZ_decompress_write( decoder, mid_buffer, LZ_compress_read( encoder, mid_buffer, buffer_size ) ) < 0 ||
LZ_decompress_read( decoder, out_buffer, buffer_size ) != 0 ||
LZ_decompress_reset( decoder ) < 0 ||
LZ_compress_restart_member( encoder, member_size ) < 0 )
{
fprintf( stderr, "lzcheck: Can't restart member: %s.\n",
LZ_strerror( LZ_decompress_errno( decoder ) ) );
retval = 3; break;
}
const int size = min( 100, read_size );
if( LZ_compress_write( encoder, in_buffer, size ) != size ||
LZ_compress_finish( encoder ) < 0 ||
LZ_decompress_write( decoder, mid_buffer, LZ_compress_read( encoder, mid_buffer, buffer_size ) ) < 0 ||
LZ_decompress_read( decoder, out_buffer, 0 ) != 0 ||
LZ_decompress_sync_to_member( decoder ) < 0 ||
LZ_compress_restart_member( encoder, member_size ) < 0 )
{
fprintf( stderr, "lzcheck: Can't seek to next member: %s.\n",
LZ_strerror( LZ_decompress_errno( decoder ) ) );
retval = 3; break;
}
}
LZ_decompress_close( decoder );
LZ_compress_close( encoder );
fclose( file );
return retval;
}
|