~ubuntu-branches/ubuntu/vivid/emscripten/vivid

« back to all changes in this revision

Viewing changes to third_party/lzma.js/lzip/main.cc

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2013-05-02 13:11:51 UTC
  • Revision ID: package-import@ubuntu.com-20130502131151-q8dvteqr1ef2x7xz
Tags: upstream-1.4.1~20130504~adb56cb
ImportĀ upstreamĀ versionĀ 1.4.1~20130504~adb56cb

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*  Lzip - Data compressor based on the LZMA algorithm
 
2
    Copyright (C) 2008, 2009, 2010, 2011 Antonio Diaz Diaz.
 
3
 
 
4
    This program is free software: you can redistribute it and/or modify
 
5
    it under the terms of the GNU General Public License as published by
 
6
    the Free Software Foundation, either version 3 of the License, or
 
7
    (at your option) any later version.
 
8
 
 
9
    This program is distributed in the hope that it will be useful,
 
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
    GNU General Public License for more details.
 
13
 
 
14
    You should have received a copy of the GNU General Public License
 
15
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
16
*/
 
17
/*
 
18
    Return values: 0 for a normal exit, 1 for environmental problems
 
19
    (file not found, invalid flags, I/O errors, etc), 2 to indicate a
 
20
    corrupt or invalid input file, 3 for an internal consistency error
 
21
    (eg, bug) which caused lzip to panic.
 
22
*/
 
23
 
 
24
#define _FILE_OFFSET_BITS 64
 
25
 
 
26
#include <errno.h>
 
27
#include <limits.h>
 
28
#include <stdio.h>
 
29
#include <stdlib.h>
 
30
#include <string.h>
 
31
#include <fcntl.h>
 
32
#include <stdint.h>
 
33
#include <unistd.h>
 
34
#include <utime.h>
 
35
#include <sys/stat.h>
 
36
#if defined(__MSVCRT__)
 
37
#include <io.h>
 
38
#define fchmod(x,y) 0
 
39
#define fchown(x,y,z) 0
 
40
#define SIGHUP SIGTERM
 
41
#define S_ISSOCK(x) 0
 
42
#define S_IRGRP 0
 
43
#define S_IWGRP 0
 
44
#define S_IROTH 0
 
45
#define S_IWOTH 0
 
46
#endif
 
47
#if defined(__OS2__)
 
48
#include <io.h>
 
49
#endif
 
50
 
 
51
#include "lzip.h"
 
52
#include "decoder.h"
 
53
 
 
54
#if !DECODER_ONLY
 
55
#include "encoder.h"
 
56
#include "fast_encoder.h"
 
57
#endif
 
58
 
 
59
#if CHAR_BIT != 8
 
60
#error "Environments where CHAR_BIT != 8 are not supported."
 
61
#endif
 
62
 
 
63
#ifndef LLONG_MAX
 
64
#define LLONG_MAX  0x7FFFFFFFFFFFFFFFLL
 
65
#endif
 
66
#ifndef LLONG_MIN
 
67
#define LLONG_MIN  (-LLONG_MAX - 1LL)
 
68
#endif
 
69
#ifndef ULLONG_MAX
 
70
#define ULLONG_MAX 0xFFFFFFFFFFFFFFFFULL
 
71
#endif
 
72
 
 
73
 
 
74
void pp(const char *p) { if (p) fputs(p, stderr); }
 
