text: /*====================================================================*
   -  Copyright (C) 2001 Leptonica.  All rights reserved.
   -
   -  Redistribution and use in source and binary forms, with or without
   -  modification, are permitted provided that the following conditions
   -  are met:
   -  1. Redistributions of source code must retain the above copyright
   -     notice, this list of conditions and the following disclaimer.
   -  2. Redistributions in binary form must reproduce the above
   -     copyright notice, this list of conditions and the following
   -     disclaimer in the documentation and/or other materials
   -     provided with the distribution.
   -
   -  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   -  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   -  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   -  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ANY
   -  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   -  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   -  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   -  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
   -  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   -  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   -  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *====================================================================*/
  
  /*
   * corrupttest.c
   *
   *     Excises or permutes a given fraction of bytes, starting from
   *     a specified location.  The parameters @loc and @size are fractions
   *     of the entire file (between 0.0 and 1.0).
   *
   *     Syntax:  corrupttest <file> <deletion> [loc size]
   *
   *        where <deletion> == 1 means that bytes are deleted
   *              <deletion> == 0 means that random bytes are substituted
   *
   *     Use: "fuzz testing" jpeg, png, tiff, bmp, webp and pnm reading,
   *          under corruption by either random byte substitution or
   *          deletion of part of the compressed file.
   *
   *     For example,
   *          corrupttest rabi.png 0 0.0001 0.0001
   *     which tests read functions on rabi.png after 23 bytes (0.01%)
   *     starting at byte 23 have been randomly permuted, emits the following:
   *      > Info in fileCorruptByMutation: Randomizing 23 bytes at location 23
   *      > libpng error: IHDR: CRC error
   *      > Error in pixReadMemPng: internal png error
   *      > Error in pixReadStream: png: no pix returned
   *      > Error in pixRead: pix not read
   *      > libpng error: IHDR: CRC error
   *      > Error in fgetPngResolution: internal png error
   */
  
  #include "string.h"
  #include "allheaders.h"
  
  static const char *corruptfile = "/tmp/lept/corrupt/badfile";
  
  int main(int     argc,
           char  **argv)
  {
  size_t       filesize;
  l_float32    loc, size;
  l_float32    coeff1[15], coeff2[25];
  l_int32      i, j, w, xres, yres, format, ret, nwarn, hint, deletion, show;
  l_uint8     *comment, *filedata;
  char        *filein;
  size_t       nbytes;
  FILE        *fp;
  PIX         *pix;
  static char  mainName[] = "corrupttest";
  
      if (argc != 3 && argc != 5)
          return ERROR_INT("syntax: corrupttest filein deletion [loc size]",
          mainName, 1);
      filein = argv[1];
      deletion = atoi(argv[2]);
      findFileFormat(filein, &format);
      nbytes = nbytesInFile(filein);
      fprintf(stderr, "file size: %lu bytes\n", (unsigned long)nbytes);
  
      setLeptDebugOK(1);
      lept_mkdir("lept/corrupt");
  
      hint = 0;
      if (argc == 5) {  /* Single test */
          loc = atof(argv[3]);
          size = atof(argv[4]);
          if (deletion == TRUE) {
              fileCorruptByDeletion(filein, loc, size, corruptfile);
          } else {  /* mutation */
              fileCorruptByMutation(filein, loc, size, corruptfile);
          }
          fp = fopenReadStream(corruptfile);
          if (format == IFF_JFIF_JPEG) {
              if ((pix = pixReadJpeg(corruptfile, 0, 1, &nwarn, hint)) != NULL) {
                  pixDisplay(pix, 100, 100);
                  pixDestroy(&pix);
              }
              freadHeaderJpeg(fp, &w, NULL, NULL, NULL, NULL);
              fgetJpegResolution(fp, &xres, &yres);
              ret = fgetJpegComment(fp, &comment);
              if (!ret && comment) {
                  fprintf(stderr, "comment: %s\n", comment);
                  lept_free(comment);
              }
          } else if (format == IFF_PNG) {
              if ((pix = pixRead(corruptfile)) != NULL) {
                  pixDisplay(pix, 100, 100);
                  pixDestroy(&pix);
              }
              freadHeaderPng(fp, &w, NULL, NULL, NULL, NULL);
              fgetPngResolution(fp, &xres, &yres);
          } else if (format == IFF_WEBP) {
              if ((pix = pixRead(corruptfile)) != NULL) {
                  pixDisplay(pix, 100, 100);
                  pixDestroy(&pix);
              }
              readHeaderWebP(corruptfile, &w, NULL, NULL);
          } else if (format == IFF_PNM) {
              if ((pix = pixRead(corruptfile)) != NULL) {
                  pixDisplay(pix, 100, 100);
                  pixDestroy(&pix);
              }
              freadHeaderPnm(fp, &w, NULL, NULL, NULL, NULL, NULL);
          }
          fclose(fp);
          return 0;
      }
  
          /* Generate coefficients so that the size of the mangled
           * or deleted data can range from 0.001% to 1% of the file,
           * and the location of deleted data ranges from 0.001%
           * to 90% of the file. */
      for (i = 0; i < 15; i++) {
          if (i < 5) coeff1[i] = 0.00001;
          else if (i < 10) coeff1[i] = 0.0001;
          else coeff1[i] = 0.001;
      }
      for (i = 0; i < 25; i++) {
          if (i < 5) coeff2[i] = 0.00001;
          else if (i < 10) coeff2[i] = 0.0001;
          else if (i < 15) coeff2[i] = 0.001;
          else if (i < 20) coeff2[i] = 0.01;
          else coeff2[i] = 0.1;
      }
   
          /* Multiple test (argc == 3) */
      show = TRUE;
      for (i = 0; i < 25; i++) {
          loc = coeff2[i] * (2 * (i % 5) + 1);
          for (j = 0; j < 15; j++) {
              size = coeff1[j] * (2 * (j % 5) + 1);
  
                  /* Write corrupt file */
              if (deletion == TRUE) {
                  fileCorruptByDeletion(filein, loc, size, corruptfile);
              } else {
                  fileCorruptByMutation(filein, loc, size, corruptfile);
              }
  
                  /* Attempt to read the file */
              pix = NULL;
              if (format == IFF_JFIF_JPEG) {
                  /* The pix is usually returned as long as the header
                   * information is not damaged.
                   * We expect nwarn > 0 (typically 1) for nearly every
                   * corrupted image.  In the situation where only a few
                   * bytes are removed, a corrupted image will occasionally
                   * have nwarn == 0 even though it's visually defective.  */
                  pix = pixReadJpeg(corruptfile, 0, 1, &nwarn, 0);
                  if (pix && nwarn != 1 && deletion == TRUE) {
                      fprintf(stderr, "nwarn[%d,%d] = %d\n", j, i, nwarn);
                      if (show) pixDisplay(pix, 20 * i, 30 * j);
                      show = FALSE;
                  }
              } else if (format == IFF_PNG) {
                  pix = pixRead(corruptfile);
                  if (pix) {
                      fprintf(stderr, "pix[%d,%d] is read\n", j, i);
                      if (show) pixDisplay(pix, 20 * i, 30 * j);
                      show = FALSE;
                  }
                  pixDestroy(&pix);
                  filedata = l_binaryRead(corruptfile, &filesize);
                  pix = pixReadMemPng(filedata, filesize);
                  lept_free(filedata);
              } else if (format == IFF_TIFF || format == IFF_TIFF_PACKBITS ||
                         format == IFF_TIFF_RLE || format == IFF_TIFF_G3 ||
                         format == IFF_TIFF_G4 || format == IFF_TIFF_LZW ||
                         format == IFF_TIFF_ZIP) {
                  /* A corrupted pix is often returned, as long as the
                   * header is not damaged, so we do not display them.  */
                  pix = pixRead(corruptfile);
                  if (pix) fprintf(stderr, "pix[%d,%d] is read\n", j, i);
                  pixDestroy(&pix);
                  filedata = l_binaryRead(corruptfile, &filesize);
                  pix = pixReadMemTiff(filedata, filesize, 0);
                  if (!pix) fprintf(stderr, "no pix!\n");
                  lept_free(filedata);
              } else if (format == IFF_BMP) {
                  /* A corrupted pix is always returned if the header is
                   * not damaged, so we do not display them.  */
                  pix = pixRead(corruptfile);
                  if (pix) fprintf(stderr, "pix[%d,%d] is read\n", j, i);
                  pixDestroy(&pix);
                  filedata = l_binaryRead(corruptfile, &filesize);
                  pix = pixReadMemBmp(filedata, filesize);
                  lept_free(filedata);
              } else if (format == IFF_WEBP) {
                  /* A corrupted pix is always returned if the header is
                   * not damaged, so we do not display them.  */
                  pix = pixRead(corruptfile);
                  if (pix) fprintf(stderr, "pix[%d,%d] is read\n", j, i);
                  pixDestroy(&pix);
                  filedata = l_binaryRead(corruptfile, &filesize);
                  pix = pixReadMemWebP(filedata, filesize);
                  lept_free(filedata);
              } else if (format == IFF_PNM) {
                  /* A corrupted pix is always returned if the header is
                   * not damaged, so we do not display them.  */
                  pix = pixRead(corruptfile);
                  if (pix) fprintf(stderr, "pix[%d,%d] is read\n", j, i);
                  pixDestroy(&pix);
                  filedata = l_binaryRead(corruptfile, &filesize);
                  pix = pixReadMemPnm(filedata, filesize);
                  lept_free(filedata);
              } else {
                  fprintf(stderr, "Format %d unknown\n", format);
                  continue;
              }
  
                  /* Effect of 1% byte mangling from interior of data stream */
              if (pix && j == 14 && i == 10 && deletion == FALSE)
                  pixDisplay(pix, 0, 0);
              pixDestroy(&pix);
  
                  /* Attempt to read the header and the resolution */
              fp = fopenReadStream(corruptfile);
              if (format == IFF_JFIF_JPEG) {
                  freadHeaderJpeg(fp, &w, NULL, NULL, NULL, NULL);
                  if (fgetJpegResolution(fp, &xres, &yres) == 0)
                      fprintf(stderr, "w = %d, xres = %d, yres = %d\n",
                      w, xres, yres);
              } else if (format == IFF_PNG)  {
                  freadHeaderPng(fp, &w, NULL, NULL, NULL, NULL);
                  if (fgetPngResolution(fp, &xres, &yres) == 0)
                      fprintf(stderr, "w = %d, xres = %d, yres = %d\n",
                      w, xres, yres);
              } else if (format == IFF_TIFF || format == IFF_TIFF_PACKBITS ||
                         format == IFF_TIFF_RLE || format == IFF_TIFF_G3 ||
                         format == IFF_TIFF_G4 || format == IFF_TIFF_LZW ||
                         format == IFF_TIFF_ZIP) {
                  freadHeaderTiff(fp, 0, &w, NULL, NULL, NULL, NULL, NULL, NULL);
                  getTiffResolution(fp, &xres, &yres);
                  fprintf(stderr, "w = %d, xres = %d, yres = %d\n",
                          w, xres, yres);
              } else if (format == IFF_WEBP)  {
                  if (readHeaderWebP(corruptfile, &w, NULL, NULL) == 0)
                      fprintf(stderr, "w = %d\n", w);
              } else if (format == IFF_PNM)  {
                  if (freadHeaderPnm(fp, &w, NULL, NULL, NULL, NULL, NULL) == 0)
                      fprintf(stderr, "w = %d\n", w);
              }
              fclose(fp);
          }
      }
      return 0;
  }
  
  