~mmach/netext73/lz4

« back to all changes in this revision

Viewing changes to programs/lz4io.c

  • Committer: mmach
  • Date: 2022-11-09 18:52:10 UTC
  • Revision ID: netbit73@gmail.com-20221109185210-w358idlhh0phq688
1.9.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
  LZ4io.c - LZ4 File/Stream Interface
3
 
  Copyright (C) Yann Collet 2011-2017
 
3
  Copyright (C) Yann Collet 2011-2020
4
4
 
5
5
  GPL v2 License
6
6
 
103
103
        }   }
104
104
static const clock_t refreshRate = CLOCKS_PER_SEC / 6;
105
105
static clock_t g_time = 0;
 
106
 
106
107
#define LZ4IO_STATIC_ASSERT(c)   { enum { LZ4IO_static_assert = 1/(int)(!!(c)) }; }   /* use after variable declarations */
107
108
 
108
109
 
109
110
/**************************************
110
 
*  Local Parameters
111
 
**************************************/
 
111
*  Exceptions
 
112
***************************************/
 
113
#ifndef DEBUG
 
114
#  define DEBUG 0
 
115
#endif
 
116
#define DEBUGOUTPUT(...) if (DEBUG) DISPLAY(__VA_ARGS__);
 
117
#define END_PROCESS(error, ...)                                           \
 
118
{                                                                         \
 
119
    DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \
 
120
    DISPLAYLEVEL(1, "Error %i : ", error);                                \
 
121
    DISPLAYLEVEL(1, __VA_ARGS__);                                         \
 
122
    DISPLAYLEVEL(1, " \n");                                               \
 
123
    exit(error);                                                          \
 
124
}
 
125
 
 
126
 
 
127
/* ************************************************** */
 
128
/* ****************** Parameters ******************** */
 
129
/* ************************************************** */
112
130
 
113
131
struct LZ4IO_prefs_s {
114
132
    int passThrough;
127
145
    int removeSrcFile;
128
146
};
129
147
 
130
 
/**************************************
131
 
*  Exceptions
132
 
***************************************/
133
 
#ifndef DEBUG
134
 
#  define DEBUG 0
135
 
#endif
136
 
#define DEBUGOUTPUT(...) if (DEBUG) DISPLAY(__VA_ARGS__);
137
 
#define EXM_THROW(error, ...)                                             \
138
 
{                                                                         \
139
 
    DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \
140
 
    DISPLAYLEVEL(1, "Error %i : ", error);                                \
141
 
    DISPLAYLEVEL(1, __VA_ARGS__);                                         \
142
 
    DISPLAYLEVEL(1, " \n");                                               \
143
 
    exit(error);                                                          \
144
 
}
145
 
 
146
 
 
147
 
/**************************************
148
 
*  Version modifiers
149
 
**************************************/
150
 
#define EXTENDED_ARGUMENTS
151
 
#define EXTENDED_HELP
152
 
#define EXTENDED_FORMAT
153
 
#define DEFAULT_DECOMPRESSOR LZ4IO_decompressLZ4F
154
 
 
155
 
 
156
 
/* ************************************************** */
157
 
/* ****************** Parameters ******************** */
158
 