75
 
 
76
namespace {
 
77
 
 
78
const char * const Program_name = "Lzip";
 
79
const char * const program_name = "lzip";
 
80
const char * const program_year = "2011";
 
81
const char * invocation_name = 0;
 
82
 
 
83
#ifdef O_BINARY
 
84
const int o_binary = O_BINARY;
 
85
#else
 
86
const int o_binary = 0;
 
87
#endif
 
88
 
 
89
struct { const char * from; const char * to; } const known_extensions[] = {
 
90
{ ".lz",  ""   },
 
91
{ ".tlz", ".tar" },
 
92
{ 0,      0    } };
 
93
 
 
94
struct Lzma_options
 
95
{
 
96
  int dictionary_size;          // 4KiB..512MiB
 
97
  int match_len_limit;          // 5..273
 
98
};
 
99
 
 
100
enum Mode { m_compress, m_decompress, m_test };
 
101
 
 
102
int outfd = -1;
 
103
int verbosity = 0;
 
104
bool delete_output_on_interrupt = false;
 
105
 
 
106
 
 
107
void show_help()
 
108
{
 
109
  printf( "%s - Data compressor based on the LZMA algorithm.\n", Program_name );
 
110
  printf( "<< Most of these are unsupported. Compressing/decompressing from stdin to stdout is the right way! >>\n" );
 
111
  printf( "\nUsage: %s [options] [files]\n", invocation_name );
 
112
  printf( "\nOptions:\n" );
 
113
  printf( "  -h, --help                 display this help and exit\n" );
 
114
  printf( "  -V, --version              output version information and exit\n" );
 
115
  printf( "  -b, --member-size=<n>      set member size limit in bytes\n" );
 
116
  printf( "  -c, --stdout               send output to standard output\n" );
 
117
  printf( "  -d, --decompress           decompress\n" );
 
118
  printf( "  -f, --force                overwrite existing output files\n" );
 
119
  printf( "  -F, --recompress           force recompression of compressed files\n" );
 
120
  printf( "  -k, --keep                 keep (don't delete) input files\n" );
 
121
  printf( "  -m, --match-length=<n>     set match length limit in bytes [36]\n" );
 
122
  printf( "  -o, --output=<file>        if reading stdin, place the output into <file>\n" );
 
123
  printf( "  -q, --quiet                suppress all messages\n" );
 
124
  printf( "  -s, --dictionary-size=<n>  set dictionary size limit in bytes [8MiB]\n" );
 
125
  printf( "  -S, --volume-size=<n>      set volume size limit in bytes\n" );
 
126
  printf( "  -t, --test                 test compressed file integrity\n" );
 
127
  printf( "  -v, --verbose              be verbose (a 2nd -v gives more)\n" );
 
128
  printf( "  -0 .. -9                   set compression level [default 6]\n" );
 
129
  printf( "      --fast                 alias for -0\n" );
 
130
  printf( "      --best                 alias for -9\n" );
 
131
  printf( "If no file names are given, %s compresses or decompresses\n", program_name );
 
132
  printf( "from standard input to standard output.\n" );
 
133
  printf( "Numbers may be followed by a multiplier: k = kB = 10^3 = 1000,\n" );
 
134
  printf( "Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n" );
 
135
  printf( "\nReport bugs to lzip-bug@nongnu.org\n" );
 
136
  printf( "Lzip home page: http://www.nongnu.org/lzip/lzip.html\n" );
 
137
}
 
138
 
 
139
 
 
140
void show_version()
 
141
{
 
142
  printf( "%s %s\n", Program_name, PROGVERSION );
 
143
  printf( "Copyright (C) %s Antonio Diaz Diaz.\n", program_year );
 
144
  printf( "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n" );
 
145
  printf( "This is free software: you are free to change and redistribute it.\n" );
 
146
  printf( "There is NO WARRANTY, to the extent permitted by law.\n" );
 
147
}
 
148
 
 
149
 
 
150
const char * format_num( long long num )
 
151
{
 
152
  const char * const prefix[8] =
 
153
  { "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" };
 
154
  enum { buf_size = 16, factor = 1024 };
 
155
  static char buf[buf_size];
 
156
  const char *p = "";
 
157
 
 
158
  for( int i = 0; i < 8 && ( llabs( num ) > 9999 ||
 
159
       ( llabs( num ) >= factor && num % factor == 0 ) ); ++i )
 
160
  { num /= factor; p = prefix[i]; }
 
161
  snprintf( buf, buf_size, "%lld %s", num, p );
 
162
  return buf;
 
163
}
 
164
 
 
165
 
 
166
bool open_outstream( const bool force )
 
167
 
168
  return false;
 
169
}
 
170
 
 
171
 
 
172
bool check_tty( const int infd, const Mode program_mode )
 
173
{
 
174
  if( program_mode == m_compress && outfd >= 0 && isatty( outfd ) )
 
175
  {
 
176
    show_error( "I won't write compressed data to a terminal.", 0, true );
 
177
    return false;
 
178
  }
 
179
  if( ( program_mode == m_decompress || program_mode == m_test ) &&
 
180
      isatty( infd ) )
 
181
  {
 
182
    show_error( "I won't read compressed data from a terminal.", 0, true );
 
183
    return false;
 
184
  }
 
185
  return true;
 
186
}
 
187
 
 
188
 
 
189
void cleanup_and_fail( const int retval )
 
190
{
 
191
  exit( retval );
 
192
}
 
193
 
 
194
 
 
195
     // Set permissions, owner and times.
 
196
void close_and_set_permissions( const struct stat * const in_statsp )
 
197
{
 
198
  bool error = false;
 
199
  if( in_statsp )
 
200
  {
 
201
    if( ( fchown( outfd, in_statsp->st_uid, in_statsp->st_gid ) != 0 &&
 
202
          errno != EPERM ) ||
 
203
        fchmod( outfd, in_statsp->st_mode ) != 0 )
 
204
      error = true;
 
205
    // fchown will in many cases return with EPERM, which can be safely ignored.
 
206
  }
 
207
  if( close( outfd ) == 0 ) outfd = -1;
 
208
  else cleanup_and_fail( 1 );
 
209
  delete_output_on_interrupt = false;
 
210
  if( !in_statsp ) return;
 
211
  if( !error )
 
212
  {
 
213
    struct utimbuf t;
 
214
    t.actime = in_statsp->st_atime;
 
215
    t.modtime = in_statsp->st_mtime;
 
216
    //if( utime( output_filename.c_str(), &t ) != 0 ) error = true;
 
217
  }
 
218
  if( error )
 
219
  {
 
220
    show_error( "Can't change output file attributes." );
 
221
    cleanup_and_fail( 1 );
 
222
  }
 
223
}
 
224
 
 
225
 
 
226
bool next_filename()
 
227
{
 
228
  return false;
 
229
}
 
230
 
 
231
#if !DECODER_ONLY
 
232
int compress( const long long member_size, const long long volume_size,
 
233
              const Lzma_options & encoder_options, const int infd,
 
234
              const struct stat * const in_statsp )
 
235
{
 
236
  File_header header;
 
237
  header.set_magic();
 
238
  if( !header.dictionary_size( encoder_options.dictionary_size ) ||
 
239
      encoder_options.match_len_limit < min_match_len_limit ||
 
240
      encoder_options.match_len_limit > max_match_len )
 
241
    internal_error( "invalid argument to encoder" );
 
242
  int retval = 0;
 
243
 
 
244
    Matchfinder matchfinder( header.dictionary_size(),
 
245
                             encoder_options.match_len_limit, infd );
 
246
    header.dictionary_size( matchfinder.dictionary_size() );
 
247
 
 
248
    long long in_size = 0, out_size = 0, partial_volume_size = 0;
 
249
    while( true )               // encode one member per iteration
 
250
    {
 
251
      LZ_encoder encoder( matchfinder, header, outfd );
 
252
      const long long size =
 
253
        min( member_size, volume_size - partial_volume_size );
 
254
      if( !encoder.encode_member( size ) )
 
255
      { pp( "Encoder error" ); retval = 1; break; }
 
256
      in_size += matchfinder.data_position();
 
257
      out_size += encoder.member_position();
 
258
      if( matchfinder.finished() ) break;
 
259
      partial_volume_size += encoder.member_position();
 
260
      if( partial_volume_size >= volume_size - min_dictionary_size )
 
261
      {
 
262
        partial_volume_size = 0;
 
263
        if( delete_output_on_interrupt )
 
264
        {
 
265
          close_and_set_permissions( in_statsp );
 
266
          if( !next_filename() )
 
267
          { pp( "Too many volume files" ); retval = 1; break; }
 
268
          if( !open_outstream( true ) ) { retval = 1; break; }
 
269
          delete_output_on_interrupt = true;
 
270
        }
 
271
      }
 
272
      matchfinder.reset();
 
273
    }
 
274
 
 
275
    if( retval == 0 && verbosity >= 1 )
 
276
    {
 
277
      if( in_size <= 0 || out_size <= 0 )
 
278
        fprintf( stderr, "No data compressed.\n" );
 
279
      else
 
280
        fprintf( stderr, "%6.3f:1, %6.3f bits/byte, "
 
281
                              "%5.2f%% saved, %lld in, %lld out.\n",
 
282
                      (double)in_size / out_size,
 
283
                      ( 8.0 * out_size ) / in_size,
 
284
                      100.0 * ( 1.0 - ( (double)out_size / in_size ) ),
 
285
                      in_size, out_size );
 
286
    }
 
287
  return retval;
 
288
}
 