/* ************************************************** */
159
 
 
160
148
LZ4IO_prefs_t* LZ4IO_defaultPreferences(void)
161
149
{
162
150
    LZ4IO_prefs_t* const ret = (LZ4IO_prefs_t*)malloc(sizeof(*ret));
163
 
    if (!ret) EXM_THROW(21, "Allocation error : not enough memory");
 
151
    if (!ret) END_PROCESS(21, "Allocation error : not enough memory");
164
152
    ret->passThrough = 0;
165
153
    ret->overwrite = 1;
166
154
    ret->testMode = 0;
298
286
 
299
287
 
300
288
/* ************************************************************************ **
 
289
** ********************** String functions ********************* **
 
290
** ************************************************************************ */
 
291
 
 
292
static int LZ4IO_isDevNull(const char* s)
 
293
{
 
294
    return UTIL_sameString(s, nulmark);
 
295
}
 
296
 
 
297
static int LZ4IO_isStdin(const char* s)
 
298
{
 
299
    return UTIL_sameString(s, stdinmark);
 
300
}
 
301
 
 
302
static int LZ4IO_isStdout(const char* s)
 
303
{
 
304
    return UTIL_sameString(s, stdoutmark);
 
305
}
 
306
 
 
307
 
 
308
/* ************************************************************************ **
301
309
** ********************** LZ4 File / Pipe compression ********************* **
302
310
** ************************************************************************ */
303
311
 
313
321
{
314
322
    FILE* f;
315
323
 
316
 
    if (!strcmp (srcFileName, stdinmark)) {
317
 
        DISPLAYLEVEL(4,"Using stdin for input\n");
 
324
    if (LZ4IO_isStdin(srcFileName)) {
 
325
        DISPLAYLEVEL(4,"Using stdin for input \n");
318
326
        f = stdin;
319
327
        SET_BINARY_MODE(stdin);
320
328
    } else {
321
329
        f = fopen(srcFileName, "rb");
322
 
        if ( f==NULL ) DISPLAYLEVEL(1, "%s: %s \n", srcFileName, strerror(errno));
 
330
        if (f==NULL) DISPLAYLEVEL(1, "%s: %s \n", srcFileName, strerror(errno));
323
331
    }
324
332
 
325
333
    return f;
334
342
    FILE* f;
335
343
    assert(dstFileName != NULL);
336
344
 
337
 
    if (!strcmp (dstFileName, stdoutmark)) {
 
345
    if (LZ4IO_isStdout(dstFileName)) {
338
346
        DISPLAYLEVEL(4, "Using stdout for output \n");
339
347
        f = stdout;
340
348
        SET_BINARY_MODE(stdout);
343
351
                            " to force-enable it, add --sparse command \n");
344
352
        }
345
353
    } else {
346
 
        if (!prefs->overwrite && strcmp (dstFileName, nulmark)) {  /* Check if destination file already exists */
 
354
        if (!prefs->overwrite && !LZ4IO_isDevNull(dstFileName)) {
 
355
            /* Check if destination file already exists */
347
356
            FILE* const testf = fopen( dstFileName, "rb" );
348
357
            if (testf != NULL) {  /* dest exists, prompt for overwrite authorization */
349
358
                fclose(testf);
351
360
                    DISPLAY("%s already exists; not overwritten  \n", dstFileName);
352
361
                    return NULL;
353
362
                }
354
 
                DISPLAY("%s already exists; do you wish to overwrite (y/N) ? ", dstFileName);
 
363
                DISPLAY("%s already exists; do you want to overwrite (y/N) ? ", dstFileName);
355
364
                {   int ch = getchar();
356
365
                    if ((ch!='Y') && (ch!='y')) {
357
366
                        DISPLAY("    not overwritten  \n");
377
386
*   Legacy Compression
378
387
***************************************/
379
388
 
380
 
/* unoptimized version; solves endianess & alignment issues */
 
389
/* Size in bytes of a legacy block header in little-endian format */
 
390
#define LZ4IO_LEGACY_BLOCK_HEADER_SIZE 4
 
391
#define LZ4IO_LEGACY_BLOCK_SIZE_MAX  (8 MB)
 
392
 
 
393
/* unoptimized version; solves endianness & alignment issues */
381
394
static void LZ4IO_writeLE32 (void* p, unsigned value32)
382
395
{
383
396
    unsigned char* const dstPtr = (unsigned char*)p;
413
426
    /* Init */
414
427
    clock_t const clockStart = clock();
415
428
    if (finput == NULL)
416
 
        EXM_THROW(20, "%s : open file error ", input_filename);
 
429
        END_PROCESS(20, "%s : open file error ", input_filename);
417
430
 
418
431
    foutput = LZ4IO_openDstFile(output_filename, prefs);
419
432
    if (foutput == NULL) {
420
433
        fclose(finput);
421
 
        EXM_THROW(20, "%s : open file error ", input_filename);
 
434
        END_PROCESS(20, "%s : open file error ", input_filename);
422
435
    }
423
436
 
424
437
    /* Allocate Memory */
425
438
    in_buff = (char*)malloc(LEGACY_BLOCKSIZE);
426
439
    out_buff = (char*)malloc((size_t)outBuffSize + 4);
427
440
    if (!in_buff || !out_buff)
428
 
        EXM_THROW(21, "Allocation error : not enough memory");
 
441
        END_PROCESS(21, "Allocation error : not enough memory");
429
442
 
430
443
    /* Write Archive Header */
431
444
    LZ4IO_writeLE32(out_buff, LEGACY_MAGICNUMBER);
432
445
    if (fwrite(out_buff, 1, MAGICNUMBER_SIZE, foutput) != MAGICNUMBER_SIZE)
433
 
        EXM_THROW(22, "Write error : cannot write header");
 
446
        END_PROCESS(22, "Write error : cannot write header");
434
447
 
435
448
    /* Main Loop */
436
449
    while (1) {
445
458
        outSize = compressionFunction(in_buff, out_buff+4, (int)inSize, outBuffSize, compressionlevel);
446
459
        assert(outSize >= 0);
447
460
        compressedfilesize += (unsigned long long)outSize+4;
448
 
        DISPLAYUPDATE(2, "\rRead : %i MB  ==> %.2f%%   ",
 
461
        DISPLAYUPDATE(2, "\rRead : %i MiB  ==> %.2f%%   ",
449
462
                (int)(filesize>>20), (double)compressedfilesize/filesize*100);
450
463
 
451
464
        /* Write Block */
453
466
        assert(outSize < outBuffSize);
454
467
        LZ4IO_writeLE32(out_buff, (unsigned)outSize);
455
468
        if (fwrite(out_buff, 1, (size_t)outSize+4, foutput) != (size_t)(outSize+4)) {
456
 
            EXM_THROW(24, "Write error : cannot write compressed block");
 
469
            END_PROCESS(24, "Write error : cannot write compressed block");
457
470
    }   }
458
 
    if (ferror(finput)) EXM_THROW(25, "Error while reading %s ", input_filename);
 
471
    if (ferror(finput)) END_PROCESS(24, "Error while reading %s ", input_filename);
459
472
 
460
473
    /* Status */
461
474
    clockEnd = clock();
462
 
    if (clockEnd==clockStart) clockEnd+=1;  /* avoid division by zero (speed) */
 
475
    clockEnd += (clockEnd==clockStart); /* avoid division by zero (speed) */
463
476
    filesize += !filesize;   /* avoid division by zero (ratio) */
464
477
    DISPLAYLEVEL(2, "\r%79s\r", "");   /* blank line */
465
478
    DISPLAYLEVEL(2,"Compressed %llu bytes into %llu bytes ==> %.2f%%\n",
466
479
        filesize, compressedfilesize, (double)compressedfilesize / filesize * 100);
467
480
    {   double const seconds = (double)(clockEnd - clockStart) / CLOCKS_PER_SEC;
468
 
        DISPLAYLEVEL(4,"Done in %.2f s ==> %.2f MB/s\n", seconds,
 
481
        DISPLAYLEVEL(4,"Done in %.2f s ==> %.2f MiB/s\n", seconds,
469
482
                        (double)filesize / seconds / 1024 / 1024);
470
483
    }
471
484
 
473
486
    free(in_buff);
474
487
    free(out_buff);
475
488
    fclose(finput);
476
 
    if (strcmp(output_filename,stdoutmark)) fclose(foutput);   /* do not close stdout */
 
489
    if (!LZ4IO_isStdout(output_filename)) fclose(foutput);  /* do not close stdout */
477
490
 
478
491
    return 0;
479
492
}
498
511
    /* loop on each file */
499
512
    for (i=0; i<ifntSize; i++) {
500
513
        size_t const ifnSize = strlen(inFileNamesTable[i]);
501
 
        if (!strcmp(suffix, stdoutmark)) {
 
514
        if (LZ4IO_isStdout(suffix)) {
502
515
            missed_files += LZ4IO_compressFilename_Legacy(
503
516
                                    inFileNamesTable[i], stdoutmark,
504
517
                                    compressionLevel, prefs);
530
543
/*********************************************
531
544
*  Compression using Frame format
532
545
*********************************************/
533
 
 
534
546
typedef struct {
535
547
    void*  srcBuffer;
536
548
    size_t srcBufferSize;
551
563
    char*  dictBuf;
552
564
    FILE* dictFile;
553
565
 
554
 
    if (!circularBuf) EXM_THROW(25, "Allocation error : not enough memory for circular buffer");
555
 
    if (!dictFilename) EXM_THROW(25, "Dictionary error : no filename provided");
 
566
    if (!circularBuf) END_PROCESS(25, "Allocation error : not enough memory for circular buffer");
 
567
    if (!dictFilename) END_PROCESS(26, "Dictionary error : no filename provided");
556
568
 
557
569
    dictFile = LZ4IO_openSrcFile(dictFilename);
558
 
    if (!dictFile) EXM_THROW(25, "Dictionary error : could not open dictionary file");
 
570
    if (!dictFile) END_PROCESS(27, "Dictionary error : could not open dictionary file");
559
571
 
560
 
    /* opportunistically seek to the part of the file we care about. If this */
561
 
    /* fails it's not a problem since we'll just read everything anyways.    */
562
 
    if (strcmp(dictFilename, stdinmark)) {
 
572
    /* opportunistically seek to the part of the file we care about.
 
573
     * If this fails it's not a problem since we'll just read everything anyways. */
 
574
    if (!LZ4IO_isStdin(dictFilename)) {
563
575
        (void)UTIL_fseek(dictFile, -LZ4_MAX_DICT_SIZE, SEEK_END);
564
576
    }
565
577
 
584
596
    } else {
585
597
        /* Otherwise, we will alloc a new buffer and copy our dict into that. */
586
598
        dictBuf = (char *)malloc(dictLen ? dictLen : 1);
587
 
        if (!dictBuf) EXM_THROW(25, "Allocation error : not enough memory");
 
599
        if (!dictBuf) END_PROCESS(28, "Allocation error : not enough memory");
588
600
 
589
601
        memcpy(dictBuf, circularBuf + dictStart, circularBufSize - dictStart);
590
602
        memcpy(dictBuf + circularBufSize - dictStart, circularBuf, dictLen - (circularBufSize - dictStart));
603
615
    LZ4F_CDict* cdict;
604
616
    if (!prefs->useDictionary) return NULL;
605
617
    dictionaryBuffer = LZ4IO_createDict(&dictionarySize, prefs->dictionaryFilename);
606
 
    if (!dictionaryBuffer) EXM_THROW(25, "Dictionary error : could not create dictionary");
 
618
    if (!dictionaryBuffer) END_PROCESS(29, "Dictionary error : could not create dictionary");
607
619
    cdict = LZ4F_createCDict(dictionaryBuffer, dictionarySize);
608
620
    free(dictionaryBuffer);
609
621
    return cdict;
615
627
    cRess_t ress;
616
628
 
617
629
    LZ4F_errorCode_t const errorCode = LZ4F_createCompressionContext(&(ress.ctx), LZ4F_VERSION);
618
 
    if (LZ4F_isError(errorCode)) EXM_THROW(30, "Allocation error : can't create LZ4F context : %s", LZ4F_getErrorName(errorCode));
 
630
    if (LZ4F_isError(errorCode)) END_PROCESS(30, "Allocation error : can't create LZ4F context : %s", LZ4F_getErrorName(errorCode));
619
631
 
620
632
    /* Allocate Memory */
621
633
    ress.srcBuffer = malloc(blockSize);
622
634
    ress.srcBufferSize = blockSize;
623
635
    ress.dstBufferSize = LZ4F_compressFrameBound(blockSize, NULL);   /* cover worst case */
624
636
    ress.dstBuffer = malloc(ress.dstBufferSize);
625
 
    if (!ress.srcBuffer || !ress.dstBuffer) EXM_THROW(31, "Allocation error : not enough memory");
 
637
    if (!ress.srcBuffer || !ress.dstBuffer) END_PROCESS(31, "Allocation error : not enough memory");
626
638
 
627
639
    ress.cdict = LZ4IO_createCDict(prefs);
628
640
 
638
650
    ress.cdict = NULL;
639
651
 
640
652
    { LZ4F_errorCode_t const errorCode = LZ4F_freeCompressionContext(ress.ctx);
641
 
      if (LZ4F_isError(errorCode)) EXM_THROW(38, "Error : can't free LZ4F context resource : %s", LZ4F_getErrorName(errorCode)); }
 
653
      if (LZ4F_isError(errorCode)) END_PROCESS(35, "Error : can't free LZ4F context resource : %s", LZ4F_getErrorName(errorCode)); }
642
654
}
643
655
 
644
656
/*
686
698
 
687
699
    /* read first block */
688
700
    readSize  = fread(srcBuffer, (size_t)1, blockSize, srcFile);
689
 
    if (ferror(srcFile)) EXM_THROW(30, "Error reading %s ", srcFileName);
 
701
    if (ferror(srcFile)) END_PROCESS(40, "Error reading %s ", srcFileName);
690
702
    filesize += readSize;
691
703
 
692
704
    /* single-block file */
694
706
        /* Compress in single pass */
695
707
        size_t const cSize = LZ4F_compressFrame_usingCDict(ctx, dstBuffer, dstBufferSize, srcBuffer, readSize, ress.cdict, &prefs);
696
708
        if (LZ4F_isError(cSize))
697
 
            EXM_THROW(31, "Compression failed : %s", LZ4F_getErrorName(cSize));
 
709
            END_PROCESS(41, "Compression failed : %s", LZ4F_getErrorName(cSize));
698
710
        compressedfilesize = cSize;
699
 
        DISPLAYUPDATE(2, "\rRead : %u MB   ==> %.2f%%   ",
 
711
        DISPLAYUPDATE(2, "\rRead : %u MiB   ==> %.2f%%   ",
700
712
                      (unsigned)(filesize>>20), (double)compressedfilesize/(filesize+!filesize)*100);   /* avoid division by zero */
701
713
 
702
714
        /* Write Block */
703
715
        if (fwrite(dstBuffer, 1, cSize, dstFile) != cSize) {
704
 
            EXM_THROW(32, "Write error : failed writing single-block compressed frame");
 
716
            END_PROCESS(42, "Write error : failed writing single-block compressed frame");
705
717
    }   }
706
718
 
707
719
    else
710
722
    {
711
723
        /* Write Frame Header */
712
724
        size_t const headerSize = LZ4F_compressBegin_usingCDict(ctx, dstBuffer, dstBufferSize, ress.cdict, &prefs);
713
 
        if (LZ4F_isError(headerSize)) EXM_THROW(33, "File header generation failed : %s", LZ4F_getErrorName(headerSize));
 
725
        if (LZ4F_isError(headerSize)) END_PROCESS(43, "File header generation failed : %s", LZ4F_getErrorName(headerSize));
714
726
        if (fwrite(dstBuffer, 1, headerSize, dstFile) != headerSize)
715
 
            EXM_THROW(34, "Write error : cannot write header");
 
727
            END_PROCESS(44, "Write error : cannot write header");
716
728
        compressedfilesize += headerSize;
717
729
 
718
730
        /* Main Loop - one block at a time */
719
731
        while (readSize>0) {
720
732
            size_t const outSize = LZ4F_compressUpdate(ctx, dstBuffer, dstBufferSize, srcBuffer, readSize, NULL);
721
733
            if (LZ4F_isError(outSize))
722
 
                EXM_THROW(35, "Compression failed : %s", LZ4F_getErrorName(outSize));
 
734
                END_PROCESS(45, "Compression failed : %s", LZ4F_getErrorName(outSize));
723
735
            compressedfilesize += outSize;
724
 
            DISPLAYUPDATE(2, "\rRead : %u MB   ==> %.2f%%   ",
 
736
            DISPLAYUPDATE(2, "\rRead : %u MiB   ==> %.2f%%   ",
725
737
                        (unsigned)(filesize>>20), (double)compressedfilesize/filesize*100);
726
738
 
727
739
            /* Write Block */
728
740
            if (fwrite(dstBuffer, 1, outSize, dstFile) != outSize)
729
 
                EXM_THROW(36, "Write error : cannot write compressed block");
 
741
                END_PROCESS(46, "Write error : cannot write compressed block");
730
742
 
731
743
            /* Read next block */
732
744
            readSize  = fread(srcBuffer, (size_t)1, (size_t)blockSize, srcFile);
733
745
            filesize += readSize;
734
746
        }
735
 
        if (ferror(srcFile)) EXM_THROW(37, "Error reading %s ", srcFileName);
 
747
        if (ferror(srcFile)) END_PROCESS(47, "Error reading %s ", srcFileName);
736
748
 
737
749
        /* End of Frame mark */
738
750
        {   size_t const endSize = LZ4F_compressEnd(ctx, dstBuffer, dstBufferSize, NULL);
739
751
            if (LZ4F_isError(endSize))
740
 
                EXM_THROW(38, "End of frame error : %s", LZ4F_getErrorName(endSize));
 
752
                END_PROCESS(48, "End of frame error : %s", LZ4F_getErrorName(endSize));
741
753
            if (fwrite(dstBuffer, 1, endSize, dstFile) != endSize)
742
 
                EXM_THROW(39, "Write error : cannot write end of frame");
 
754
                END_PROCESS(49, "Write error : cannot write end of frame");
743
755
            compressedfilesize += endSize;
744
756
    }   }
745
757
 
746
758
    /* Release file handlers */
747
759
    fclose (srcFile);
748
 
    if (strcmp(dstFileName,stdoutmark)) fclose (dstFile);  /* do not close stdout */
 
760
    if (!LZ4IO_isStdout(dstFileName)) fclose(dstFile);  /* do not close stdout */
749
761
 
750
762
    /* Copy owner, file permissions and modification time */
751
763
    {   stat_t statbuf;
752
 
        if (strcmp (srcFileName, stdinmark)
753
 
         && strcmp (dstFileName, stdoutmark)
754
 
         && strcmp (dstFileName, nulmark)
 
764
        if (!LZ4IO_isStdin(srcFileName)
 
765
         && !LZ4IO_isStdout(dstFileName)
 
766
         && !LZ4IO_isDevNull(dstFileName)
755
767
         && UTIL_getFileStat(srcFileName, &statbuf)) {
756
768
            UTIL_setFileStat(dstFileName, &statbuf);
757
769
    }   }
758
770
 
759
771
    if (io_prefs->removeSrcFile) {  /* remove source file : --rm */
760
772
        if (remove(srcFileName))
761
 
            EXM_THROW(40, "Remove error : %s: %s", srcFileName, strerror(errno));
 
773
            END_PROCESS(50, "Remove error : %s: %s", srcFileName, strerror(errno));
762
774
    }
763
775
 
764
776
    /* Final Status */
814
826
    /* loop on each file */
815
827
    for (i=0; i<ifntSize; i++) {
816
828
        size_t const ifnSize = strlen(inFileNamesTable[i]);
817
 
        if (!strcmp(suffix, stdoutmark)) {
 
829
        if (LZ4IO_isStdout(suffix)) {
818
830
            missed_files += LZ4IO_compressFilename_extRess(ress,
819
831
                                    inFileNamesTable[i], stdoutmark,
820
832
                                    compressionLevel, prefs);
821
833
            continue;
822
834
        }
 
835
        /* suffix != stdout => compress into a file => generate its name */
823
836
        if (ofnSize <= ifnSize+suffixSize+1) {
824
837
            free(dstFileName);
825
838
            ofnSize = ifnSize + 20;
877
890
 
878
891
    if (!sparseMode) {  /* normal write */
879
892
        size_t const sizeCheck = fwrite(buffer, 1, bufferSize, file);
880
 
        if (sizeCheck != bufferSize) EXM_THROW(70, "Write error : cannot write decoded block");
 
893
        if (sizeCheck != bufferSize) END_PROCESS(70, "Write error : cannot write decoded block");
881
894
        return 0;
882
895
    }
883
896
 
884
897
    /* avoid int overflow */
885
898
    if (storedSkips > 1 GB) {
886
899
        int const seekResult = UTIL_fseek(file, 1 GB, SEEK_CUR);
887
 
        if (seekResult != 0) EXM_THROW(71, "1 GB skip error (sparse file support)");
 
900
        if (seekResult != 0) END_PROCESS(71, "1 GB skip error (sparse file support)");
888
901
        storedSkips -= 1 GB;
889
902
    }
890
903
 
901
914
        if (nb0T != seg0SizeT) {   /* not all 0s */
902
915
            errno = 0;
903
916
            {   int const seekResult = UTIL_fseek(file, storedSkips, SEEK_CUR);
904
 
                if (seekResult) EXM_THROW(72, "Sparse skip error(%d): %s ; try --no-sparse", (int)errno, strerror(errno));
 
917
                if (seekResult) END_PROCESS(72, "Sparse skip error(%d): %s ; try --no-sparse", (int)errno, strerror(errno));
905
918
            }
906
919
            storedSkips = 0;
907
920
            seg0SizeT -= nb0T;
908
921
            ptrT += nb0T;
909
922
            {   size_t const sizeCheck = fwrite(ptrT, sizeT, seg0SizeT, file);
910
 
                if (sizeCheck != seg0SizeT) EXM_THROW(73, "Write error : cannot write decoded block");
 
923
                if (sizeCheck != seg0SizeT) END_PROCESS(73, "Write error : cannot write decoded block");
911
924
        }   }
912
925
        ptrT += seg0SizeT;
913
926
    }
921
934
        storedSkips += (unsigned) (restPtr - restStart);
922
935
        if (restPtr != restEnd) {
923
936
            int const seekResult = UTIL_fseek(file, storedSkips, SEEK_CUR);
924
 
            if (seekResult) EXM_THROW(74, "Sparse skip error ; try --no-sparse");
 
937
            if (seekResult) END_PROCESS(74, "Sparse skip error ; try --no-sparse");
925
938
            storedSkips = 0;
926
939
            {   size_t const sizeCheck = fwrite(restPtr, 1, (size_t)(restEnd - restPtr), file);
927
 
                if (sizeCheck != (size_t)(restEnd - restPtr)) EXM_THROW(75, "Write error : cannot write decoded end of block");
 
940
                if (sizeCheck != (size_t)(restEnd - restPtr)) END_PROCESS(75, "Write error : cannot write decoded end of block");
928
941
        }   }
929
942
    }
930
943
 
936
949
    if (storedSkips>0) {   /* implies sparseFileSupport>0 */
937
950
        const char lastZeroByte[1] = { 0 };
938
951
        if (UTIL_fseek(file, storedSkips-1, SEEK_CUR) != 0)
939
 
            EXM_THROW(69, "Final skip error (sparse file)\n");
 
952
            END_PROCESS(68, "Final skip error (sparse file)\n");
940
953
        if (fwrite(lastZeroByte, 1, 1, file) != 1)
941
 
            EXM_THROW(69, "Write error : cannot write last zero\n");
 
954
            END_PROCESS(69, "Write error : cannot write last zero\n");
942
955
    }
943
956
}
944
957
 
945
958
 
946
959
static unsigned g_magicRead = 0;   /* out-parameter of LZ4IO_decodeLegacyStream() */
947
 
static unsigned long long LZ4IO_decodeLegacyStream(FILE* finput, FILE* foutput, const LZ4IO_prefs_t* prefs)
 
960
 
 
961
static unsigned long long
 
962
LZ4IO_decodeLegacyStream(FILE* finput, FILE* foutput, const LZ4IO_prefs_t* prefs)
948
963
{
949
964
    unsigned long long streamSize = 0;
950
965
    unsigned storedSkips = 0;
952
967
    /* Allocate Memory */
953
968
    char* const in_buff  = (char*)malloc((size_t)LZ4_compressBound(LEGACY_BLOCKSIZE));
954
969
    char* const out_buff = (char*)malloc(LEGACY_BLOCKSIZE);
955
 
    if (!in_buff || !out_buff) EXM_THROW(51, "Allocation error : not enough memory");
 
970
    if (!in_buff || !out_buff) END_PROCESS(51, "Allocation error : not enough memory");
956
971
 
957
972
    /* Main Loop */
958
973
    while (1) {
959
974
        unsigned int blockSize;
960
975
 
961
976
        /* Block Size */
962
 
        {   size_t const sizeCheck = fread(in_buff, 1, 4, finput);
 
977
        {   size_t const sizeCheck = fread(in_buff, 1, LZ4IO_LEGACY_BLOCK_HEADER_SIZE, finput);
963
978
            if (sizeCheck == 0) break;                   /* Nothing to read : file read is completed */
964
 
            if (sizeCheck != 4) EXM_THROW(52, "Read error : cannot access block size "); }
965
 
            blockSize = LZ4IO_readLE32(in_buff);       /* Convert to Little Endian */
966
 
            if (blockSize > LZ4_COMPRESSBOUND(LEGACY_BLOCKSIZE)) {
 
979
            if (sizeCheck != LZ4IO_LEGACY_BLOCK_HEADER_SIZE) END_PROCESS(52, "Read error : cannot access block size ");
 
980
        }
 
981
        blockSize = LZ4IO_readLE32(in_buff);       /* Convert to Little Endian */
 
982
        if (blockSize > LZ4_COMPRESSBOUND(LEGACY_BLOCKSIZE)) {
967
983
            /* Cannot read next block : maybe new stream ? */
968
984
            g_magicRead = blockSize;
969
985
            break;
971
987
 
972
988
        /* Read Block */
973
989
        { size_t const sizeCheck = fread(in_buff, 1, blockSize, finput);
974
 
          if (sizeCheck!=blockSize) EXM_THROW(52, "Read error : cannot access compressed block !"); }
 
990
          if (sizeCheck != blockSize) END_PROCESS(53, "Read error : cannot access compressed block !"); }
975
991
 
976
992
        /* Decode Block */
977
993
        {   int const decodeSize = LZ4_decompress_safe(in_buff, out_buff, (int)blockSize, LEGACY_BLOCKSIZE);
978
 
            if (decodeSize < 0) EXM_THROW(53, "Decoding Failed ! Corrupted input detected !");
 
994
            if (decodeSize < 0) END_PROCESS(54, "Decoding Failed ! Corrupted input detected !");
979
995
            streamSize += (unsigned long long)decodeSize;
980
996
            /* Write Block */
981
997
            storedSkips = LZ4IO_fwriteSparse(foutput, out_buff, (size_t)decodeSize, prefs->sparseFileSupport, storedSkips); /* success or die */
982
998
    }   }
983
 
    if (ferror(finput)) EXM_THROW(54, "Read error : ferror");
 
999
    if (ferror(finput)) END_PROCESS(55, "Read error : ferror");
984
1000
 
985
1001
    LZ4IO_fwriteSparseEnd(foutput, storedSkips);
986
1002
 
1013
1029
    }
1014
1030
 
1015
1031
    ress->dictBuffer = LZ4IO_createDict(&ress->dictBufferSize, prefs->dictionaryFilename);
1016
 
    if (!ress->dictBuffer) EXM_THROW(25, "Dictionary error : could not create dictionary");
 
1032
    if (!ress->dictBuffer) END_PROCESS(25, "Dictionary error : could not create dictionary");
1017
1033
}
1018
1034
 
1019
1035
static const size_t LZ4IO_dBufferSize = 64 KB;
1023
1039
 
1024
1040
    /* init */
1025
1041
    LZ4F_errorCode_t const errorCode = LZ4F_createDecompressionContext(&ress.dCtx, LZ4F_VERSION);
1026
 
    if (LZ4F_isError(errorCode)) EXM_THROW(60, "Can't create LZ4F context : %s", LZ4F_getErrorName(errorCode));
 
1042
    if (LZ4F_isError(errorCode)) END_PROCESS(60, "Can't create LZ4F context : %s", LZ4F_getErrorName(errorCode));
1027
1043
 
1028
1044
    /* Allocate Memory */
1029
1045
    ress.srcBufferSize = LZ4IO_dBufferSize;
1030
1046
    ress.srcBuffer = malloc(ress.srcBufferSize);
1031
1047
    ress.dstBufferSize = LZ4IO_dBufferSize;
1032
1048
    ress.dstBuffer = malloc(ress.dstBufferSize);
1033
 
    if (!ress.srcBuffer || !ress.dstBuffer) EXM_THROW(61, "Allocation error : not enough memory");
 
1049
    if (!ress.srcBuffer || !ress.dstBuffer) END_PROCESS(61, "Allocation error : not enough memory");
1034
1050
 
1035
1051
    LZ4IO_loadDDict(&ress, prefs);
1036
1052
 
1041
1057
static void LZ4IO_freeDResources(dRess_t ress)
1042
1058
{
1043
1059
    LZ4F_errorCode_t errorCode = LZ4F_freeDecompressionContext(ress.dCtx);
1044
 
    if (LZ4F_isError(errorCode)) EXM_THROW(69, "Error : can't free LZ4F context resource : %s", LZ4F_getErrorName(errorCode));
 
1060
    if (LZ4F_isError(errorCode)) END_PROCESS(69, "Error : can't free LZ4F context resource : %s", LZ4F_getErrorName(errorCode));
1045
1061
    free(ress.srcBuffer);
1046
1062
    free(ress.dstBuffer);
1047
1063
    free(ress.dictBuffer);
1056
1072
    unsigned long long filesize = 0;
1057
1073
    LZ4F_errorCode_t nextToLoad;
1058
1074
    unsigned storedSkips = 0;
 
1075
    LZ4F_decompressOptions_t const dOpt_skipCrc = { 0, 1, 0, 0 };
 
1076
    const LZ4F_decompressOptions_t* const dOptPtr =
 
1077
        ((prefs->blockChecksum==0) && (prefs->streamChecksum==0)) ?
 
1078
        &dOpt_skipCrc : NULL;
1059
1079
 
1060
1080
    /* Init feed with magic number (already consumed from FILE* sFile) */
1061
1081
    {   size_t inSize = MAGICNUMBER_SIZE;
1062
1082
        size_t outSize= 0;
1063
1083
        LZ4IO_writeLE32(ress.srcBuffer, LZ4IO_MAGICNUMBER);
1064
 
        nextToLoad = LZ4F_decompress_usingDict(ress.dCtx, ress.dstBuffer, &outSize, ress.srcBuffer, &inSize, ress.dictBuffer, ress.dictBufferSize, NULL);
1065
 
        if (LZ4F_isError(nextToLoad)) EXM_THROW(62, "Header error : %s", LZ4F_getErrorName(nextToLoad));
 
1084
        nextToLoad = LZ4F_decompress_usingDict(ress.dCtx,
 
1085
                            ress.dstBuffer, &outSize,
 
1086
                            ress.srcBuffer, &inSize,
 
1087
                            ress.dictBuffer, ress.dictBufferSize,
 
1088
                            dOptPtr);  /* set it once, it's enough */
 
1089
        if (LZ4F_isError(nextToLoad))
 
1090
            END_PROCESS(62, "Header error : %s", LZ4F_getErrorName(nextToLoad));
1066
1091
    }
1067
1092
 
1068
1093
    /* Main Loop */
1080
1105
            /* Decode Input (at least partially) */
1081
1106
            size_t remaining = readSize - pos;
1082
1107
            decodedBytes = ress.dstBufferSize;
1083
 
            nextToLoad = LZ4F_decompress_usingDict(ress.dCtx, ress.dstBuffer, &decodedBytes, (char*)(ress.srcBuffer)+pos, &remaining, ress.dictBuffer, ress.dictBufferSize, NULL);
1084
 
            if (LZ4F_isError(nextToLoad)) EXM_THROW(66, "Decompression error : %s", LZ4F_getErrorName(nextToLoad));
 
1108
            nextToLoad = LZ4F_decompress_usingDict(ress.dCtx,
 
1109
                                    ress.dstBuffer, &decodedBytes,
 
1110
                                    (char*)(ress.srcBuffer)+pos, &remaining,
 
1111
                                    ress.dictBuffer, ress.dictBufferSize,
 
1112
                                    NULL);
 
1113
            if (LZ4F_isError(nextToLoad))
 
1114
                END_PROCESS(66, "Decompression error : %s", LZ4F_getErrorName(nextToLoad));
1085
1115
            pos += remaining;
1086
1116
 
1087
1117
            /* Write Block */
1089
1119
                if (!prefs->testMode)
1090
1120
                    storedSkips = LZ4IO_fwriteSparse(dstFile, ress.dstBuffer, decodedBytes, prefs->sparseFileSupport, storedSkips);
1091
1121
                filesize += decodedBytes;
1092
 
                DISPLAYUPDATE(2, "\rDecompressed : %u MB  ", (unsigned)(filesize>>20));
 
1122
                DISPLAYUPDATE(2, "\rDecompressed : %u MiB  ", (unsigned)(filesize>>20));
1093
1123
            }
1094
1124
 
1095
1125
            if (!nextToLoad) break;
1096
1126
        }
1097
1127
    }
1098
1128
    /* can be out because readSize == 0, which could be an fread() error */
1099
 
    if (ferror(srcFile)) EXM_THROW(67, "Read error");
 
1129
    if (ferror(srcFile)) END_PROCESS(67, "Read error");
1100
1130
 
1101
1131
    if (!prefs->testMode) LZ4IO_fwriteSparseEnd(dstFile, storedSkips);
1102
 
    if (nextToLoad!=0) EXM_THROW(68, "Unfinished stream");
 
1132
    if (nextToLoad!=0) END_PROCESS(68, "Unfinished stream");
1103
1133
 
1104
1134
    return filesize;
1105
1135
}
1123
1153
    unsigned storedSkips = 0;
1124
1154
 
1125
1155
    if (fwrite(MNstore, 1, MAGICNUMBER_SIZE, foutput) != MAGICNUMBER_SIZE) {
1126
 
        EXM_THROW(50, "Pass-through write error");
 
1156
        END_PROCESS(50, "Pass-through write error");
1127
1157
    }
1128
1158
    while (readBytes) {
1129
1159
        readBytes = fread(buffer, 1, sizeof(buffer), finput);
1130
1160
        total += readBytes;
1131
1161
        storedSkips = LZ4IO_fwriteSparse(foutput, buffer, readBytes, sparseFileSupport, storedSkips);
1132
1162
    }
1133
 
    if (ferror(finput)) EXM_THROW(51, "Read Error");
 
1163
    if (ferror(finput)) END_PROCESS(51, "Read Error");
1134
1164
 
1135
1165
    LZ4IO_fwriteSparseEnd(foutput, storedSkips);
1136
1166
    return total;
1137
1167
}
1138
1168
 
 
1169
/* when fseek() doesn't work (pipe scenario),
 
1170
 * read and forget from input.
 
1171
**/
 
1172
#define SKIP_BUFF_SIZE (16 KB)
 
1173
#define MIN(a,b)   ( ((a)<(b)) ? (a) : (b) )
 
1174
static int skipStream(FILE* f, unsigned offset)
 
1175
{
 
1176
    char buf[SKIP_BUFF_SIZE];
 
1177
    while (offset > 0) {
 
1178
        size_t const tr = MIN(offset, sizeof(buf));
 
1179
        size_t const r = fread(buf, 1, tr, f);
 
1180
        if (r != tr) return 1; /* error reading f */
 
1181
        offset -= (unsigned)tr;
 
1182
    }
 
1183
    assert(offset == 0);
 
1184
    return 0;
 
1185
}
1139
1186
 
1140
1187
/** Safely handle cases when (unsigned)offset > LONG_MAX */
1141
1188
static int fseek_u32(FILE *fp, unsigned offset, int where)
1147
1194
    while (offset > 0) {
1148
1195
        unsigned s = offset;
1149
1196
        if (s > stepMax) s = stepMax;
1150
 
        errorNb = UTIL_fseek(fp, (long) s, SEEK_CUR);
1151
 
        if (errorNb != 0) break;
1152
 
        offset -= s;
 
1197
        errorNb = UTIL_fseek(fp, (long)s, SEEK_CUR);
 
1198
        if (errorNb==0) { offset -= s; continue; }
 
1199
        errorNb = skipStream(fp, offset);
 
1200
        offset = 0;
1153
1201
    }
1154
1202
    return errorNb;
1155
1203
}
1156
1204
 
 
1205
 
1157
1206
#define ENDOFSTREAM ((unsigned long long)-1)
 
1207
#define DECODING_ERROR ((unsigned long long)-2)
1158
1208
static unsigned long long
1159
1209
selectDecoder(dRess_t ress,
1160
1210
              FILE* finput, FILE* foutput,
1175
1225
        size_t const nbReadBytes = fread(MNstore, 1, MAGICNUMBER_SIZE, finput);
1176
1226
        if (nbReadBytes==0) { nbFrames = 0; return ENDOFSTREAM; }   /* EOF */
1177
1227
        if (nbReadBytes != MAGICNUMBER_SIZE)
1178
 
          EXM_THROW(40, "Unrecognized header : Magic Number unreadable");
 
1228
          END_PROCESS(40, "Unrecognized header : Magic Number unreadable");
1179
1229
        magicNumber = LZ4IO_readLE32(MNstore);   /* Little Endian format */
1180
1230
    }
1181
1231
    if (LZ4IO_isSkippableMagicNumber(magicNumber))
1192
1242
        DISPLAYLEVEL(4, "Skipping detected skippable area \n");
1193
1243
        {   size_t const nbReadBytes = fread(MNstore, 1, 4, finput);
1194
1244
            if (nbReadBytes != 4)
1195
 
                EXM_THROW(42, "Stream error : skippable size unreadable");
 
1245
                END_PROCESS(42, "Stream error : skippable size unreadable");
1196
1246
        }
1197
1247
        {   unsigned const size = LZ4IO_readLE32(MNstore);
1198
1248
            int const errorNb = fseek_u32(finput, size, SEEK_CUR);
1199
1249
            if (errorNb != 0)
1200
 
                EXM_THROW(43, "Stream error : cannot skip skippable area");
 
1250
                END_PROCESS(43, "Stream error : cannot skip skippable area");
1201
1251
        }
1202
1252
        return 0;
1203
 
    EXTENDED_FORMAT;  /* macro extension for custom formats */
1204
1253
    default:
1205
1254
        if (nbFrames == 1) {  /* just started */
1206
1255
            /* Wrong magic number at the beginning of 1st stream */
1208
1257
                nbFrames = 0;
1209
1258
                return LZ4IO_passThrough(finput, foutput, MNstore, prefs->sparseFileSupport);
1210
1259
            }
1211
 
            EXM_THROW(44,"Unrecognized header : file cannot be decoded");
 
1260
            END_PROCESS(44,"Unrecognized header : file cannot be decoded");
1212
1261
        }
1213
1262
        {   long int const position = ftell(finput);  /* only works for files < 2 GB */
1214
1263
            DISPLAYLEVEL(2, "Stream followed by undecodable data ");
1216
1265
                DISPLAYLEVEL(2, "at position %i ", (int)position);
1217
1266
            DISPLAYLEVEL(2, "\n");
1218
1267
        }
1219
 
        return ENDOFSTREAM;
 
1268
        return DECODING_ERROR;
1220
1269
    }
1221
1270
}
1222
1271
 
1228
1277
{
1229
1278
    FILE* const foutput = ress.dstFile;
1230
1279
    unsigned long long filesize = 0;
 
1280
    int result = 0;
1231
1281
 
1232
1282
    /* Init */
1233
1283
    FILE* const finput = LZ4IO_openSrcFile(input_filename);
1239
1289
        unsigned long long const decodedSize =
1240
1290
                        selectDecoder(ress, finput, foutput, prefs);
1241
1291
        if (decodedSize == ENDOFSTREAM) break;
 
1292
        if (decodedSize == DECODING_ERROR) { result=1; break; }
1242
1293
        filesize += decodedSize;
1243
1294
    }
1244
1295
 
1246
1297
    fclose(finput);
1247
1298
    if (prefs->removeSrcFile) {  /* --rm */
1248
1299
        if (remove(input_filename))
1249
 
            EXM_THROW(45, "Remove error : %s: %s", input_filename, strerror(errno));
 
1300
            END_PROCESS(45, "Remove error : %s: %s", input_filename, strerror(errno));
1250
1301
    }
1251
1302
 
1252
1303
    /* Final Status */
1254
1305
    DISPLAYLEVEL(2, "%-20.20s : decoded %llu bytes \n", input_filename, filesize);
1255
1306
    (void)output_filename;
1256
1307
 
1257
 
    return 0;
 
1308
    return result;
1258
1309
}
1259
1310
 
1260
1311
 
1263
1314
                        const char* input_filename, const char* output_filename,
1264
1315
                        const LZ4IO_prefs_t* const prefs)
1265
1316
{
 
1317
    int result;
1266
1318
    stat_t statbuf;
1267
1319
    int stat_result = 0;
1268
1320
    FILE* const foutput = LZ4IO_openDstFile(output_filename, prefs);
1269
1321
    if (foutput==NULL) return 1;   /* failure */
1270
1322
 
1271
 
    if ( strcmp(input_filename, stdinmark)
 
1323
    if ( !LZ4IO_isStdin(input_filename)
1272
1324
      && UTIL_getFileStat(input_filename, &statbuf))
1273
1325
        stat_result = 1;
1274
1326
 
1275
1327
    ress.dstFile = foutput;
1276
 
    LZ4IO_decompressSrcFile(ress, input_filename, output_filename, prefs);
 
1328
    result = LZ4IO_decompressSrcFile(ress, input_filename, output_filename, prefs);
1277
1329
 
1278
1330
    fclose(foutput);
1279
1331
 
1280
1332
    /* Copy owner, file permissions and modification time */
1281
1333
    if ( stat_result != 0
1282
 
      && strcmp (output_filename, stdoutmark)
1283
 
      && strcmp (output_filename, nulmark)) {
 
1334
      && !LZ4IO_isStdout(output_filename)
 
1335
      && !LZ4IO_isDevNull(output_filename)) {
1284
1336
        UTIL_setFileStat(output_filename, &statbuf);
1285
1337
        /* should return value be read ? or is silent fail good enough ? */
1286
1338
    }
1287
1339
 
1288
 
    return 0;
 
1340
    return result;
1289
1341
}
1290
1342
 
1291
1343
 
 
1344
/* Note : LZ4IO_decompressFilename()
 
1345
 * can provide total decompression time for the specified fileName.
 
1346
 * This information is not available with LZ4IO_decompressMultipleFilenames().
 
1347
 */
1292
1348
int LZ4IO_decompressFilename(const char* input_filename, const char* output_filename, const LZ4IO_prefs_t* prefs)
1293
1349
{
1294
1350
    dRess_t const ress = LZ4IO_createDResources(prefs);
1295
1351
    clock_t const start = clock();
1296
1352
 
1297
 
    int const missingFiles = LZ4IO_decompressDstFile(ress, input_filename, output_filename, prefs);
 
1353
    int const status = LZ4IO_decompressDstFile(ress, input_filename, output_filename, prefs);
1298
1354
 
1299
1355
    clock_t const end = clock();
1300
1356
    double const seconds = (double)(end - start) / CLOCKS_PER_SEC;
1301
1357
    DISPLAYLEVEL(4, "Done in %.2f sec  \n", seconds);
1302
1358
 
1303
1359
    LZ4IO_freeDResources(ress);
1304
 
    return missingFiles;
 
1360
    return status;
1305
1361
}
1306
1362
 
1307
1363
 
1318
1374
    size_t const suffixSize = strlen(suffix);
1319
1375
    dRess_t ress = LZ4IO_createDResources(prefs);
1320
1376
 
1321
 
    if (outFileName==NULL) EXM_THROW(70, "Memory allocation error");
 
1377
    if (outFileName==NULL) END_PROCESS(70, "Memory allocation error");
 
1378
    if (prefs->blockChecksum==0 && prefs->streamChecksum==0) {
 
1379
        DISPLAYLEVEL(4, "disabling checksum validation during decoding \n");
 
1380
    }
1322
1381
    ress.dstFile = LZ4IO_openDstFile(stdoutmark, prefs);
1323
1382
 
1324
1383
    for (i=0; i<ifntSize; i++) {
1325
1384
        size_t const ifnSize = strlen(inFileNamesTable[i]);
1326
1385
        const char* const suffixPtr = inFileNamesTable[i] + ifnSize - suffixSize;
1327
 
        if (!strcmp(suffix, stdoutmark)) {
1328
 
            missingFiles += LZ4IO_decompressSrcFile(ress, inFileNamesTable[i], stdoutmark, prefs);
 
1386
        if (LZ4IO_isStdout(suffix) || LZ4IO_isDevNull(suffix)) {
 
1387
            missingFiles += LZ4IO_decompressSrcFile(ress, inFileNamesTable[i], suffix, prefs);
1329
1388
            continue;
1330
1389
        }
1331
1390
        if (ofnSize <= ifnSize-suffixSize+1) {
1332
1391
            free(outFileName);
1333
1392
            ofnSize = ifnSize + 20;
1334
1393
            outFileName = (char*)malloc(ofnSize);
1335
 
            if (outFileName==NULL) EXM_THROW(71, "Memory allocation error");
 
1394
            if (outFileName==NULL) END_PROCESS(71, "Memory allocation error");
1336
1395
        }
1337
 
        if (ifnSize <= suffixSize  ||  strcmp(suffixPtr, suffix) != 0) {
 
1396
        if (ifnSize <= suffixSize  || !UTIL_sameString(suffixPtr, suffix) ) {
1338
1397
            DISPLAYLEVEL(1, "File extension doesn't match expected LZ4_EXTENSION (%4s); will not process file: %s\n", suffix, inFileNamesTable[i]);
1339
1398
            skippedFiles++;
1340
1399
            continue;
1387
1446
/* Read block headers and skip block data
1388
1447
   Return total blocks size for this frame including block headers,
1389
1448
   block checksums and content checksums.
1390
 
   returns 0 in case it can't succesfully skip block data.
 
1449
   returns 0 in case it can't successfully skip block data.
1391
1450
   Assumes SEEK_CUR after frame header.
1392
1451
 */
1393
1452
static unsigned long long
1424
1483
    return totalBlocksSize;
1425
1484
}
1426
1485
 
 
1486
static const unsigned long long legacyFrameUndecodable = (0ULL-1);
1427
1487
/* For legacy frames only.
1428
1488
   Read block headers and skip block data.
1429
1489
   Return total blocks size for this frame including block headers.
1430
 
   or 0 in case it can't succesfully skip block data.
 
1490
   or legacyFrameUndecodable in case it can't successfully skip block data.
1431
1491
   This works as long as legacy block header size = magic number size.
1432
1492
   Assumes SEEK_CUR after frame header.
1433
1493
 */
1434
1494
static unsigned long long LZ4IO_skipLegacyBlocksData(FILE* finput)
1435
1495
{
1436
 
    unsigned char blockInfo[LZIO_LEGACY_BLOCK_HEADER_SIZE];
 
1496
    unsigned char blockInfo[LZ4IO_LEGACY_BLOCK_HEADER_SIZE];
1437
1497
    unsigned long long totalBlocksSize = 0;
1438
 
    LZ4IO_STATIC_ASSERT(LZIO_LEGACY_BLOCK_HEADER_SIZE == MAGICNUMBER_SIZE);
 
1498
    LZ4IO_STATIC_ASSERT(LZ4IO_LEGACY_BLOCK_HEADER_SIZE == MAGICNUMBER_SIZE);
1439
1499
    for (;;) {
1440
 
        if (!fread(blockInfo, 1, LZIO_LEGACY_BLOCK_HEADER_SIZE, finput)) {
 
1500
        size_t const bhs = fread(blockInfo, 1, LZ4IO_LEGACY_BLOCK_HEADER_SIZE, finput);
 
1501
        if (bhs == 0) {
1441
1502
            if (feof(finput)) return totalBlocksSize;
1442
 
            return 0;
 
1503
            return legacyFrameUndecodable;
 
1504
        }
 
1505
        if (bhs != 4) {
 
1506
            return legacyFrameUndecodable;
1443
1507
        }
1444
1508
        {   const unsigned int nextCBlockSize = LZ4IO_readLE32(&blockInfo);
1445
 
            if ( nextCBlockSize == LEGACY_MAGICNUMBER ||
1446
 
                    nextCBlockSize == LZ4IO_MAGICNUMBER ||
1447
 
                    LZ4IO_isSkippableMagicNumber(nextCBlockSize)) {
1448
 
                /* Rewind back. we want cursor at the begining of next frame.*/
1449
 
                if (fseek(finput, -LZIO_LEGACY_BLOCK_HEADER_SIZE, SEEK_CUR) != 0) {
1450
 
                    return 0;
 
1509
            if ( nextCBlockSize == LEGACY_MAGICNUMBER
 
1510
              || nextCBlockSize == LZ4IO_MAGICNUMBER
 
1511
              || LZ4IO_isSkippableMagicNumber(nextCBlockSize) ) {
 
1512
                /* Rewind back. we want cursor at the beginning of next frame */
 
1513
                if (UTIL_fseek(finput, -LZ4IO_LEGACY_BLOCK_HEADER_SIZE, SEEK_CUR) != 0) {
 
1514
                    END_PROCESS(37, "impossible to skip backward");
1451
1515
                }
1452
1516
                break;
1453
1517
            }
1454
 
            totalBlocksSize += LZIO_LEGACY_BLOCK_HEADER_SIZE + nextCBlockSize;
1455
 
            /* skip to the next block */
 
1518
            if (nextCBlockSize > LZ4IO_LEGACY_BLOCK_SIZE_MAX) {
 
1519
                DISPLAYLEVEL(4, "Error : block in legacy frame is too large \n");
 
1520
                return legacyFrameUndecodable;
 
1521
            }
 
1522
            totalBlocksSize += LZ4IO_LEGACY_BLOCK_HEADER_SIZE + nextCBlockSize;
 
1523
            /* skip to the next block
 
1524
             * note : this won't fail if nextCBlockSize is too large, skipping past the end of finput */
1456
1525
            if (UTIL_fseek(finput, nextCBlockSize, SEEK_CUR) != 0) {
1457
 
                return 0;
 
1526
                return legacyFrameUndecodable;
1458
1527
    }   }   }
1459
1528
    return totalBlocksSize;
1460
1529
}
1514
1583
            if (nbReadBytes == 0) { break; } /* EOF */
1515
1584
            result = LZ4IO_format_not_known;  /* default result (error) */
1516
1585
            if (nbReadBytes != MAGICNUMBER_SIZE) {
1517
 
                EXM_THROW(40, "Unrecognized header : Magic Number unreadable");
 
1586
                END_PROCESS(40, "Unrecognized header : Magic Number unreadable");
1518
1587
        }   }
1519
1588
        magicNumber = LZ4IO_readLE32(buffer);   /* Little Endian format */
1520
1589
        if (LZ4IO_isSkippableMagicNumber(magicNumber))
1525
1594
            if (cfinfo->frameSummary.frameType != lz4Frame) cfinfo->eqFrameTypes = 0;
1526
1595
            /* Get frame info */
1527
1596
            {   const size_t readBytes = fread(buffer + MAGICNUMBER_SIZE, 1, LZ4F_HEADER_SIZE_MIN - MAGICNUMBER_SIZE, finput);
1528
 
                if (!readBytes || ferror(finput)) EXM_THROW(71, "Error reading %s", input_filename);
 
1597
                if (!readBytes || ferror(finput)) END_PROCESS(71, "Error reading %s", input_filename);
1529
1598
            }
1530
1599
            {   size_t hSize = LZ4F_headerSize(&buffer, LZ4F_HEADER_SIZE_MIN);
1531
1600
                if (LZ4F_isError(hSize)) break;
1532
1601
                if (hSize > (LZ4F_HEADER_SIZE_MIN + MAGICNUMBER_SIZE)) {
1533
1602
                    /* We've already read LZ4F_HEADER_SIZE_MIN so read any extra until hSize*/
1534
1603
                    const size_t readBytes = fread(buffer + LZ4F_HEADER_SIZE_MIN, 1, hSize - LZ4F_HEADER_SIZE_MIN, finput);
1535
 
                    if (!readBytes || ferror(finput)) EXM_THROW(72, "Error reading %s", input_filename);
 
1604
                    if (!readBytes || ferror(finput)) END_PROCESS(72, "Error reading %s", input_filename);
1536
1605
                }
1537
1606
                /* Create decompression context */
1538
1607
                {   LZ4F_dctx* dctx;
1578
1647
            cfinfo->eqBlockTypes = 0;
1579
1648
            cfinfo->allContentSize = 0;
1580
1649
            {   const unsigned long long totalBlocksSize = LZ4IO_skipLegacyBlocksData(finput);
 
1650
                if (totalBlocksSize == legacyFrameUndecodable) {
 
1651
                    DISPLAYLEVEL(1, "Corrupted legacy frame \n");
 
1652
                    result = LZ4IO_format_not_known;
 
1653
                    break;
 
1654
                }
1581
1655
                if (totalBlocksSize) {
1582
1656
                    DISPLAYLEVEL(3, "    %6llu %14s %5s %8s %20llu %20s %9s\n",
1583
1657
                                 cfinfo->frameCount + 1,
1595
1669
            cfinfo->allContentSize = 0;
1596
1670
            {   size_t const nbReadBytes = fread(buffer, 1, 4, finput);
1597
1671
                if (nbReadBytes != 4)
1598
 
                    EXM_THROW(42, "Stream error : skippable size unreadable");
 
1672
                    END_PROCESS(42, "Stream error : skippable size unreadable");
1599
1673
            }
1600
1674
            {   unsigned const size = LZ4IO_readLE32(buffer);
1601
1675
                int const errorNb = fseek_u32(finput, size, SEEK_CUR);
1602
1676
                if (errorNb != 0)
1603
 
                    EXM_THROW(43, "Stream error : cannot skip skippable area");
 
1677
                    END_PROCESS(43, "Stream error : cannot skip skippable area");
1604
1678
                DISPLAYLEVEL(3, "    %6llu %14s %5s %8s %20u %20s %9s\n",
1605
1679
                             cfinfo->frameCount + 1,
1606
1680
                             "SkippableFrame",
1614
1688
                DISPLAYLEVEL(3, "Stream followed by undecodable data ");
1615
1689
                if (position != -1L)
1616
1690
                    DISPLAYLEVEL(3, "at position %i ", (int)position);
 
1691
                result = LZ4IO_format_not_known;
1617
1692
                DISPLAYLEVEL(3, "\n");
1618
1693
            }
1619
1694
        break;
1639
1714
        /* Get file info */
1640
1715
        LZ4IO_cFileInfo_t cfinfo = LZ4IO_INIT_CFILEINFO;
1641
1716
        cfinfo.fileName = LZ4IO_baseName(inFileNames[idx]);
1642
 
        if (!UTIL_isRegFile(inFileNames[idx])) {
 
1717
        if (LZ4IO_isStdin(inFileNames[idx]) ? !UTIL_isRegFD(0) : !UTIL_isRegFile(inFileNames[idx])) {
1643
1718
            DISPLAYLEVEL(1, "lz4: %s is not a regular file \n", inFileNames[idx]);
1644
 
            return 0;
 
1719
            return 1;
1645
1720
        }
1646
1721
        DISPLAYLEVEL(3, "%s(%llu/%llu)\n", cfinfo.fileName, (unsigned long long)idx + 1, (unsigned  long long)ifnIdx);
1647
1722
        DISPLAYLEVEL(3, "    %6s %14s %5s %8s %20s %20s %9s\n",
1650
1725
            if (op_result != LZ4IO_LZ4F_OK) {
1651
1726
                assert(op_result == LZ4IO_format_not_known);
1652
1727
                DISPLAYLEVEL(1, "lz4: %s: File format not recognized \n", inFileNames[idx]);
1653
 
                return 0;
 
1728
                return 1;
1654
1729
        }   }
1655
1730
        DISPLAYLEVEL(3, "\n");
1656
1731
        if (g_displayLevel < 3) {