289
 
 
290
 
 
291
int fcompress( const long long member_size, const long long volume_size,
 
292
               const int infd,
 
293
               const struct stat * const in_statsp )
 
294
{
 
295
  if( verbosity >= 1 ) pp();
 
296
  File_header header;
 
297
  header.set_magic();
 
298
  int retval = 0;
 
299
 
 
300
    Fmatchfinder fmatchfinder( infd );
 
301
    header.dictionary_size( fmatchfinder.dictionary_size() );
 
302
 
 
303
    long long in_size = 0, out_size = 0, partial_volume_size = 0;
 
304
    while( true )               // encode one member per iteration
 
305
    {
 
306
      FLZ_encoder encoder( fmatchfinder, header, outfd );
 
307
      const long long size =
 
308
        min( member_size, volume_size - partial_volume_size );
 
309
      if( !encoder.encode_member( size ) )
 
310
      { pp( "Encoder error" ); retval = 1; break; }
 
311
      in_size += fmatchfinder.data_position();
 
312
      out_size += encoder.member_position();
 
313
      if( fmatchfinder.finished() ) break;
 
314
      partial_volume_size += encoder.member_position();
 
315
      if( partial_volume_size >= volume_size - min_dictionary_size )
 
316
      {
 
317
        partial_volume_size = 0;
 
318
        if( delete_output_on_interrupt )
 
319
        {
 
320
          close_and_set_permissions( in_statsp );
 
321
          if( !next_filename() )
 
322
          { pp( "Too many volume files" ); retval = 1; break; }
 
323
          if( !open_outstream( true ) ) { retval = 1; break; }
 
324
          delete_output_on_interrupt = true;
 
325
        }
 
326
      }
 
327
      fmatchfinder.reset();
 
328
    }
 
329
 
 
330
    if( retval == 0 && verbosity >= 1 )
 
331
    {
 
332
      if( in_size <= 0 || out_size <= 0 )
 
333
        fprintf( stderr, "No data compressed.\n" );
 
334
      else
 
335
        fprintf( stderr, "%6.3f:1, %6.3f bits/byte, "
 
336
                              "%5.2f%% saved, %lld in, %lld out.\n",
 
337
                      (double)in_size / out_size,
 
338
                      ( 8.0 * out_size ) / in_size,
 
339
                      100.0 * ( 1.0 - ( (double)out_size / in_size ) ),
 
340
                      in_size, out_size );
 
341
    }
 
342
  return retval;
 
343
}
 
344
#endif
 
345
 
 
346
int decompress( const int infd, const bool testing )
 
347
{
 
348
  int retval = 0;
 
349
 
 
350
    Range_decoder rdec( infd );
 
351
    long long partial_file_pos = 0;
 
352
    for( bool first_member = true; ; first_member = false )
 
353
    {
 
354
      File_header header;
 
355
      int size;
 
356
      rdec.reset_member_position();
 
357
      for( size = 0; size < File_header::size && !rdec.finished(); ++size )
 
358
         header.data[size] = rdec.get_byte();
 
359
      if( rdec.finished() )                     // End Of File
 
360
      {
 
361
        if( first_member )
 
362
        { pp( "Error reading member header" ); retval = 1; }
 
363
        break;
 
364
      }
 
365
      if( !header.verify_magic() )
 
366
      {
 
367
        if( first_member )
 
368
        { pp( "Bad magic number (file not in lzip format)" ); retval = 2; }
 
369
        break;
 
370
      }
 
371
      if( !header.verify_version() )
 
372
      {
 
373
        if( verbosity >= 0 )
 
374
        { pp();
 
375
            fprintf( stderr, "Version %d member format not supported.\n",
 
376
                          header.version() ); }
 
377
        retval = 2; break;
 
378
      }
 
379
      if( header.dictionary_size() < min_dictionary_size ||
 
380
          header.dictionary_size() > max_dictionary_size )
 
381
      { pp( "Invalid dictionary size in member header" ); retval = 2; break; }
 
382
 
 
383
      if( verbosity >= 2 || ( verbosity == 1 && first_member ) )
 
384
      {
 
385
        pp();
 
386
        if( verbosity >= 2 )
 
387
          fprintf( stderr, "version %d, dictionary size %7sB.  ",
 
388
                        header.version(),
 
389
                        format_num( header.dictionary_size() ) );
 
390
      }
 
391
      LZ_decoder decoder( header, rdec, outfd );
 
392
 
 
393
      const int result = decoder.decode_member();
 
394
      partial_file_pos += rdec.member_position();
 
395
      if( result != 0 )
 
396
      {
 
397
        if( verbosity >= 0 && result <= 2 )
 
398
        {
 
399
          pp();
 
400
          if( result == 2 )
 
401
            fprintf( stderr, "File ends unexpectedly at pos %lld\n",
 
402
                          partial_file_pos );
 
403
          else
 
404
            fprintf( stderr, "Decoder error at pos %lld\n",
 
405
                          partial_file_pos );
 
406
        }
 
407
        retval = 2; break;
 
408
      }
 
409
      if( verbosity >= 2 )
 
410
      { if( testing ) fprintf( stderr, "ok\n" );
 
411
          else fprintf( stderr, "done\n" ); }
 
412
    }
 
413
  if( verbosity == 1 && retval == 0 )
 
414
  { if( testing ) fprintf( stderr, "ok\n" );
 
415
      else fprintf( stderr, "done\n" ); }
 
416
  return retval;
 
417
}
 
418
 
 
419
 
 
420
} // end namespace
 
421
 
 
422
 
 
423
void show_error( const char * const msg, const int errcode, const bool help )
 
424
{
 
425
  if( verbosity >= 0 )
 
426
  {
 
427
    if( msg && msg[0] )
 
428
    {
 
429
      fprintf( stderr, "%s: %s", program_name, msg );
 
430
      if( errcode > 0 )
 
431
        fprintf( stderr, ": %s", strerror( errcode ) );
 
432
      fprintf( stderr, "\n" );
 
433
    }
 
434
    if( help && invocation_name && invocation_name[0] )
 
435
      fprintf( stderr, "Try `%s --help' for more information.\n",
 
436
                    invocation_name );
 
437
  }
 
438
}
 
439
 
 
440
 
 
441
void internal_error( const char * const msg )
 
442
{
 
443
  if( verbosity >= 0 )
 
444
    fprintf( stderr, "%s: internal error: %s.\n", program_name, msg );
 
445
  exit( 3 );
 
446
}
 
447
 
 
448
 
 
449
int main( const int argc, const char * const argv[] )
 
450
{
 
451
  // Mapping from gzip/bzip2 style 1..9 compression modes
 
452
  // to the corresponding LZMA compression modes.
 
453
  const Lzma_options option_mapping[] =
 
454
  {
 
455
  { 1 << 16,  16 },             // -0 entry values not used
 
456
  { 1 << 20,   5 },             // -1
 
457
  { 3 << 19,   6 },             // -2
 
458
  { 1 << 21,   8 },             // -3
 
459
  { 3 << 20,  12 },             // -4
 
460
  { 1 << 22,  20 },             // -5
 
461
  { 1 << 23,  36 },             // -6
 
462
  { 1 << 24,  68 },             // -7
 
463
  { 3 << 23, 132 },             // -8
 
464
  { 1 << 25, 273 } };           // -9
 
465
  Lzma_options encoder_options = option_mapping[6];     // default = "-6"
 
466
  long long member_size = LLONG_MAX;
 
467
  long long volume_size = LLONG_MAX;
 
468
  int infd = -1;
 
469
  Mode program_mode = m_compress;
 
470
  bool keep_input_files = false;
 
471
  bool to_stdout = false;
 
472
  bool zero = false;
 
473
  invocation_name = argv[0];
 
474
 
 
475
  // Greatly simplified argument parsing
 
476
  int argind = 1;
 
477
  for( ; argind < argc; ++argind )
 
478
  {
 
479
    const int code = argv[argind][1];
 
480
    switch( code )
 
481
    {
 
482
      case 'c': to_stdout = true; break;
 
483
      case 'd': program_mode = m_decompress; break;
 
484
      case 'h': show_help(); return 0;
 
485
      case 'k': keep_input_files = true; break;
 
486
      case 'q': verbosity = -1; break;
 
487
                zero = false; break;
 
488
      case 'v': if( verbosity < 4 ) ++verbosity; break;
 
489
      case 'V': show_version(); return 0;
 
490
      default : internal_error( "uncaught option" );
 
491
    }
 
492
  } // end process options
 
493
 
 
494
#if defined(__MSVCRT__) || defined(__OS2__)
 
495
  _setmode( STDIN_FILENO, O_BINARY );
 
496
  _setmode( STDOUT_FILENO, O_BINARY );
 
497
#endif
 
498
 
 
499
  if( program_mode == m_test )
 
500
    outfd = -1;
 
501
#if !DECODER_ONLY
 
502
  else if( program_mode == m_compress )
 
503
  {
 
504
    dis_slots.init();
 
505
    prob_prices.init();
 
506
  }
 
507
#endif
 
508
 
 
509
  int retval = 0;
 
510
  {
 
511
    struct stat in_stats;
 
512
 
 
513
    infd = STDIN_FILENO;
 
514
    outfd = STDOUT_FILENO;
 
515
 
 
516
    if( !check_tty( infd, program_mode ) ) return 1;
 
517
 
 
518
    const struct stat * const in_statsp = 0;
 
519
    //pp.set_name( "-" );
 
520
    int tmp = 0;
 
521
#if !DECODER_ONLY
 
522
    if( program_mode == m_compress )
 
523
    {
 
524
      if( zero )
 
525
        tmp = fcompress( member_size, volume_size, infd, in_statsp );
 
526
      else
 
527
        tmp = compress( member_size, volume_size, encoder_options, infd,
 
528
                        in_statsp );
 
529
    }
 
530
    else
 
531
#endif
 
532
      tmp = decompress( infd, program_mode == m_test );
 
533
    if( tmp > retval ) retval = tmp;
 
534
    //if( tmp && program_mode != m_test ) cleanup_and_fail( retval );
 
535
 
 
536
    if( delete_output_on_interrupt )
 
537
      close_and_set_permissions( in_statsp );
 
538
  }
 
539
  if( outfd >= 0 && close( outfd ) != 0 )
 
540
  {
 
541
    show_error( "Can't close stdout", errno );
 
542
    if( retval < 1 ) retval = 1;
 
543
  }
 
544
  return retval;
 
545
}