getTiffStreamResolution(TIFF     *tif,
                        l_int32  *pxres,
                        l_int32  *pyres)
{
l_uint16   resunit;
l_int32    foundxres, foundyres;
l_float32  fxres, fyres;

    PROCNAME("getTiffStreamResolution");

    if (!tif)
        return ERROR_INT("tif not opened", procName, 1);
    if (!pxres || !pyres)
        return ERROR_INT("&xres and &yres not both defined", procName, 1);
    *pxres = *pyres = 0;

    TIFFGetFieldDefaulted(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
    foundxres = TIFFGetField(tif, TIFFTAG_XRESOLUTION, &fxres);
    foundyres = TIFFGetField(tif, TIFFTAG_YRESOLUTION, &fyres);
    if (!foundxres && !foundyres) return 1;
    if (isnan(fxres) || isnan(fyres)) return 1;
    if (!foundxres && foundyres)
        fxres = fyres;
    else if (foundxres && !foundyres)
        fyres = fxres;

        /* Avoid overflow into int32; set max fxres and fyres to 5 x 10^8 */
    if (fxres < 0 || fxres > (1L << 29) || fyres < 0 || fyres > (1L << 29))
        return ERROR_INT("fxres and/or fyres values are invalid", procName, 1);

    if (resunit == RESUNIT_CENTIMETER) {  /* convert to ppi */
        *pxres = (l_int32)(2.54 * fxres + 0.5);
        *pyres = (l_int32)(2.54 * fyres + 0.5);
    } else {
        *pxres = (l_int32)fxres;
        *pyres = (l_int32)fyres;
    }

    return 0;
}

static const l_int32  DefaultResolution = 300;

static const l_int32  ManyPagesInTiffFile = 3000;

static const l_int32  MaxTiffWidth = 1 << 20;

static const l_int32  MaxTiffHeight = 1 << 20;

static PIX      *pixReadFromTiffStream(TIFF *tif);

static l_int32   getTiffStreamResolution(TIFF *tif, l_int32 *pxres,
                                         l_int32 *pyres);

static l_int32   tiffReadHeaderTiff(TIFF *tif, l_int32 *pwidth,
                                    l_int32 *pheight, l_int32 *pbps,
                                    l_int32 *pspp, l_int32 *pres,
                                    l_int32 *pcmap, l_int32 *pformat);

static l_int32   writeCustomTiffTags(TIFF *tif, NUMA *natags,
                                     SARRAY *savals, SARRAY  *satypes,
                                     NUMA *nasizes);

static l_int32   pixWriteToTiffStream(TIFF *tif, PIX *pix, l_int32 comptype,
                                      NUMA *natags, SARRAY *savals,
                                      SARRAY *satypes, NUMA *nasizes);

static TIFF     *fopenTiff(FILE *fp, const char *modestring);

static TIFF     *openTiff(const char *filename, const char *modestring);

static l_int32   getTiffCompressedFormat(l_uint16 tiffcomp);

static TIFF     *fopenTiffMemstream(const char *filename, const char *operation,
                                    l_uint8 **pdata, size_t *pdatasize);

struct L_Memstream
{
    l_uint8   *buffer;    /* expands to hold data when written to;         */
                          /* fixed size when read from.                    */
    size_t     bufsize;   /* current size allocated when written to;       */
                          /* fixed size of input data when read from.      */
    size_t     offset;    /* byte offset from beginning of buffer.         */
    size_t     hw;        /* high-water mark; max bytes in buffer.         */
    l_uint8  **poutdata;  /* input param for writing; data goes here.      */
    size_t    *poutsize;  /* input param for writing; data size goes here. */
}

static toff_t tiffSeekCallback(thandle_t handle, toff_t offset, l_int32 whence);

static l_int32 tiffCloseCallback(thandle_t handle);

static l_int32 tiffMapCallback(thandle_t handle, tdata_t *data, toff_t *length);


tiffMapCallback(thandle_t  handle,
                tdata_t   *data,
                toff_t    *length)
{
L_MEMSTREAM  *mstream;

    mstream = (L_MEMSTREAM *)handle;
    *data = mstream->buffer;
    *length = mstream->hw;
    return 0;
}

Issue 23654 in oss-fuzz: Heap-buffer-overflow in pixReadFromTiffStream
  * Increase scanline buffer for reading gray+alpha and converting to RGBA

struct L_Memstream
{
    l_uint8   *buffer;    /* expands to hold data when written to;         */
                          /* fixed size when read from.                    */
    size_t     bufsize;   /* current size allocated when written to;       */
                          /* fixed size of input data when read from.      */
    size_t     offset;    /* byte offset from beginning of buffer.         */
    size_t     hw;        /* high-water mark; max bytes in buffer.         */
    l_uint8  **poutdata;  /* input param for writing; data goes here.      */
    size_t    *poutsize;  /* input param for writing; data size goes here. */
}

typedef struct L_Memstream  L_MEMSTREAM;

static L_MEMSTREAM *memstreamCreateForRead(l_uint8 *indata, size_t pinsize);

static L_MEMSTREAM *memstreamCreateForWrite(l_uint8 **poutdata,
                                            size_t *poutsize);

static tsize_t tiffReadCallback(thandle_t handle, tdata_t data, tsize_t length);

static tsize_t tiffWriteCallback(thandle_t handle, tdata_t data,
                                 tsize_t length);

static toff_t tiffSeekCallback(thandle_t handle, toff_t offset, l_int32 whence);

static l_int32 tiffCloseCallback(thandle_t handle);

static toff_t tiffSizeCallback(thandle_t handle);

static l_int32 tiffMapCallback(thandle_t handle, tdata_t *data, toff_t *length);

static void tiffUnmapCallback(thandle_t handle, tdata_t data, toff_t length);


pixReadStreamTiff(FILE    *fp,
                  l_int32  n)
{
PIX   *pix;
TIFF  *tif;

    PROCNAME("pixReadStreamTiff");

    if (!fp)
        return (PIX *)ERROR_PTR("stream not defined", procName, NULL);

    if ((tif = fopenTiff(fp, "r")) == NULL)
        return (PIX *)ERROR_PTR("tif not opened", procName, NULL);

    if (TIFFSetDirectory(tif, n) == 0) {
        TIFFCleanup(tif);
        return NULL;
    }
    if ((pix = pixReadFromTiffStream(tif)) == NULL) {
        TIFFCleanup(tif);
        return NULL;
    }
    TIFFCleanup(tif);
    return pix;
}

static const l_int32  DefaultResolution = 300;

static const l_int32  ManyPagesInTiffFile = 3000;

static const l_int32  MaxTiffWidth = 1 << 20;

static const l_int32  MaxTiffHeight = 1 << 20;

static PIX      *pixReadFromTiffStream(TIFF *tif);

static l_int32   getTiffStreamResolution(TIFF *tif, l_int32 *pxres,
                                         l_int32 *pyres);

static l_int32   tiffReadHeaderTiff(TIFF *tif, l_int32 *pwidth,
                                    l_int32 *pheight, l_int32 *pbps,
                                    l_int32 *pspp, l_int32 *pres,
                                    l_int32 *pcmap, l_int32 *pformat);

static l_int32   writeCustomTiffTags(TIFF *tif, NUMA *natags,
                                     SARRAY *savals, SARRAY  *satypes,
                                     NUMA *nasizes);

static l_int32   pixWriteToTiffStream(TIFF *tif, PIX *pix, l_int32 comptype,
                                      NUMA *natags, SARRAY *savals,
                                      SARRAY *satypes, NUMA *nasizes);

static TIFF     *fopenTiff(FILE *fp, const char *modestring);

static TIFF     *openTiff(const char *filename, const char *modestring);

static l_int32   getTiffCompressedFormat(l_uint16 tiffcomp);

static TIFF     *fopenTiffMemstream(const char *filename, const char *operation,
                                    l_uint8 **pdata, size_t *pdatasize);

static toff_t tiffSeekCallback(thandle_t handle, toff_t offset, l_int32 whence);

static l_int32 tiffCloseCallback(thandle_t handle);

static l_int32 tiffMapCallback(thandle_t handle, tdata_t *data, toff_t *length);


lept_write_proc(thandle_t  cookie,
                tdata_t    buff,
                tsize_t    size)
{
    FILE* fp = (FILE *)cookie;
    tsize_t done;
    if (!buff || !cookie || !fp)
        return (tsize_t)-1;
    done = fwrite(buff, 1, size, fp);
    return done;
}

static TIFF     *fopenTiff(FILE *fp, const char *modestring);

struct L_Memstream
{
    l_uint8   *buffer;    /* expands to hold data when written to;         */
                          /* fixed size when read from.                    */
    size_t     bufsize;   /* current size allocated when written to;       */
                          /* fixed size of input data when read from.      */
    size_t     offset;    /* byte offset from beginning of buffer.         */
    size_t     hw;        /* high-water mark; max bytes in buffer.         */
    l_uint8  **poutdata;  /* input param for writing; data goes here.      */
    size_t    *poutsize;  /* input param for writing; data size goes here. */
}

static tsize_t tiffReadCallback(thandle_t handle, tdata_t data, tsize_t length);

static tsize_t tiffWriteCallback(thandle_t handle, tdata_t data,
                                 tsize_t length);

static toff_t tiffSeekCallback(thandle_t handle, toff_t offset, l_int32 whence);

static l_int32 tiffCloseCallback(thandle_t handle);

static toff_t tiffSizeCallback(thandle_t handle);

static l_int32 tiffMapCallback(thandle_t handle, tdata_t *data, toff_t *length);

static void tiffUnmapCallback(thandle_t handle, tdata_t data, toff_t length);


pixWriteMemTiff(l_uint8  **pdata,
                size_t    *psize,
                PIX       *pix,
                l_int32    comptype)
{
    return pixWriteMemTiffCustom(pdata, psize, pix, comptype,
                                 NULL, NULL, NULL, NULL);
}

static const l_int32  DefaultResolution = 300;

static const l_int32  ManyPagesInTiffFile = 3000;

static const l_int32  MaxTiffWidth = 1 << 20;

static const l_int32  MaxTiffHeight = 1 << 20;

static PIX      *pixReadFromTiffStream(TIFF *tif);

static l_int32   getTiffStreamResolution(TIFF *tif, l_int32 *pxres,
                                         l_int32 *pyres);

static l_int32   tiffReadHeaderTiff(TIFF *tif, l_int32 *pwidth,
                                    l_int32 *pheight, l_int32 *pbps,
                                    l_int32 *pspp, l_int32 *pres,
                                    l_int32 *pcmap, l_int32 *pformat);

static l_int32   writeCustomTiffTags(TIFF *tif, NUMA *natags,
                                     SARRAY *savals, SARRAY  *satypes,
                                     NUMA *nasizes);

static l_int32   pixWriteToTiffStream(TIFF *tif, PIX *pix, l_int32 comptype,
                                      NUMA *natags, SARRAY *savals,
                                      SARRAY *satypes, NUMA *nasizes);

static l_int32   getTiffCompressedFormat(l_uint16 tiffcomp);

static TIFF     *fopenTiffMemstream(const char *filename, const char *operation,
                                    l_uint8 **pdata, size_t *pdatasize);

struct L_Memstream
{
    l_uint8   *buffer;    /* expands to hold data when written to;         */
                          /* fixed size when read from.                    */
    size_t     bufsize;   /* current size allocated when written to;       */
                          /* fixed size of input data when read from.      */
    size_t     offset;    /* byte offset from beginning of buffer.         */
    size_t     hw;        /* high-water mark; max bytes in buffer.         */
    l_uint8  **poutdata;  /* input param for writing; data goes here.      */
    size_t    *poutsize;  /* input param for writing; data size goes here. */
}

static L_MEMSTREAM *memstreamCreateForRead(l_uint8 *indata, size_t pinsize);

static L_MEMSTREAM *memstreamCreateForWrite(l_uint8 **poutdata,
                                            size_t *poutsize);

static toff_t tiffSeekCallback(thandle_t handle, toff_t offset, l_int32 whence);

static l_int32 tiffCloseCallback(thandle_t handle);

static l_int32 tiffMapCallback(thandle_t handle, tdata_t *data, toff_t *length);


pixReadFromTiffStream(TIFF  *tif)
{
char      *text;
l_uint8   *linebuf, *data, *rowptr;
l_uint16   spp, bps, photometry, tiffcomp, orientation, sample_fmt;
l_uint16  *redmap, *greenmap, *bluemap;
l_int32    d, wpl, bpl, comptype, i, j, k, ncolors, rval, gval, bval, aval;
l_int32    xres, yres, tiffbpl, packedbpl, halfsize;
l_uint32   w, h, tiffword, read_oriented;
l_uint32  *line, *ppixel, *tiffdata, *pixdata;
PIX       *pix, *pix1;
PIXCMAP   *cmap;

    PROCNAME("pixReadFromTiffStream");

    if (!tif)
        return (PIX *)ERROR_PTR("tif not defined", procName, NULL);

    read_oriented = 0;

        /* Only accept uint image data:
         *   SAMPLEFORMAT_UINT = 1;
         *   SAMPLEFORMAT_INT = 2;
         *   SAMPLEFORMAT_IEEEFP = 3;
         *   SAMPLEFORMAT_VOID = 4;   */
    TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLEFORMAT, &sample_fmt);
    if (sample_fmt != SAMPLEFORMAT_UINT) {
        L_ERROR("sample format = %d is not uint\n", procName, sample_fmt);
        return NULL;
    }

        /* Can't read tiff in tiled format. For what is involved, see, e.g:
         *   https://www.cs.rochester.edu/~nelson/courses/vision/\
         *     resources/tiff/libtiff.html#Tiles
         * A tiled tiff can be converted to a normal (strip) tif:
         *   tiffcp -s <input-tiled-tif> <output-strip-tif>    */
    if (TIFFIsTiled(tif)) {
        L_ERROR("tiled format is not supported\n", procName);
        return NULL;
    }

        /* Old style jpeg is not supported.  We tried supporting 8 bpp.
         * TIFFReadScanline() fails on this format, so we used RGBA
         * reading, which generates a 4 spp image, and pulled out the
         * red component.  However, there were problems with double-frees
         * in cleanup.  For RGB, tiffbpl is exactly half the size that
         * you would expect for the raster data in a scanline, which
         * is 3 * w.  */
    TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &tiffcomp);
    if (tiffcomp == COMPRESSION_OJPEG) {
        L_ERROR("old style jpeg format is not supported\n", procName);
        return NULL;
    }

        /* Use default fields for bps and spp */
    TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bps);
    TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
    if (bps != 1 && bps != 2 && bps != 4 && bps != 8 && bps != 16) {
        L_ERROR("invalid bps = %d\n", procName, bps);
        return NULL;
    }
    if (spp == 2 && bps != 8) {
        L_WARNING("for 2 spp, only handle 8 bps\n", procName);
        return NULL;
    }
    if (spp == 1)
        d = bps;
    else if (spp == 2)  /* gray plus alpha */
        d = 32;  /* will convert to RGBA */
    else if (spp == 3 || spp == 4)
        d = 32;
    else
        return (PIX *)ERROR_PTR("spp not in set {1,2,3,4}", procName, NULL);

    TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
    TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
    if (w > MaxTiffWidth) {
        L_ERROR("width = %d pixels; too large\n", procName, w);
        return NULL;
    }
    if (h > MaxTiffHeight) {
        L_ERROR("height = %d pixels; too large\n", procName, h);
        return NULL;
    }

        /* The relation between the size of a byte buffer required to hold
           a raster of image pixels (packedbpl) and the size of the tiff
           buffer (tiffbuf) is either 1:1 or approximately 2:1, depending
           on how the data is stored and subsampled.  Allow some slop
           when validating the relation between buffer size and the image
           parameters w, spp and bps. */
    tiffbpl = TIFFScanlineSize(tif);
    packedbpl = (bps * spp * w + 7) / 8;
    halfsize = L_ABS(2 * tiffbpl - packedbpl) <= 8;
#if 0
    if (halfsize)
        L_INFO("packedbpl = %d is approx. twice tiffbpl = %d\n", procName,
               packedbpl, tiffbpl);
#endif
    if (tiffbpl != packedbpl && !halfsize) {
        L_ERROR("invalid tiffbpl: tiffbpl = %d, packedbpl = %d, "
                "bps = %d, spp = %d, w = %d\n",
                procName, tiffbpl, packedbpl, bps, spp, w);
        return NULL;
    }

    if ((pix = pixCreate(w, h, d)) == NULL)
        return (PIX *)ERROR_PTR("pix not made", procName, NULL);
    pixSetInputFormat(pix, IFF_TIFF);
    data = (l_uint8 *)pixGetData(pix);
    wpl = pixGetWpl(pix);
    bpl = 4 * wpl;

    if (spp == 1) {
        linebuf = (l_uint8 *)LEPT_CALLOC(tiffbpl + 1, sizeof(l_uint8));
        for (i = 0; i < h; i++) {
            if (TIFFReadScanline(tif, linebuf, i, 0) < 0) {
                LEPT_FREE(linebuf);
                pixDestroy(&pix);
                return (PIX *)ERROR_PTR("line read fail", procName, NULL);
            }
            memcpy(data, linebuf, tiffbpl);
            data += bpl;
        }
        if (bps <= 8)
            pixEndianByteSwap(pix);
        else   /* bps == 16 */
            pixEndianTwoByteSwap(pix);
        LEPT_FREE(linebuf);
    } else if (spp == 2 && bps == 8) {  /* gray plus alpha */
        L_INFO("gray+alpha is not supported; converting to RGBA\n", procName);
        pixSetSpp(pix, 4);
        linebuf = (l_uint8 *)LEPT_CALLOC(2 * tiffbpl + 1, sizeof(l_uint8));
        pixdata = pixGetData(pix);
        for (i = 0; i < h; i++) {
            if (TIFFReadScanline(tif, linebuf, i, 0) < 0) {
                LEPT_FREE(linebuf);
                pixDestroy(&pix);
                return (PIX *)ERROR_PTR("line read fail", procName, NULL);
            }
            rowptr = linebuf;
            ppixel = pixdata + i * wpl;
            for (j = k = 0; j < w; j++) {
                    /* Copy gray value into r, g and b */
                SET_DATA_BYTE(ppixel, COLOR_RED, rowptr[k]);
                SET_DATA_BYTE(ppixel, COLOR_GREEN, rowptr[k]);
                SET_DATA_BYTE(ppixel, COLOR_BLUE, rowptr[k++]);
                SET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL, rowptr[k++]);
                ppixel++;
            }
        }
        LEPT_FREE(linebuf);
    } else {  /* rgb and rgba */
        if ((tiffdata = (l_uint32 *)LEPT_CALLOC((size_t)w * h,
                                                 sizeof(l_uint32))) == NULL) {
            pixDestroy(&pix);
            return (PIX *)ERROR_PTR("calloc fail for tiffdata", procName, NULL);
        }
            /* TIFFReadRGBAImageOriented() converts to 8 bps */
        if (!TIFFReadRGBAImageOriented(tif, w, h, tiffdata,
                                       ORIENTATION_TOPLEFT, 0)) {
            LEPT_FREE(tiffdata);
            pixDestroy(&pix);
            return (PIX *)ERROR_PTR("failed to read tiffdata", procName, NULL);
        } else {
            read_oriented = 1;
        }

        if (spp == 4) pixSetSpp(pix, 4);
        line = pixGetData(pix);
        for (i = 0; i < h; i++, line += wpl) {
            for (j = 0, ppixel = line; j < w; j++) {
                    /* TIFFGet* are macros */
                tiffword = tiffdata[i * w + j];
                rval = TIFFGetR(tiffword);
                gval = TIFFGetG(tiffword);
                bval = TIFFGetB(tiffword);
                if (spp == 3) {
                    composeRGBPixel(rval, gval, bval, ppixel);
                } else {  /* spp == 4 */
                    aval = TIFFGetA(tiffword);
                    composeRGBAPixel(rval, gval, bval, aval, ppixel);
                }
                ppixel++;
            }
        }
        LEPT_FREE(tiffdata);
    }

    if (getTiffStreamResolution(tif, &xres, &yres) == 0) {
        pixSetXRes(pix, xres);
        pixSetYRes(pix, yres);
    }

        /* Find and save the compression type */
    comptype = getTiffCompressedFormat(tiffcomp);
    pixSetInputFormat(pix, comptype);

    if (TIFFGetField(tif, TIFFTAG_COLORMAP, &redmap, &greenmap, &bluemap)) {
            /* Save the colormap as a pix cmap.  Because the
             * tiff colormap components are 16 bit unsigned,
             * and go from black (0) to white (0xffff), the
             * the pix cmap takes the most significant byte. */
        if (bps > 8) {
            pixDestroy(&pix);
            return (PIX *)ERROR_PTR("colormap size > 256", procName, NULL);
        }
        if ((cmap = pixcmapCreate(bps)) == NULL) {
            pixDestroy(&pix);
            return (PIX *)ERROR_PTR("colormap not made", procName, NULL);
        }
        ncolors = 1 << bps;
        for (i = 0; i < ncolors; i++)
            pixcmapAddColor(cmap, redmap[i] >> 8, greenmap[i] >> 8,
                            bluemap[i] >> 8);
        if (pixSetColormap(pix, cmap)) {
            pixDestroy(&pix);
            return (PIX *)ERROR_PTR("invalid colormap", procName, NULL);
        }

            /* Remove the colormap for 1 bpp. */
        if (bps == 1) {
            pix1 = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
            pixDestroy(&pix);
            pix = pix1;
        }
    } else {   /* No colormap: check photometry and invert if necessary */
        if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometry)) {
                /* Guess default photometry setting.  Assume min_is_white
                 * if compressed 1 bpp; min_is_black otherwise. */
            if (tiffcomp == COMPRESSION_CCITTFAX3 ||
                tiffcomp == COMPRESSION_CCITTFAX4 ||
                tiffcomp == COMPRESSION_CCITTRLE ||
                tiffcomp == COMPRESSION_CCITTRLEW) {
                photometry = PHOTOMETRIC_MINISWHITE;
            } else {
                photometry = PHOTOMETRIC_MINISBLACK;
            }
        }
        if ((d == 1 && photometry == PHOTOMETRIC_MINISBLACK) ||
            (d == 8 && photometry == PHOTOMETRIC_MINISWHITE))
            pixInvert(pix, pix);
    }

    if (TIFFGetField(tif, TIFFTAG_ORIENTATION, &orientation)) {
        if (orientation >= 1 && orientation <= 8) {
            struct tiff_transform *transform = (read_oriented) ?
                &tiff_partial_orientation_transforms[orientation - 1] :
                &tiff_orientation_transforms[orientation - 1];
            if (transform->vflip) pixFlipTB(pix, pix);
            if (transform->hflip) pixFlipLR(pix, pix);
            if (transform->rotate) {
                PIX *oldpix = pix;
                pix = pixRotate90(oldpix, transform->rotate);
                pixDestroy(&oldpix);
            }
        }
    }

    text = NULL;
    TIFFGetField(tif, TIFFTAG_IMAGEDESCRIPTION, &text);
    if (text) pixSetText(pix, text);
    return pix;
}

static const l_int32  DefaultResolution = 300;

static const l_int32  ManyPagesInTiffFile = 3000;

static const l_int32  MaxTiffWidth = 1 << 20;

static const l_int32  MaxTiffHeight = 1 << 20;

static PIX      *pixReadFromTiffStream(TIFF *tif);

static l_int32   getTiffStreamResolution(TIFF *tif, l_int32 *pxres,
                                         l_int32 *pyres);

static l_int32   tiffReadHeaderTiff(TIFF *tif, l_int32 *pwidth,
                                    l_int32 *pheight, l_int32 *pbps,
                                    l_int32 *pspp, l_int32 *pres,
                                    l_int32 *pcmap, l_int32 *pformat);

static l_int32   writeCustomTiffTags(TIFF *tif, NUMA *natags,
                                     SARRAY *savals, SARRAY  *satypes,
                                     NUMA *nasizes);

static l_int32   pixWriteToTiffStream(TIFF *tif, PIX *pix, l_int32 comptype,
                                      NUMA *natags, SARRAY *savals,
                                      SARRAY *satypes, NUMA *nasizes);

static TIFF     *fopenTiff(FILE *fp, const char *modestring);

static TIFF     *openTiff(const char *filename, const char *modestring);

static l_int32   getTiffCompressedFormat(l_uint16 tiffcomp);

static TIFF     *fopenTiffMemstream(const char *filename, const char *operation,
                                    l_uint8 **pdata, size_t *pdatasize);

struct tiff_transform {
    int vflip;    /* if non-zero, image needs a vertical fip */
    int hflip;    /* if non-zero, image needs a horizontal flip */
    int rotate;   /* -1 -> counterclockwise 90-degree rotation,
                      0 -> no rotation
                      1 -> clockwise 90-degree rotation */
}

static struct tiff_transform tiff_orientation_transforms[] = {
    {0, 0, 0},
    {0, 1, 0},
    {1, 1, 0},
    {1, 0, 0},
    {0, 1, -1},
    {0, 0, 1},
    {0, 1, 1},
    {0, 0, -1}
};

static struct tiff_transform tiff_partial_orientation_transforms[] = {
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 1, -1},
    {0, 1, 1},
    {1, 0, 1},
    {0, 1, -1}
};

struct L_Memstream
{
    l_uint8   *buffer;    /* expands to hold data when written to;         */
                          /* fixed size when read from.                    */
    size_t     bufsize;   /* current size allocated when written to;       */
                          /* fixed size of input data when read from.      */
    size_t     offset;    /* byte offset from beginning of buffer.         */
    size_t     hw;        /* high-water mark; max bytes in buffer.         */
    l_uint8  **poutdata;  /* input param for writing; data goes here.      */
    size_t    *poutsize;  /* input param for writing; data size goes here. */
}


pixReadTiff(const char  *filename,
            l_int32      n)
{
FILE  *fp;
PIX   *pix;

    PROCNAME("pixReadTiff");

    if (!filename)
        return (PIX *)ERROR_PTR("filename not defined", procName, NULL);

    if ((fp = fopenReadStream(filename)) == NULL)
        return (PIX *)ERROR_PTR("image file not found", procName, NULL);
    pix = pixReadStreamTiff(fp, n);
    fclose(fp);
    return pix;
}

static const l_int32  DefaultResolution = 300;

static const l_int32  ManyPagesInTiffFile = 3000;

static const l_int32  MaxTiffWidth = 1 << 20;

static const l_int32  MaxTiffHeight = 1 << 20;

static PIX      *pixReadFromTiffStream(TIFF *tif);

static l_int32   getTiffStreamResolution(TIFF *tif, l_int32 *pxres,
                                         l_int32 *pyres);

static l_int32   tiffReadHeaderTiff(TIFF *tif, l_int32 *pwidth,
                                    l_int32 *pheight, l_int32 *pbps,
                                    l_int32 *pspp, l_int32 *pres,
                                    l_int32 *pcmap, l_int32 *pformat);

static l_int32   writeCustomTiffTags(TIFF *tif, NUMA *natags,
                                     SARRAY *savals, SARRAY  *satypes,
                                     NUMA *nasizes);

static l_int32   pixWriteToTiffStream(TIFF *tif, PIX *pix, l_int32 comptype,
                                      NUMA *natags, SARRAY *savals,
                                      SARRAY *satypes, NUMA *nasizes);

static TIFF     *fopenTiff(FILE *fp, const char *modestring);

static TIFF     *openTiff(const char *filename, const char *modestring);

static l_int32   getTiffCompressedFormat(l_uint16 tiffcomp);

static TIFF     *fopenTiffMemstream(const char *filename, const char *operation,
                                    l_uint8 **pdata, size_t *pdatasize);

struct tiff_transform {
    int vflip;    /* if non-zero, image needs a vertical fip */
    int hflip;    /* if non-zero, image needs a horizontal flip */
    int rotate;   /* -1 -> counterclockwise 90-degree rotation,
                      0 -> no rotation
                      1 -> clockwise 90-degree rotation */
}

static toff_t tiffSeekCallback(thandle_t handle, toff_t offset, l_int32 whence);

static l_int32 tiffCloseCallback(thandle_t handle);

static l_int32 tiffMapCallback(thandle_t handle, tdata_t *data, toff_t *length);


writeCustomTiffTags(TIFF    *tif,
                    NUMA    *natags,
                    SARRAY  *savals,
                    SARRAY  *satypes,
                    NUMA    *nasizes)
{
char      *sval, *type;
l_int32    i, n, ns, size, tagval, val;
l_float64  dval;
l_uint32   uval, uval2;

    PROCNAME("writeCustomTiffTags");

    if (!tif)
        return ERROR_INT("tif stream not defined", procName, 1);
    if (!natags && !savals && !satypes)
        return 0;
    if (!natags || !savals || !satypes)
        return ERROR_INT("not all arrays defined", procName, 1);
    n = numaGetCount(natags);
    if ((sarrayGetCount(savals) != n) || (sarrayGetCount(satypes) != n))
        return ERROR_INT("not all sa the same size", procName, 1);

        /* The sized arrays (4 args to TIFFSetField) are written first */
    if (nasizes) {
        ns = numaGetCount(nasizes);
        if (ns > n)
            return ERROR_INT("too many 4-arg tag calls", procName, 1);
        for (i = 0; i < ns; i++) {
            numaGetIValue(natags, i, &tagval);
            sval = sarrayGetString(savals, i, L_NOCOPY);
            type = sarrayGetString(satypes, i, L_NOCOPY);
            numaGetIValue(nasizes, i, &size);
            if (strcmp(type, "char*") && strcmp(type, "l_uint8*"))
                L_WARNING("array type not char* or l_uint8*; ignore\n",
                          procName);
            TIFFSetField(tif, tagval, size, sval);
        }
    } else {
        ns = 0;
    }

        /* The typical tags (3 args to TIFFSetField) are now written */
    for (i = ns; i < n; i++) {
        numaGetIValue(natags, i, &tagval);
        sval = sarrayGetString(savals, i, L_NOCOPY);
        type = sarrayGetString(satypes, i, L_NOCOPY);
        if (!strcmp(type, "char*") || !strcmp(type, "const char*")) {
            TIFFSetField(tif, tagval, sval);
        } else if (!strcmp(type, "l_uint16")) {
            if (sscanf(sval, "%u", &uval) == 1) {
                TIFFSetField(tif, tagval, (l_uint16)uval);
            } else {
                lept_stderr("val %s not of type %s\n", sval, type);
                return ERROR_INT("custom tag(s) not written", procName, 1);
            }
        } else if (!strcmp(type, "l_uint32")) {
            if (sscanf(sval, "%u", &uval) == 1) {
                TIFFSetField(tif, tagval, uval);
            } else {
                lept_stderr("val %s not of type %s\n", sval, type);
                return ERROR_INT("custom tag(s) not written", procName, 1);
            }
        } else if (!strcmp(type, "l_int32")) {
            if (sscanf(sval, "%d", &val) == 1) {
                TIFFSetField(tif, tagval, val);
            } else {
                lept_stderr("val %s not of type %s\n", sval, type);
                return ERROR_INT("custom tag(s) not written", procName, 1);
            }
        } else if (!strcmp(type, "l_float64")) {
            if (sscanf(sval, "%lf", &dval) == 1) {
                TIFFSetField(tif, tagval, dval);
            } else {
                lept_stderr("val %s not of type %s\n", sval, type);
                return ERROR_INT("custom tag(s) not written", procName, 1);
            }
        } else if (!strcmp(type, "l_uint16-l_uint16")) {
            if (sscanf(sval, "%u-%u", &uval, &uval2) == 2) {
                TIFFSetField(tif, tagval, (l_uint16)uval, (l_uint16)uval2);
            } else {
                lept_stderr("val %s not of type %s\n", sval, type);
                return ERROR_INT("custom tag(s) not written", procName, 1);
            }
        } else {
            lept_stderr("unknown type %s\n",type);
            return ERROR_INT("unknown type; tag(s) not written", procName, 1);
        }
    }
    return 0;
}

static const l_int32  DefaultResolution = 300;

static const l_int32  ManyPagesInTiffFile = 3000;

static const l_int32  MaxTiffWidth = 1 << 20;

static const l_int32  MaxTiffHeight = 1 << 20;

static PIX      *pixReadFromTiffStream(TIFF *tif);

static l_int32   getTiffStreamResolution(TIFF *tif, l_int32 *pxres,
                                         l_int32 *pyres);

static l_int32   tiffReadHeaderTiff(TIFF *tif, l_int32 *pwidth,
                                    l_int32 *pheight, l_int32 *pbps,
                                    l_int32 *pspp, l_int32 *pres,
                                    l_int32 *pcmap, l_int32 *pformat);

static l_int32   writeCustomTiffTags(TIFF *tif, NUMA *natags,
                                     SARRAY *savals, SARRAY  *satypes,
                                     NUMA *nasizes);

static l_int32   pixWriteToTiffStream(TIFF *tif, PIX *pix, l_int32 comptype,
                                      NUMA *natags, SARRAY *savals,
                                      SARRAY *satypes, NUMA *nasizes);

static TIFF     *fopenTiff(FILE *fp, const char *modestring);

static TIFF     *openTiff(const char *filename, const char *modestring);

static l_int32   getTiffCompressedFormat(l_uint16 tiffcomp);

static TIFF     *fopenTiffMemstream(const char *filename, const char *operation,
                                    l_uint8 **pdata, size_t *pdatasize);

struct L_Memstream
{
    l_uint8   *buffer;    /* expands to hold data when written to;         */
                          /* fixed size when read from.                    */
    size_t     bufsize;   /* current size allocated when written to;       */
                          /* fixed size of input data when read from.      */
    size_t     offset;    /* byte offset from beginning of buffer.         */
    size_t     hw;        /* high-water mark; max bytes in buffer.         */
    l_uint8  **poutdata;  /* input param for writing; data goes here.      */
    size_t    *poutsize;  /* input param for writing; data size goes here. */
}

static L_MEMSTREAM *memstreamCreateForRead(l_uint8 *indata, size_t pinsize);

static L_MEMSTREAM *memstreamCreateForWrite(l_uint8 **poutdata,
                                            size_t *poutsize);

static toff_t tiffSeekCallback(thandle_t handle, toff_t offset, l_int32 whence);

static l_int32 tiffCloseCallback(thandle_t handle);

static l_int32 tiffMapCallback(thandle_t handle, tdata_t *data, toff_t *length);


pixWriteTiff(const char  *filename,
             PIX         *pix,
             l_int32      comptype,
             const char  *modestr)
{
    return pixWriteTiffCustom(filename, pix, comptype, modestr,
                              NULL, NULL, NULL, NULL);
}


memstreamCreateForRead(l_uint8  *indata,
                       size_t    insize)
{
L_MEMSTREAM  *mstream;

    mstream = (L_MEMSTREAM *)LEPT_CALLOC(1, sizeof(L_MEMSTREAM));
    mstream->buffer = indata;   /* handle to input data array */
    mstream->bufsize = insize;  /* amount of input data */
    mstream->hw = insize;       /* high-water mark fixed at input data size */
    mstream->offset = 0;        /* offset always starts at 0 */
    return mstream;
}

static TIFF     *fopenTiffMemstream(const char *filename, const char *operation,
                                    l_uint8 **pdata, size_t *pdatasize);

struct L_Memstream
{
    l_uint8   *buffer;    /* expands to hold data when written to;         */
                          /* fixed size when read from.                    */
    size_t     bufsize;   /* current size allocated when written to;       */
                          /* fixed size of input data when read from.      */
    size_t     offset;    /* byte offset from beginning of buffer.         */
    size_t     hw;        /* high-water mark; max bytes in buffer.         */
    l_uint8  **poutdata;  /* input param for writing; data goes here.      */
    size_t    *poutsize;  /* input param for writing; data size goes here. */
}

typedef struct L_Memstream  L_MEMSTREAM;

static L_MEMSTREAM *memstreamCreateForRead(l_uint8 *indata, size_t pinsize);

static L_MEMSTREAM *memstreamCreateForWrite(l_uint8 **poutdata,
                                            size_t *poutsize);

static tsize_t tiffReadCallback(thandle_t handle, tdata_t data, tsize_t length);

static tsize_t tiffWriteCallback(thandle_t handle, tdata_t data,
                                 tsize_t length);

static toff_t tiffSeekCallback(thandle_t handle, toff_t offset, l_int32 whence);

static l_int32 tiffCloseCallback(thandle_t handle);

static toff_t tiffSizeCallback(thandle_t handle);

static l_int32 tiffMapCallback(thandle_t handle, tdata_t *data, toff_t *length);

static void tiffUnmapCallback(thandle_t handle, tdata_t data, toff_t length);


tiffWriteCallback(thandle_t  handle,
                  tdata_t    data,
                  tsize_t    length)
{
L_MEMSTREAM  *mstream;
size_t        newsize;

        /* reallocNew() uses calloc to initialize the array.
         * If malloc is used instead, for some of the encoding methods,
         * not all the data in 'bufsize' bytes in the buffer will
         * have been initialized by the end of the compression. */
    mstream = (L_MEMSTREAM *)handle;
    if (mstream->offset + length > mstream->bufsize) {
        newsize = 2 * (mstream->offset + length);
        mstream->buffer = (l_uint8 *)reallocNew((void **)&mstream->buffer,
                                                mstream->hw, newsize);
        mstream->bufsize = newsize;
    }

    memcpy(mstream->buffer + mstream->offset, data, length);
    mstream->offset += length;
    mstream->hw = L_MAX(mstream->offset, mstream->hw);
    return length;
}


tiffCloseCallback(thandle_t  handle)
{
L_MEMSTREAM  *mstream;

    mstream = (L_MEMSTREAM *)handle;
    if (mstream->poutdata) {   /* writing: save the output data */
        *mstream->poutdata = mstream->buffer;
        *mstream->poutsize = mstream->hw;
    }
    LEPT_FREE(mstream);  /* never free the buffer! */
    return 0;
}


pixaReadMemMultipageTiff(const l_uint8  *data,
                         size_t          size)
{
size_t  offset;
PIX    *pix;
PIXA   *pixa;

    PROCNAME("pixaReadMemMultipageTiff");

    if (!data)
        return (PIXA *)ERROR_PTR("data not defined", procName, NULL);

    offset = 0;
    pixa = pixaCreate(0);
    do {
        pix = pixReadMemFromMultipageTiff(data, size, &offset);
        pixaAddPix(pixa, pix, L_INSERT);
    } while (offset != 0);
    return pixa;
}

static const l_int32  DefaultResolution = 300;

static const l_int32  ManyPagesInTiffFile = 3000;

static const l_int32  MaxTiffWidth = 1 << 20;

static const l_int32  MaxTiffHeight = 1 << 20;

static PIX      *pixReadFromTiffStream(TIFF *tif);

static l_int32   pixWriteToTiffStream(TIFF *tif, PIX *pix, l_int32 comptype,
                                      NUMA *natags, SARRAY *savals,
                                      SARRAY *satypes, NUMA *nasizes);

static TIFF     *fopenTiff(FILE *fp, const char *modestring);

static TIFF     *openTiff(const char *filename, const char *modestring);

static TIFF     *fopenTiffMemstream(const char *filename, const char *operation,
                                    l_uint8 **pdata, size_t *pdatasize);

struct L_Memstream
{
    l_uint8   *buffer;    /* expands to hold data when written to;         */
                          /* fixed size when read from.                    */
    size_t     bufsize;   /* current size allocated when written to;       */
                          /* fixed size of input data when read from.      */
    size_t     offset;    /* byte offset from beginning of buffer.         */
    size_t     hw;        /* high-water mark; max bytes in buffer.         */
    l_uint8  **poutdata;  /* input param for writing; data goes here.      */
    size_t    *poutsize;  /* input param for writing; data size goes here. */
}

static L_MEMSTREAM *memstreamCreateForRead(l_uint8 *indata, size_t pinsize);

static L_MEMSTREAM *memstreamCreateForWrite(l_uint8 **poutdata,
                                            size_t *poutsize);

static tsize_t tiffReadCallback(thandle_t handle, tdata_t data, tsize_t length);

static tsize_t tiffWriteCallback(thandle_t handle, tdata_t data,
                                 tsize_t length);

static toff_t tiffSeekCallback(thandle_t handle, toff_t offset, l_int32 whence);

static l_int32 tiffMapCallback(thandle_t handle, tdata_t *data, toff_t *length);

static void tiffUnmapCallback(thandle_t handle, tdata_t data, toff_t length);


pixWriteMemTiffCustom(l_uint8  **pdata,
                      size_t    *psize,
                      PIX       *pix,
                      l_int32    comptype,
                      NUMA      *natags,
                      SARRAY    *savals,
                      SARRAY    *satypes,
                      NUMA      *nasizes)
{
l_int32  ret;
TIFF    *tif;

    PROCNAME("pixWriteMemTiffCustom");

    if (!pdata)
        return ERROR_INT("&data not defined", procName, 1);
    if (!psize)
        return ERROR_INT("&size not defined", procName, 1);
    if (!pix)
        return ERROR_INT("&pix not defined", procName, 1);
    if (pixGetDepth(pix) != 1 && comptype != IFF_TIFF &&
        comptype != IFF_TIFF_LZW && comptype != IFF_TIFF_ZIP &&
        comptype != IFF_TIFF_JPEG) {
        L_WARNING("invalid compression type for bpp > 1\n", procName);
        comptype = IFF_TIFF_ZIP;
    }

    if ((tif = fopenTiffMemstream("tifferror", "w", pdata, psize)) == NULL)
        return ERROR_INT("tiff stream not opened", procName, 1);
    ret = pixWriteToTiffStream(tif, pix, comptype, natags, savals,
                               satypes, nasizes);

    TIFFClose(tif);
    return ret;
}

static const l_int32  DefaultResolution = 300;

static const l_int32  ManyPagesInTiffFile = 3000;

static const l_int32  MaxTiffWidth = 1 << 20;

static const l_int32  MaxTiffHeight = 1 << 20;

static PIX      *pixReadFromTiffStream(TIFF *tif);

static l_int32   getTiffStreamResolution(TIFF *tif, l_int32 *pxres,
                                         l_int32 *pyres);

static l_int32   tiffReadHeaderTiff(TIFF *tif, l_int32 *pwidth,
                                    l_int32 *pheight, l_int32 *pbps,
                                    l_int32 *pspp, l_int32 *pres,
                                    l_int32 *pcmap, l_int32 *pformat);

static l_int32   writeCustomTiffTags(TIFF *tif, NUMA *natags,
                                     SARRAY *savals, SARRAY  *satypes,
                                     NUMA *nasizes);

static l_int32   pixWriteToTiffStream(TIFF *tif, PIX *pix, l_int32 comptype,
                                      NUMA *natags, SARRAY *savals,
                                      SARRAY *satypes, NUMA *nasizes);

static TIFF     *fopenTiff(FILE *fp, const char *modestring);

static TIFF     *openTiff(const char *filename, const char *modestring);

static l_int32   getTiffCompressedFormat(l_uint16 tiffcomp);

static TIFF     *fopenTiffMemstream(const char *filename, const char *operation,
                                    l_uint8 **pdata, size_t *pdatasize);

struct L_Memstream
{
    l_uint8   *buffer;    /* expands to hold data when written to;         */
                          /* fixed size when read from.                    */
    size_t     bufsize;   /* current size allocated when written to;       */
                          /* fixed size of input data when read from.      */
    size_t     offset;    /* byte offset from beginning of buffer.         */
    size_t     hw;        /* high-water mark; max bytes in buffer.         */
    l_uint8  **poutdata;  /* input param for writing; data goes here.      */
    size_t    *poutsize;  /* input param for writing; data size goes here. */
}

static L_MEMSTREAM *memstreamCreateForRead(l_uint8 *indata, size_t pinsize);

static L_MEMSTREAM *memstreamCreateForWrite(l_uint8 **poutdata,
                                            size_t *poutsize);

static tsize_t tiffReadCallback(thandle_t handle, tdata_t data, tsize_t length);

static tsize_t tiffWriteCallback(thandle_t handle, tdata_t data,
                                 tsize_t length);

static toff_t tiffSeekCallback(thandle_t handle, toff_t offset, l_int32 whence);

static l_int32 tiffCloseCallback(thandle_t handle);

static l_int32 tiffMapCallback(thandle_t handle, tdata_t *data, toff_t *length);

static void tiffUnmapCallback(thandle_t handle, tdata_t data, toff_t length);


tiffReadCallback(thandle_t  handle,
                 tdata_t    data,
                 tsize_t    length)
{
L_MEMSTREAM  *mstream;
size_t        amount;

    mstream = (L_MEMSTREAM *)handle;
    amount = L_MIN((size_t)length, mstream->hw - mstream->offset);

        /* Fuzzed files can create this condition! */
    if (mstream->offset + amount < amount ||  /* overflow */
        mstream->offset + amount > mstream->hw) {
        lept_stderr("Bad file: amount too big: %zu\n", amount);
        return 0;
    }

    memcpy(data, mstream->buffer + mstream->offset, amount);
    mstream->offset += amount;
    return amount;
}


getTiffResolution(FILE     *fp,
                  l_int32  *pxres,
                  l_int32  *pyres)
{
TIFF  *tif;

    PROCNAME("getTiffResolution");

    if (!pxres || !pyres)
        return ERROR_INT("&xres and &yres not both defined", procName, 1);
    *pxres = *pyres = 0;
    if (!fp)
        return ERROR_INT("stream not opened", procName, 1);

    if ((tif = fopenTiff(fp, "r")) == NULL)
        return ERROR_INT("tif not open for read", procName, 1);
    getTiffStreamResolution(tif, pxres, pyres);
    TIFFCleanup(tif);
    return 0;
}


tiffGetCount(FILE     *fp,
             l_int32  *pn)
{
l_int32  i;
TIFF    *tif;

    PROCNAME("tiffGetCount");

    if (!fp)
        return ERROR_INT("stream not defined", procName, 1);
    if (!pn)
        return ERROR_INT("&n not defined", procName, 1);
    *pn = 0;

    if ((tif = fopenTiff(fp, "r")) == NULL)
        return ERROR_INT("tif not open for read", procName, 1);

    for (i = 1; ; i++) {
        if (TIFFReadDirectory(tif) == 0)
            break;
        if (i == ManyPagesInTiffFile + 1) {
            L_WARNING("big file: more than %d pages\n", procName,
                      ManyPagesInTiffFile);
        }
    }
    *pn = i;
    TIFFCleanup(tif);
    return 0;
}


pixWriteToTiffStream(TIFF    *tif,
                     PIX     *pix,
                     l_int32  comptype,
                     NUMA    *natags,
                     SARRAY  *savals,
                     SARRAY  *satypes,
                     NUMA    *nasizes)
{
l_uint8   *linebuf, *data;
l_uint16   redmap[256], greenmap[256], bluemap[256];
l_int32    w, h, d, spp, i, j, k, wpl, bpl, tiffbpl, ncolors, cmapsize;
l_int32   *rmap, *gmap, *bmap;
l_int32    xres, yres;
l_uint32  *line, *ppixel;
PIX       *pixt;
PIXCMAP   *cmap;
char      *text;

    PROCNAME("pixWriteToTiffStream");

    if (!tif)
        return ERROR_INT("tif stream not defined", procName, 1);
    if (!pix)
        return ERROR_INT( "pix not defined", procName, 1 );

    pixSetPadBits(pix, 0);
    pixGetDimensions(pix, &w, &h, &d);
    spp = pixGetSpp(pix);
    xres = pixGetXRes(pix);
    yres = pixGetYRes(pix);
    if (xres == 0) xres = DefaultResolution;
    if (yres == 0) yres = DefaultResolution;

        /* ------------------ Write out the header -------------  */
    TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, (l_uint32)RESUNIT_INCH);
    TIFFSetField(tif, TIFFTAG_XRESOLUTION, (l_float64)xres);
    TIFFSetField(tif, TIFFTAG_YRESOLUTION, (l_float64)yres);

    TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (l_uint32)w);
    TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (l_uint32)h);
    TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);

    if ((text = pixGetText(pix)) != NULL)
        TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, text);

    if (d == 1 && !pixGetColormap(pix)) {
            /* If d == 1, preserve the colormap.  Note that when
             * d == 1 pix with colormaps are read, the colormaps
             * are removed.  The only pix in leptonica that have
             * colormaps are made programmatically. */
        TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
    } else if ((d == 32 && spp == 3) || d == 24) {
        TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
        TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (l_uint16)3);
        TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,
                       (l_uint16)8, (l_uint16)8, (l_uint16)8);
    } else if (d == 32 && spp == 4) {
        l_uint16  val[1];
        val[0] = EXTRASAMPLE_ASSOCALPHA;
        TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, (l_uint16)1, &val);
        TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
        TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (l_uint16)4);
        TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,
                     (l_uint16)8, (l_uint16)8, (l_uint16)8, (l_uint16)8);
    } else if (d == 16) {  /* we only support spp = 1, bps = 16 */
        TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
    } else if ((cmap = pixGetColormap(pix)) == NULL) {
        TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
    } else {  /* Save colormap in the tiff; not more than 256 colors */
        if (d > 8) {
            L_ERROR("d = %d > 8 with colormap!; reducing to 8\n", procName, d);
            d = 8;
        }
        pixcmapToArrays(cmap, &rmap, &gmap, &bmap, NULL);
        ncolors = pixcmapGetCount(cmap);
        ncolors = L_MIN(256, ncolors);  /* max 256 */
        cmapsize = 1 << d;
        cmapsize = L_MIN(256, cmapsize);  /* power of 2; max 256 */
        if (ncolors > cmapsize) {
            L_WARNING("too many colors in cmap for tiff; truncating\n",
                      procName);
            ncolors = cmapsize;
        }
        for (i = 0; i < ncolors; i++) {
            redmap[i] = (rmap[i] << 8) | rmap[i];
            greenmap[i] = (gmap[i] << 8) | gmap[i];
            bluemap[i] = (bmap[i] << 8) | bmap[i];
        }
        for (i = ncolors; i < cmapsize; i++)  /* init, even though not used */
            redmap[i] = greenmap[i] = bluemap[i] = 0;
        LEPT_FREE(rmap);
        LEPT_FREE(gmap);
        LEPT_FREE(bmap);

        TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
        TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (l_uint16)1);
        TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, (l_uint16)d);
        TIFFSetField(tif, TIFFTAG_COLORMAP, redmap, greenmap, bluemap);
    }

    if (d <= 16) {
        TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, (l_uint16)d);
        TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (l_uint16)1);
    }

    TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
    if (comptype == IFF_TIFF) {  /* no compression */
        TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
    } else if (comptype == IFF_TIFF_G4) {
        TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
    } else if (comptype == IFF_TIFF_G3) {
        TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX3);
    } else if (comptype == IFF_TIFF_RLE) {
        TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTRLE);
    } else if (comptype == IFF_TIFF_PACKBITS) {
        TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS);
    } else if (comptype == IFF_TIFF_LZW) {
        TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
    } else if (comptype == IFF_TIFF_ZIP) {
        TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_ADOBE_DEFLATE);
    } else if (comptype == IFF_TIFF_JPEG) {
        TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_JPEG);
    } else {
        L_WARNING("unknown tiff compression; using none\n", procName);
        TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
    }

        /* This is a no-op if arrays are NULL */
    writeCustomTiffTags(tif, natags, savals, satypes, nasizes);

        /* ------------- Write out the image data -------------  */
    tiffbpl = TIFFScanlineSize(tif);
    wpl = pixGetWpl(pix);
    bpl = 4 * wpl;
    if (tiffbpl > bpl)
        lept_stderr("Big trouble: tiffbpl = %d, bpl = %d\n", tiffbpl, bpl);
    if ((linebuf = (l_uint8 *)LEPT_CALLOC(1, bpl)) == NULL)
        return ERROR_INT("calloc fail for linebuf", procName, 1);

        /* Use single strip for image */
    TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, h);

    if (d != 24 && d != 32) {
        if (d == 16)
            pixt = pixEndianTwoByteSwapNew(pix);
        else
            pixt = pixEndianByteSwapNew(pix);
        data = (l_uint8 *)pixGetData(pixt);
        for (i = 0; i < h; i++, data += bpl) {
            memcpy(linebuf, data, tiffbpl);
            if (TIFFWriteScanline(tif, linebuf, i, 0) < 0)
                break;
        }
        pixDestroy(&pixt);
    } else if (d == 24) {  /* See note 4 above: special case of 24 bpp rgb */
        for (i = 0; i < h; i++) {
            line = pixGetData(pix) + i * wpl;
            if (TIFFWriteScanline(tif, (l_uint8 *)line, i, 0) < 0)
                break;
        }
    } else {  /* 32 bpp rgb or rgba */
        for (i = 0; i < h; i++) {
            line = pixGetData(pix) + i * wpl;
            for (j = 0, k = 0, ppixel = line; j < w; j++) {
                linebuf[k++] = GET_DATA_BYTE(ppixel, COLOR_RED);
                linebuf[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN);
                linebuf[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE);
                if (spp == 4)
                    linebuf[k++] = GET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL);
                ppixel++;
            }
            if (TIFFWriteScanline(tif, linebuf, i, 0) < 0)
                break;
        }
    }

/*    TIFFWriteDirectory(tif); */
    LEPT_FREE(linebuf);

    return 0;
}

static const l_int32  DefaultResolution = 300;

static const l_int32  ManyPagesInTiffFile = 3000;

static const l_int32  MaxTiffWidth = 1 << 20;

static const l_int32  MaxTiffHeight = 1 << 20;

static PIX      *pixReadFromTiffStream(TIFF *tif);

static l_int32   getTiffStreamResolution(TIFF *tif, l_int32 *pxres,
                                         l_int32 *pyres);

static l_int32   tiffReadHeaderTiff(TIFF *tif, l_int32 *pwidth,
                                    l_int32 *pheight, l_int32 *pbps,
                                    l_int32 *pspp, l_int32 *pres,
                                    l_int32 *pcmap, l_int32 *pformat);

static l_int32   writeCustomTiffTags(TIFF *tif, NUMA *natags,
                                     SARRAY *savals, SARRAY  *satypes,
                                     NUMA *nasizes);

static l_int32   pixWriteToTiffStream(TIFF *tif, PIX *pix, l_int32 comptype,
                                      NUMA *natags, SARRAY *savals,
                                      SARRAY *satypes, NUMA *nasizes);

static TIFF     *fopenTiff(FILE *fp, const char *modestring);

static TIFF     *openTiff(const char *filename, const char *modestring);

static l_int32   getTiffCompressedFormat(l_uint16 tiffcomp);

static TIFF     *fopenTiffMemstream(const char *filename, const char *operation,
                                    l_uint8 **pdata, size_t *pdatasize);

struct tiff_transform {
    int vflip;    /* if non-zero, image needs a vertical fip */
    int hflip;    /* if non-zero, image needs a horizontal flip */
    int rotate;   /* -1 -> counterclockwise 90-degree rotation,
                      0 -> no rotation
                      1 -> clockwise 90-degree rotation */
}

struct L_Memstream
{
    l_uint8   *buffer;    /* expands to hold data when written to;         */
                          /* fixed size when read from.                    */
    size_t     bufsize;   /* current size allocated when written to;       */
                          /* fixed size of input data when read from.      */
    size_t     offset;    /* byte offset from beginning of buffer.         */
    size_t     hw;        /* high-water mark; max bytes in buffer.         */
    l_uint8  **poutdata;  /* input param for writing; data goes here.      */
    size_t    *poutsize;  /* input param for writing; data size goes here. */
}

static L_MEMSTREAM *memstreamCreateForRead(l_uint8 *indata, size_t pinsize);

static L_MEMSTREAM *memstreamCreateForWrite(l_uint8 **poutdata,
                                            size_t *poutsize);

static tsize_t tiffReadCallback(thandle_t handle, tdata_t data, tsize_t length);

static tsize_t tiffWriteCallback(thandle_t handle, tdata_t data,
                                 tsize_t length);

static toff_t tiffSeekCallback(thandle_t handle, toff_t offset, l_int32 whence);

static l_int32 tiffCloseCallback(thandle_t handle);

static l_int32 tiffMapCallback(thandle_t handle, tdata_t *data, toff_t *length);

static void tiffUnmapCallback(thandle_t handle, tdata_t data, toff_t length);


tiffSeekCallback(thandle_t  handle,
                 toff_t     offset,
                 l_int32    whence)
{
L_MEMSTREAM  *mstream;

    PROCNAME("tiffSeekCallback");
    mstream = (L_MEMSTREAM *)handle;
    switch (whence) {
        case SEEK_SET:
/*            lept_stderr("seek_set: offset = %d\n", offset); */
            if((size_t)offset != offset) {  /* size_t overflow on uint32 */
                return (toff_t)ERROR_INT("too large offset value", procName, 1);
            }
            mstream->offset = offset;
            break;
        case SEEK_CUR:
/*            lept_stderr("seek_cur: offset = %d\n", offset); */
            mstream->offset += offset;
            break;
        case SEEK_END:
/*            lept_stderr("seek end: hw = %d, offset = %d\n",
                    mstream->hw, offset); */
            mstream->offset = mstream->hw - offset;  /* offset >= 0 */
            break;
        default:
            return (toff_t)ERROR_INT("bad whence value", procName,
                                     mstream->offset);
    }

    return mstream->offset;
}

static const l_int32  DefaultResolution = 300;

static const l_int32  ManyPagesInTiffFile = 3000;

static const l_int32  MaxTiffWidth = 1 << 20;

static const l_int32  MaxTiffHeight = 1 << 20;

static l_int32   getTiffStreamResolution(TIFF *tif, l_int32 *pxres,
                                         l_int32 *pyres);

static l_int32   tiffReadHeaderTiff(TIFF *tif, l_int32 *pwidth,
                                    l_int32 *pheight, l_int32 *pbps,
                                    l_int32 *pspp, l_int32 *pres,
                                    l_int32 *pcmap, l_int32 *pformat);

static l_int32   writeCustomTiffTags(TIFF *tif, NUMA *natags,
                                     SARRAY *savals, SARRAY  *satypes,
                                     NUMA *nasizes);

static l_int32   pixWriteToTiffStream(TIFF *tif, PIX *pix, l_int32 comptype,
                                      NUMA *natags, SARRAY *savals,
                                      SARRAY *satypes, NUMA *nasizes);

static l_int32   getTiffCompressedFormat(l_uint16 tiffcomp);

static TIFF     *fopenTiffMemstream(const char *filename, const char *operation,
                                    l_uint8 **pdata, size_t *pdatasize);

struct L_Memstream
{
    l_uint8   *buffer;    /* expands to hold data when written to;         */
                          /* fixed size when read from.                    */
    size_t     bufsize;   /* current size allocated when written to;       */
                          /* fixed size of input data when read from.      */
    size_t     offset;    /* byte offset from beginning of buffer.         */
    size_t     hw;        /* high-water mark; max bytes in buffer.         */
    l_uint8  **poutdata;  /* input param for writing; data goes here.      */
    size_t    *poutsize;  /* input param for writing; data size goes here. */
}

typedef struct L_Memstream  L_MEMSTREAM;

static L_MEMSTREAM *memstreamCreateForRead(l_uint8 *indata, size_t pinsize);

static L_MEMSTREAM *memstreamCreateForWrite(l_uint8 **poutdata,
                                            size_t *poutsize);

static tsize_t tiffReadCallback(thandle_t handle, tdata_t data, tsize_t length);

static tsize_t tiffWriteCallback(thandle_t handle, tdata_t data,
                                 tsize_t length);

static toff_t tiffSeekCallback(thandle_t handle, toff_t offset, l_int32 whence);

static l_int32 tiffCloseCallback(thandle_t handle);

static toff_t tiffSizeCallback(thandle_t handle);

static l_int32 tiffMapCallback(thandle_t handle, tdata_t *data, toff_t *length);

static void tiffUnmapCallback(thandle_t handle, tdata_t data, toff_t length);


tiffUnmapCallback(thandle_t  handle,
                  tdata_t    data,
                  toff_t     length)
{
    return;
}

struct L_Memstream
{
    l_uint8   *buffer;    /* expands to hold data when written to;         */
                          /* fixed size when read from.                    */
    size_t     bufsize;   /* current size allocated when written to;       */
                          /* fixed size of input data when read from.      */
    size_t     offset;    /* byte offset from beginning of buffer.         */
    size_t     hw;        /* high-water mark; max bytes in buffer.         */
    l_uint8  **poutdata;  /* input param for writing; data goes here.      */
    size_t    *poutsize;  /* input param for writing; data size goes here. */
}

static tsize_t tiffReadCallback(thandle_t handle, tdata_t data, tsize_t length);

static tsize_t tiffWriteCallback(thandle_t handle, tdata_t data,
                                 tsize_t length);

static toff_t tiffSeekCallback(thandle_t handle, toff_t offset, l_int32 whence);

static l_int32 tiffCloseCallback(thandle_t handle);

static toff_t tiffSizeCallback(thandle_t handle);

static l_int32 tiffMapCallback(thandle_t handle, tdata_t *data, toff_t *length);

static void tiffUnmapCallback(thandle_t handle, tdata_t data, toff_t length);


pixWriteStreamTiff(FILE    *fp,
                   PIX     *pix,
                   l_int32  comptype)
{
    return pixWriteStreamTiffWA(fp, pix, comptype, "w");
}

static const l_int32  DefaultResolution = 300;

static const l_int32  ManyPagesInTiffFile = 3000;

static const l_int32  MaxTiffWidth = 1 << 20;

static const l_int32  MaxTiffHeight = 1 << 20;

static PIX      *pixReadFromTiffStream(TIFF *tif);

static l_int32   getTiffStreamResolution(TIFF *tif, l_int32 *pxres,
                                         l_int32 *pyres);

static l_int32   tiffReadHeaderTiff(TIFF *tif, l_int32 *pwidth,
                                    l_int32 *pheight, l_int32 *pbps,
                                    l_int32 *pspp, l_int32 *pres,
                                    l_int32 *pcmap, l_int32 *pformat);

static l_int32   writeCustomTiffTags(TIFF *tif, NUMA *natags,
                                     SARRAY *savals, SARRAY  *satypes,
                                     NUMA *nasizes);

static l_int32   pixWriteToTiffStream(TIFF *tif, PIX *pix, l_int32 comptype,
                                      NUMA *natags, SARRAY *savals,
                                      SARRAY *satypes, NUMA *nasizes);

static TIFF     *fopenTiff(FILE *fp, const char *modestring);

static l_int32   getTiffCompressedFormat(l_uint16 tiffcomp);

static toff_t tiffSeekCallback(thandle_t handle, toff_t offset, l_int32 whence);

static l_int32 tiffCloseCallback(thandle_t handle);

static l_int32 tiffMapCallback(thandle_t handle, tdata_t *data, toff_t *length);


pixReadMemFromMultipageTiff(const l_uint8  *cdata,
                            size_t          size,
                            size_t         *poffset)
{
l_uint8  *data;
l_int32   retval;
size_t    offset;
PIX      *pix;
TIFF     *tif;

    PROCNAME("pixReadMemFromMultipageTiff");

    if (!cdata)
        return (PIX *)ERROR_PTR("cdata not defined", procName, NULL);
    if (!poffset)
        return (PIX *)ERROR_PTR("&offset not defined", procName, NULL);

    data = (l_uint8 *)cdata;  /* we're really not going to change this */
    if ((tif = fopenTiffMemstream("tifferror", "r", &data, &size)) == NULL)
        return (PIX *)ERROR_PTR("tiff stream not opened", procName, NULL);

        /* Set ptrs in the TIFF to the beginning of the image */
    offset = *poffset;
    retval = (offset == 0) ? TIFFSetDirectory(tif, 0)
                           : TIFFSetSubDirectory(tif, offset);
    if (retval == 0) {
        TIFFClose(tif);
        return NULL;
    }

    if ((pix = pixReadFromTiffStream(tif)) == NULL) {
        TIFFClose(tif);
        return NULL;
    }

        /* Advance to the next image and return the new offset */
    TIFFReadDirectory(tif);
    *poffset = TIFFCurrentDirOffset(tif);
    TIFFClose(tif);
    return pix;
}


static int input_defuzz_abs_event(int value, int old_val, int fuzz)
{
	if (fuzz) {
		if (value > old_val - fuzz / 2 && value < old_val + fuzz / 2)
			return old_val;

		if (value > old_val - fuzz && value < old_val + fuzz)
			return (old_val * 3 + value) / 4;

		if (value > old_val - fuzz * 2 && value < old_val + fuzz * 2)
			return (old_val + value) / 2;
	}

	return value;
}

Input: add safety guards to input_set_keycode()

If we happen to have a garbage in input device's keycode table with values
too big we'll end up doing clear_bit() with offset way outside of our
bitmaps, damaging other objects within an input device or even outside of
it. Let's add sanity checks to the returned old keycodes.

Reported-by: syzbot+c769968809f9359b07aa@syzkaller.appspotmail.com
Reported-by: syzbot+76f3a30e88d256644c78@syzkaller.appspotmail.com
Link: https://lore.kernel.org/r/20191207212757.GA245964@dtor-ws
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

static DEFINE_IDA(input_ida);

static LIST_HEAD(input_dev_list);

static LIST_HEAD(input_handler_list);

static DEFINE_MUTEX(input_mutex);

static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 };

static struct proc_dir_entry *proc_bus_input_dir;

static DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait);

static int input_devices_state;

static const struct seq_operations input_devices_seq_ops = {
	.start	= input_devices_seq_start,
	.next	= input_devices_seq_next,
	.stop	= input_seq_stop,
	.show	= input_devices_seq_show,
};

static const struct file_operations input_devices_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_devices_open,
	.poll		= input_proc_devices_poll,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

static const struct seq_operations input_handlers_seq_ops = {
	.start	= input_handlers_seq_start,
	.next	= input_handlers_seq_next,
	.stop	= input_seq_stop,
	.show	= input_handlers_seq_show,
};

static const struct file_operations input_handlers_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_handlers_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

#define INPUT_DEV_STRING_ATTR_SHOW(name)				\
static ssize_t input_dev_show_##name(struct device *dev,		\
				     struct device_attribute *attr,	\
				     char *buf)				\
{									\
	struct input_dev *input_dev = to_input_dev(dev);		\
									\
	return scnprintf(buf, PAGE_SIZE, "%s\n",			\
			 input_dev->name ? input_dev->name : "");	\
}									\
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL)

static DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL);

static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap,
			      int max, int add_cr);

static DEVICE_ATTR(properties, S_IRUGO, input_dev_show_properties, NULL);

static struct attribute *input_dev_attrs[] = {
	&dev_attr_name.attr,
	&dev_attr_phys.attr,
	&dev_attr_uniq.attr,
	&dev_attr_modalias.attr,
	&dev_attr_properties.attr,
	NULL
};

static const struct attribute_group input_dev_attr_group = {
	.attrs	= input_dev_attrs,
};

#define INPUT_DEV_ID_ATTR(name)						\
static ssize_t input_dev_show_id_##name(struct device *dev,		\
					struct device_attribute *attr,	\
					char *buf)			\
{									\
	struct input_dev *input_dev = to_input_dev(dev);		\
	return scnprintf(buf, PAGE_SIZE, "%04x\n", input_dev->id.name);	\
}									\
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_id_##name, NULL)

static struct attribute *input_dev_id_attrs[] = {
	&dev_attr_bustype.attr,
	&dev_attr_vendor.attr,
	&dev_attr_product.attr,
	&dev_attr_version.attr,
	NULL
};

static const struct attribute_group input_dev_id_attr_group = {
	.name	= "id",
	.attrs	= input_dev_id_attrs,
};


void input_enable_softrepeat(struct input_dev *dev, int delay, int period)
{
	dev->timer.function = input_repeat_key;
	dev->rep[REP_DELAY] = delay;
	dev->rep[REP_PERIOD] = period;
}

static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 };

static struct proc_dir_entry *proc_bus_input_dir;

static int input_devices_state;

union input_seq_state {
	struct {
		unsigned short pos;
		bool mutex_acquired;
	};
	void *p;
}

static const struct seq_operations input_devices_seq_ops = {
	.start	= input_devices_seq_start,
	.next	= input_devices_seq_next,
	.stop	= input_seq_stop,
	.show	= input_devices_seq_show,
};

static const struct file_operations input_devices_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_devices_open,
	.poll		= input_proc_devices_poll,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

static const struct seq_operations input_handlers_seq_ops = {
	.start	= input_handlers_seq_start,
	.next	= input_handlers_seq_next,
	.stop	= input_seq_stop,
	.show	= input_handlers_seq_show,
};

static const struct file_operations input_handlers_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_handlers_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

#define INPUT_DEV_STRING_ATTR_SHOW(name)				\
static ssize_t input_dev_show_##name(struct device *dev,		\
				     struct device_attribute *attr,	\
				     char *buf)				\
{									\
	struct input_dev *input_dev = to_input_dev(dev);		\
									\
	return scnprintf(buf, PAGE_SIZE, "%s\n",			\
			 input_dev->name ? input_dev->name : "");	\
}									\
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL)

static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap,
			      int max, int add_cr);

static struct attribute *input_dev_attrs[] = {
	&dev_attr_name.attr,
	&dev_attr_phys.attr,
	&dev_attr_uniq.attr,
	&dev_attr_modalias.attr,
	&dev_attr_properties.attr,
	NULL
};

static const struct attribute_group input_dev_attr_group = {
	.attrs	= input_dev_attrs,
};

#define INPUT_DEV_ID_ATTR(name)						\
static ssize_t input_dev_show_id_##name(struct device *dev,		\
					struct device_attribute *attr,	\
					char *buf)			\
{									\
	struct input_dev *input_dev = to_input_dev(dev);		\
	return scnprintf(buf, PAGE_SIZE, "%04x\n", input_dev->id.name);	\
}									\
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_id_##name, NULL)

static struct attribute *input_dev_id_attrs[] = {
	&dev_attr_bustype.attr,
	&dev_attr_vendor.attr,
	&dev_attr_product.attr,
	&dev_attr_version.attr,
	NULL
};

static const struct attribute_group input_dev_id_attr_group = {
	.name	= "id",
	.attrs	= input_dev_id_attrs,
};


int input_register_device(struct input_dev *dev)
{
	struct input_devres *devres = NULL;
	struct input_handler *handler;
	unsigned int packet_size;
	const char *path;
	int error;

	if (test_bit(EV_ABS, dev->evbit) && !dev->absinfo) {
		dev_err(&dev->dev,
			"Absolute device without dev->absinfo, refusing to register\n");
		return -EINVAL;
	}

	if (dev->devres_managed) {
		devres = devres_alloc(devm_input_device_unregister,
				      sizeof(*devres), GFP_KERNEL);
		if (!devres)
			return -ENOMEM;

		devres->input = dev;
	}

	/* Every input device generates EV_SYN/SYN_REPORT events. */
	__set_bit(EV_SYN, dev->evbit);

	/* KEY_RESERVED is not supposed to be transmitted to userspace. */
	__clear_bit(KEY_RESERVED, dev->keybit);

	/* Make sure that bitmasks not mentioned in dev->evbit are clean. */
	input_cleanse_bitmasks(dev);

	packet_size = input_estimate_events_per_packet(dev);
	if (dev->hint_events_per_packet < packet_size)
		dev->hint_events_per_packet = packet_size;

	dev->max_vals = dev->hint_events_per_packet + 2;
	dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
	if (!dev->vals) {
		error = -ENOMEM;
		goto err_devres_free;
	}

	/*
	 * If delay and period are pre-set by the driver, then autorepeating
	 * is handled by the driver itself and we don't do it in input.c.
	 */
	if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD])
		input_enable_softrepeat(dev, 250, 33);

	if (!dev->getkeycode)
		dev->getkeycode = input_default_getkeycode;

	if (!dev->setkeycode)
		dev->setkeycode = input_default_setkeycode;

	if (dev->poller)
		input_dev_poller_finalize(dev->poller);

	error = device_add(&dev->dev);
	if (error)
		goto err_free_vals;

	path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
	pr_info("%s as %s\n",
		dev->name ? dev->name : "Unspecified device",
		path ? path : "N/A");
	kfree(path);

	error = mutex_lock_interruptible(&input_mutex);
	if (error)
		goto err_device_del;

	list_add_tail(&dev->node, &input_dev_list);

	list_for_each_entry(handler, &input_handler_list, node)
		input_attach_handler(dev, handler);

	input_wakeup_procfs_readers();

	mutex_unlock(&input_mutex);

	if (dev->devres_managed) {
		dev_dbg(dev->dev.parent, "%s: registering %s with devres.\n",
			__func__, dev_name(&dev->dev));
		devres_add(dev->dev.parent, devres);
	}
	return 0;

err_device_del:
	device_del(&dev->dev);
err_free_vals:
	kfree(dev->vals);
	dev->vals = NULL;
err_devres_free:
	devres_free(devres);
	return error;
}

static LIST_HEAD(input_dev_list);

static LIST_HEAD(input_handler_list);

static DEFINE_MUTEX(input_mutex);

static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 };

static struct proc_dir_entry *proc_bus_input_dir;

static int input_devices_state;

union input_seq_state {
	struct {
		unsigned short pos;
		bool mutex_acquired;
	};
	void *p;
}

static const struct seq_operations input_devices_seq_ops = {
	.start	= input_devices_seq_start,
	.next	= input_devices_seq_next,
	.stop	= input_seq_stop,
	.show	= input_devices_seq_show,
};

static const struct file_operations input_devices_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_devices_open,
	.poll		= input_proc_devices_poll,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

static const struct seq_operations input_handlers_seq_ops = {
	.start	= input_handlers_seq_start,
	.next	= input_handlers_seq_next,
	.stop	= input_seq_stop,
	.show	= input_handlers_seq_show,
};

static const struct file_operations input_handlers_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_handlers_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

#define INPUT_DEV_STRING_ATTR_SHOW(name)				\
static ssize_t input_dev_show_##name(struct device *dev,		\
				     struct device_attribute *attr,	\
				     char *buf)				\
{									\
	struct input_dev *input_dev = to_input_dev(dev);		\
									\
	return scnprintf(buf, PAGE_SIZE, "%s\n",			\
			 input_dev->name ? input_dev->name : "");	\
}									\
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL)

static DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL);

static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap,
			      int max, int add_cr);

static DEVICE_ATTR(properties, S_IRUGO, input_dev_show_properties, NULL);

static struct attribute *input_dev_attrs[] = {
	&dev_attr_name.attr,
	&dev_attr_phys.attr,
	&dev_attr_uniq.attr,
	&dev_attr_modalias.attr,
	&dev_attr_properties.attr,
	NULL
};

static const struct attribute_group input_dev_attr_group = {
	.attrs	= input_dev_attrs,
};

#define INPUT_DEV_ID_ATTR(name)						\
static ssize_t input_dev_show_id_##name(struct device *dev,		\
					struct device_attribute *attr,	\
					char *buf)			\
{									\
	struct input_dev *input_dev = to_input_dev(dev);		\
	return scnprintf(buf, PAGE_SIZE, "%04x\n", input_dev->id.name);	\
}									\
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_id_##name, NULL)

static struct attribute *input_dev_id_attrs[] = {
	&dev_attr_bustype.attr,
	&dev_attr_vendor.attr,
	&dev_attr_product.attr,
	&dev_attr_version.attr,
	NULL
};

static const struct attribute_group input_dev_id_attr_group = {
	.name	= "id",
	.attrs	= input_dev_id_attrs,
};


static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
	const struct input_device_id *id;
	int error;

	id = input_match_device(handler, dev);
	if (!id)
		return -ENODEV;

	error = handler->connect(handler, dev, id);
	if (error && error != -ENODEV)
		pr_err("failed to attach handler %s to device %s, error: %d\n",
		       handler->name, kobject_name(&dev->dev.kobj), error);

	return error;
}

static DEFINE_IDA(input_ida);

static LIST_HEAD(input_dev_list);

static LIST_HEAD(input_handler_list);

static DEFINE_MUTEX(input_mutex);

static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 };

static struct proc_dir_entry *proc_bus_input_dir;

static DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait);

static int input_devices_state;

union input_seq_state {
	struct {
		unsigned short pos;
		bool mutex_acquired;
	};
	void *p;
}

static const struct seq_operations input_devices_seq_ops = {
	.start	= input_devices_seq_start,
	.next	= input_devices_seq_next,
	.stop	= input_seq_stop,
	.show	= input_devices_seq_show,
};

static const struct file_operations input_devices_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_devices_open,
	.poll		= input_proc_devices_poll,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

static const struct seq_operations input_handlers_seq_ops = {
	.start	= input_handlers_seq_start,
	.next	= input_handlers_seq_next,
	.stop	= input_seq_stop,
	.show	= input_handlers_seq_show,
};

static const struct file_operations input_handlers_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_handlers_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

#define INPUT_DEV_STRING_ATTR_SHOW(name)				\
static ssize_t input_dev_show_##name(struct device *dev,		\
				     struct device_attribute *attr,	\
				     char *buf)				\
{									\
	struct input_dev *input_dev = to_input_dev(dev);		\
									\
	return scnprintf(buf, PAGE_SIZE, "%s\n",			\
			 input_dev->name ? input_dev->name : "");	\
}									\
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL)

static DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL);

static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap,
			      int max, int add_cr);

static DEVICE_ATTR(properties, S_IRUGO, input_dev_show_properties, NULL);

static struct attribute *input_dev_attrs[] = {
	&dev_attr_name.attr,
	&dev_attr_phys.attr,
	&dev_attr_uniq.attr,
	&dev_attr_modalias.attr,
	&dev_attr_properties.attr,
	NULL
};

static const struct attribute_group input_dev_attr_group = {
	.attrs	= input_dev_attrs,
};

#define INPUT_DEV_ID_ATTR(name)						\
static ssize_t input_dev_show_id_##name(struct device *dev,		\
					struct device_attribute *attr,	\
					char *buf)			\
{									\
	struct input_dev *input_dev = to_input_dev(dev);		\
	return scnprintf(buf, PAGE_SIZE, "%04x\n", input_dev->id.name);	\
}									\
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_id_##name, NULL)

static struct attribute *input_dev_id_attrs[] = {
	&dev_attr_bustype.attr,
	&dev_attr_vendor.attr,
	&dev_attr_product.attr,
	&dev_attr_version.attr,
	NULL
};

static const struct attribute_group input_dev_id_attr_group = {
	.name	= "id",
	.attrs	= input_dev_id_attrs,
};


static int input_dev_resume(struct device *dev)
{
	struct input_dev *input_dev = to_input_dev(dev);

	spin_lock_irq(&input_dev->event_lock);

	/* Restore state of LEDs and sounds, if any were active. */
	input_dev_toggle(input_dev, true);

	spin_unlock_irq(&input_dev->event_lock);

	return 0;
}


static int input_handle_abs_event(struct input_dev *dev,
				  unsigned int code, int *pval)
{
	struct input_mt *mt = dev->mt;
	bool is_mt_event;
	int *pold;

	if (code == ABS_MT_SLOT) {
		/*
		 * "Stage" the event; we'll flush it later, when we
		 * get actual touch data.
		 */
		if (mt && *pval >= 0 && *pval < mt->num_slots)
			mt->slot = *pval;

		return INPUT_IGNORE_EVENT;
	}

	is_mt_event = input_is_mt_value(code);

	if (!is_mt_event) {
		pold = &dev->absinfo[code].value;
	} else if (mt) {
		pold = &mt->slots[mt->slot].abs[code - ABS_MT_FIRST];
	} else {
		/*
		 * Bypass filtering for multi-touch events when
		 * not employing slots.
		 */
		pold = NULL;
	}

	if (pold) {
		*pval = input_defuzz_abs_event(*pval, *pold,
						dev->absinfo[code].fuzz);
		if (*pold == *pval)
			return INPUT_IGNORE_EVENT;

		*pold = *pval;
	}

	/* Flush pending "slot" event */
	if (is_mt_event && mt && mt->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
		input_abs_set_val(dev, ABS_MT_SLOT, mt->slot);
		return INPUT_PASS_TO_HANDLERS | INPUT_SLOT;
	}

	return INPUT_PASS_TO_HANDLERS;
}

static DEFINE_IDA(input_ida);

static LIST_HEAD(input_dev_list);

static LIST_HEAD(input_handler_list);

static DEFINE_MUTEX(input_mutex);

static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 };

#define INPUT_IGNORE_EVENT	0

#define INPUT_PASS_TO_HANDLERS	1

#define INPUT_SLOT		4

#define INPUT_PASS_TO_ALL	(INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)

static struct proc_dir_entry *proc_bus_input_dir;

static DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait);

static int input_devices_state;

union input_seq_state {
	struct {
		unsigned short pos;
		bool mutex_acquired;
	};
	void *p;
}

static const struct seq_operations input_devices_seq_ops = {
	.start	= input_devices_seq_start,
	.next	= input_devices_seq_next,
	.stop	= input_seq_stop,
	.show	= input_devices_seq_show,
};

static const struct file_operations input_devices_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_devices_open,
	.poll		= input_proc_devices_poll,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

static const struct seq_operations input_handlers_seq_ops = {
	.start	= input_handlers_seq_start,
	.next	= input_handlers_seq_next,
	.stop	= input_seq_stop,
	.show	= input_handlers_seq_show,
};

static const struct file_operations input_handlers_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_handlers_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

#define INPUT_DEV_STRING_ATTR_SHOW(name)				\
static ssize_t input_dev_show_##name(struct device *dev,		\
				     struct device_attribute *attr,	\
				     char *buf)				\
{									\
	struct input_dev *input_dev = to_input_dev(dev);		\
									\
	return scnprintf(buf, PAGE_SIZE, "%s\n",			\
			 input_dev->name ? input_dev->name : "");	\
}									\
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL)

static DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL);

static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap,
			      int max, int add_cr);

static DEVICE_ATTR(properties, S_IRUGO, input_dev_show_properties, NULL);

static struct attribute *input_dev_attrs[] = {
	&dev_attr_name.attr,
	&dev_attr_phys.attr,
	&dev_attr_uniq.attr,
	&dev_attr_modalias.attr,
	&dev_attr_properties.attr,
	NULL
};

static const struct attribute_group input_dev_attr_group = {
	.attrs	= input_dev_attrs,
};

#define INPUT_DEV_ID_ATTR(name)						\
static ssize_t input_dev_show_id_##name(struct device *dev,		\
					struct device_attribute *attr,	\
					char *buf)			\
{									\
	struct input_dev *input_dev = to_input_dev(dev);		\
	return scnprintf(buf, PAGE_SIZE, "%04x\n", input_dev->id.name);	\
}									\
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_id_##name, NULL)

static struct attribute *input_dev_id_attrs[] = {
	&dev_attr_bustype.attr,
	&dev_attr_vendor.attr,
	&dev_attr_product.attr,
	&dev_attr_version.attr,
	NULL
};

static const struct attribute_group input_dev_id_attr_group = {
	.name	= "id",
	.attrs	= input_dev_id_attrs,
};


void input_alloc_absinfo(struct input_dev *dev)
{
	if (dev->absinfo)
		return;

	dev->absinfo = kcalloc(ABS_CNT, sizeof(*dev->absinfo), GFP_KERNEL);
	if (!dev->absinfo) {
		dev_err(dev->dev.parent ?: &dev->dev,
			"%s: unable to allocate memory\n", __func__);
		/*
		 * We will handle this allocation failure in
		 * input_register_device() when we refuse to register input
		 * device with ABS bits but without absinfo.
		 */
	}
}

static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 };

static struct proc_dir_entry *proc_bus_input_dir;

union input_seq_state {
	struct {
		unsigned short pos;
		bool mutex_acquired;
	};
	void *p;
}

static const struct seq_operations input_devices_seq_ops = {
	.start	= input_devices_seq_start,
	.next	= input_devices_seq_next,
	.stop	= input_seq_stop,
	.show	= input_devices_seq_show,
};

static const struct file_operations input_devices_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_devices_open,
	.poll		= input_proc_devices_poll,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

static const struct seq_operations input_handlers_seq_ops = {
	.start	= input_handlers_seq_start,
	.next	= input_handlers_seq_next,
	.stop	= input_seq_stop,
	.show	= input_handlers_seq_show,
};

static const struct file_operations input_handlers_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_handlers_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

#define INPUT_DEV_STRING_ATTR_SHOW(name)				\
static ssize_t input_dev_show_##name(struct device *dev,		\
				     struct device_attribute *attr,	\
				     char *buf)				\
{									\
	struct input_dev *input_dev = to_input_dev(dev);		\
									\
	return scnprintf(buf, PAGE_SIZE, "%s\n",			\
			 input_dev->name ? input_dev->name : "");	\
}									\
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL)

static struct attribute *input_dev_attrs[] = {
	&dev_attr_name.attr,
	&dev_attr_phys.attr,
	&dev_attr_uniq.attr,
	&dev_attr_modalias.attr,
	&dev_attr_properties.attr,
	NULL
};

static const struct attribute_group input_dev_attr_group = {
	.attrs	= input_dev_attrs,
};

#define INPUT_DEV_ID_ATTR(name)						\
static ssize_t input_dev_show_id_##name(struct device *dev,		\
					struct device_attribute *attr,	\
					char *buf)			\
{									\
	struct input_dev *input_dev = to_input_dev(dev);		\
	return scnprintf(buf, PAGE_SIZE, "%04x\n", input_dev->id.name);	\
}									\
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_id_##name, NULL)

static struct attribute *input_dev_id_attrs[] = {
	&dev_attr_bustype.attr,
	&dev_attr_vendor.attr,
	&dev_attr_product.attr,
	&dev_attr_version.attr,
	NULL
};

static const struct attribute_group input_dev_id_attr_group = {
	.name	= "id",
	.attrs	= input_dev_id_attrs,
};

#define INPUT_DEV_CAP_ATTR(ev, bm)					\
static ssize_t input_dev_show_cap_##bm(struct device *dev,		\
				       struct device_attribute *attr,	\
				       char *buf)			\
{									\
	struct input_dev *input_dev = to_input_dev(dev);		\
	int len = input_print_bitmap(buf, PAGE_SIZE,			\
				     input_dev->bm##bit, ev##_MAX,	\
				     true);				\
	return min_t(int, len, PAGE_SIZE);				\
}									\
static DEVICE_ATTR(bm, S_IRUGO, input_dev_show_cap_##bm, NULL)


void input_unregister_handler(struct input_handler *handler)
{
	struct input_handle *handle, *next;

	mutex_lock(&input_mutex);

	list_for_each_entry_safe(handle, next, &handler->h_list, h_node)
		handler->disconnect(handle);
	WARN_ON(!list_empty(&handler->h_list));

	list_del_init(&handler->node);

	input_wakeup_procfs_readers();

	mutex_unlock(&input_mutex);
}

static DEFINE_MUTEX(input_mutex);

static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 };

static struct proc_dir_entry *proc_bus_input_dir;

union input_seq_state {
	struct {
		unsigned short pos;
		bool mutex_acquired;
	};
	void *p;
}

static const struct seq_operations input_devices_seq_ops = {
	.start	= input_devices_seq_start,
	.next	= input_devices_seq_next,
	.stop	= input_seq_stop,
	.show	= input_devices_seq_show,
};

static const struct file_operations input_devices_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_devices_open,
	.poll		= input_proc_devices_poll,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

static const struct seq_operations input_handlers_seq_ops = {
	.start	= input_handlers_seq_start,
	.next	= input_handlers_seq_next,
	.stop	= input_seq_stop,
	.show	= input_handlers_seq_show,
};

static const struct file_operations input_handlers_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_handlers_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

#define INPUT_DEV_STRING_ATTR_SHOW(name)				\
static ssize_t input_dev_show_##name(struct device *dev,		\
				     struct device_attribute *attr,	\
				     char *buf)				\
{									\
	struct input_dev *input_dev = to_input_dev(dev);		\
									\
	return scnprintf(buf, PAGE_SIZE, "%s\n",			\
			 input_dev->name ? input_dev->name : "");	\
}									\
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL)

static struct attribute *input_dev_attrs[] = {
	&dev_attr_name.attr,
	&dev_attr_phys.attr,
	&dev_attr_uniq.attr,
	&dev_attr_modalias.attr,
	&dev_attr_properties.attr,
	NULL
};

static const struct attribute_group input_dev_attr_group = {
	.attrs	= input_dev_attrs,
};

#define INPUT_DEV_ID_ATTR(name)						\
static ssize_t input_dev_show_id_##name(struct device *dev,		\
					struct device_attribute *attr,	\
					char *buf)			\
{									\
	struct input_dev *input_dev = to_input_dev(dev);		\
	return scnprintf(buf, PAGE_SIZE, "%04x\n", input_dev->id.name);	\
}									\
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_id_##name, NULL)

static struct attribute *input_dev_id_attrs[] = {
	&dev_attr_bustype.attr,
	&dev_attr_vendor.attr,
	&dev_attr_product.attr,
	&dev_attr_version.attr,
	NULL
};

static const struct attribute_group input_dev_id_attr_group = {
	.name	= "id",
	.attrs	= input_dev_id_attrs,
};

#define INPUT_DEV_CAP_ATTR(ev, bm)					\
static ssize_t input_dev_show_cap_##bm(struct device *dev,		\
				       struct device_attribute *attr,	\
				       char *buf)			\
{									\
	struct input_dev *input_dev = to_input_dev(dev);		\
	int len = input_print_bitmap(buf, PAGE_SIZE,			\
				     input_dev->bm##bit, ev##_MAX,	\
				     true);				\
	return min_t(int, len, PAGE_SIZE);				\
}									\
static DEVICE_ATTR(bm, S_IRUGO, input_dev_show_cap_##bm, NULL)


static int input_dev_freeze(struct device *dev)
{
	struct input_dev *input_dev = to_input_dev(dev);

	spin_lock_irq(&input_dev->event_lock);

	/*
	 * Keys that are pressed now are unlikely to be
	 * still pressed when we resume.
	 */
	input_dev_release_keys(input_dev);

	spin_unlock_irq(&input_dev->event_lock);

	return 0;
}


void input_close_device(struct input_handle *handle)
{
	struct input_dev *dev = handle->dev;

	mutex_lock(&dev->mutex);

	__input_release_device(handle);

	if (!--dev->users) {
		if (dev->poller)
			input_dev_poller_stop(dev->poller);

		if (dev->close)
			dev->close(dev);
	}

	if (!--handle->open) {
		/*
		 * synchronize_rcu() makes sure that input_pass_event()
		 * completed and that no more input events are delivered
		 * through this handle
		 */
		synchronize_rcu();
	}

	mutex_unlock(&dev->mutex);
}


void input_reset_device(struct input_dev *dev)
{
	unsigned long flags;

	mutex_lock(&dev->mutex);
	spin_lock_irqsave(&dev->event_lock, flags);

	input_dev_toggle(dev, true);
	input_dev_release_keys(dev);

	spin_unlock_irqrestore(&dev->event_lock, flags);
	mutex_unlock(&dev->mutex);
}

static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 };

static struct proc_dir_entry *proc_bus_input_dir;

union input_seq_state {
	struct {
		unsigned short pos;
		bool mutex_acquired;
	};
	void *p;
}

static const struct seq_operations input_devices_seq_ops = {
	.start	= input_devices_seq_start,
	.next	= input_devices_seq_next,
	.stop	= input_seq_stop,
	.show	= input_devices_seq_show,
};

static const struct file_operations input_devices_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_devices_open,
	.poll		= input_proc_devices_poll,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

static const struct seq_operations input_handlers_seq_ops = {
	.start	= input_handlers_seq_start,
	.next	= input_handlers_seq_next,
	.stop	= input_seq_stop,
	.show	= input_handlers_seq_show,
};

static const struct file_operations input_handlers_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_handlers_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

#define INPUT_DEV_STRING_ATTR_SHOW(name)				\
static ssize_t input_dev_show_##name(struct device *dev,		\
				     struct device_attribute *attr,	\
				     char *buf)				\
{									\
	struct input_dev *input_dev = to_input_dev(dev);		\
									\
	return scnprintf(buf, PAGE_SIZE, "%s\n",			\
			 input_dev->name ? input_dev->name : "");	\
}									\
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL)

static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap,
			      int max, int add_cr);

static struct attribute *input_dev_attrs[] = {
	&dev_attr_name.attr,
	&dev_attr_phys.attr,
	&dev_attr_uniq.attr,
	&dev_attr_modalias.attr,
	&dev_attr_properties.attr,
	NULL
};

static const struct attribute_group input_dev_attr_group = {
	.attrs	= input_dev_attrs,
};

#define INPUT_DEV_ID_ATTR(name)						\
static ssize_t input_dev_show_id_##name(struct device *dev,		\
					struct device_attribute *attr,	\
					char *buf)			\
{									\
	struct input_dev *input_dev = to_input_dev(dev);		\
	return scnprintf(buf, PAGE_SIZE, "%04x\n", input_dev->id.name);	\
}									\
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_id_##name, NULL)

static struct attribute *input_dev_id_attrs[] = {
	&dev_attr_bustype.attr,
	&dev_attr_vendor.attr,
	&dev_attr_product.attr,
	&dev_attr_version.attr,
	NULL
};

static const struct attribute_group input_dev_id_attr_group = {
	.name	= "id",
	.attrs	= input_dev_id_attrs,
};

#define INPUT_DEV_CAP_ATTR(ev, bm)					\
static ssize_t input_dev_show_cap_##bm(struct device *dev,		\
				       struct device_attribute *attr,	\
				       char *buf)			\
{									\
	struct input_dev *input_dev = to_input_dev(dev);		\
	int len = input_print_bitmap(buf, PAGE_SIZE,			\
				     input_dev->bm##bit, ev##_MAX,	\
				     true);				\
	return min_t(int, len, PAGE_SIZE);				\
}									\
static DEVICE_ATTR(bm, S_IRUGO, input_dev_show_cap_##bm, NULL)


static unsigned int input_to_handler(struct input_handle *handle,
			struct input_value *vals, unsigned int count)
{
	struct input_handler *handler = handle->handler;
	struct input_value *end = vals;
	struct input_value *v;

	if (handler->filter) {
		for (v = vals; v != vals + count; v++) {
			if (handler->filter(handle, v->type, v->code, v->value))
				continue;
			if (end != v)
				*end = *v;
			end++;
		}
		count = end - vals;
	}

	if (!count)
		return 0;

	if (handler->events)
		handler->events(handle, vals, count);
	else if (handler->event)
		for (v = vals; v != vals + count; v++)
			handler->event(handle, v->type, v->code, v->value);

	return count;
}


static void input_repeat_key(struct timer_list *t)
{
	struct input_dev *dev = from_timer(dev, t, timer);
	unsigned long flags;

	spin_lock_irqsave(&dev->event_lock, flags);

	if (test_bit(dev->repeat_key, dev->key) &&
	    is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
		struct input_value vals[] =  {
			{ EV_KEY, dev->repeat_key, 2 },
			input_value_sync
		};

		input_pass_values(dev, vals, ARRAY_SIZE(vals));

		if (dev->rep[REP_PERIOD])
			mod_timer(&dev->timer, jiffies +
					msecs_to_jiffies(dev->rep[REP_PERIOD]));
	}

	spin_unlock_irqrestore(&dev->event_lock, flags);
}


static int input_default_getkeycode(struct input_dev *dev,
				    struct input_keymap_entry *ke)
{
	unsigned int index;
	int error;

	if (!dev->keycodesize)
		return -EINVAL;

	if (ke->flags & INPUT_KEYMAP_BY_INDEX)
		index = ke->index;
	else {
		error = input_scancode_to_scalar(ke, &index);
		if (error)
			return error;
	}

	if (index >= dev->keycodemax)
		return -EINVAL;

	ke->keycode = input_fetch_keycode(dev, index);
	ke->index = index;
	ke->len = sizeof(index);
	memcpy(ke->scancode, &index, sizeof(index));

	return 0;
}


int input_grab_device(struct input_handle *handle)
{
	struct input_dev *dev = handle->dev;
	int retval;

	retval = mutex_lock_interruptible(&dev->mutex);
	if (retval)
		return retval;

	if (dev->grab) {
		retval = -EBUSY;
		goto out;
	}

	rcu_assign_pointer(dev->grab, handle);

 out:
	mutex_unlock(&dev->mutex);
	return retval;
}


static int __init input_init(void)
{
	int err;

	err = class_register(&input_class);
	if (err) {
		pr_err("unable to register input_dev class\n");
		return err;
	}

	err = input_proc_init();
	if (err)
		goto fail1;

	err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0),
				     INPUT_MAX_CHAR_DEVICES, "input");
	if (err) {
		pr_err("unable to register char major %d", INPUT_MAJOR);
		goto fail2;
	}

	return 0;

 fail2:	input_proc_exit();
 fail1:	class_unregister(&input_class);
	return err;
}

#define INPUT_MAX_CHAR_DEVICES		1024

static DEFINE_IDA(input_ida);

static LIST_HEAD(input_dev_list);

static LIST_HEAD(input_handler_list);

static DEFINE_MUTEX(input_mutex);

static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 };

static struct proc_dir_entry *proc_bus_input_dir;

static DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait);

static int input_devices_state;

union input_seq_state {
	struct {
		unsigned short pos;
		bool mutex_acquired;
	};
	void *p;
}

static const struct seq_operations input_devices_seq_ops = {
	.start	= input_devices_seq_start,
	.next	= input_devices_seq_next,
	.stop	= input_seq_stop,
	.show	= input_devices_seq_show,
};

static const struct file_operations input_devices_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_devices_open,
	.poll		= input_proc_devices_poll,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

static const struct seq_operations input_handlers_seq_ops = {
	.start	= input_handlers_seq_start,
	.next	= input_handlers_seq_next,
	.stop	= input_seq_stop,
	.show	= input_handlers_seq_show,
};

static const struct file_operations input_handlers_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_handlers_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

#define INPUT_DEV_STRING_ATTR_SHOW(name)				\
static ssize_t input_dev_show_##name(struct device *dev,		\
				     struct device_attribute *attr,	\
				     char *buf)				\
{									\
	struct input_dev *input_dev = to_input_dev(dev);		\
									\
	return scnprintf(buf, PAGE_SIZE, "%s\n",			\
			 input_dev->name ? input_dev->name : "");	\
}									\
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL)

static DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL);

static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap,
			      int max, int add_cr);

static DEVICE_ATTR(properties, S_IRUGO, input_dev_show_properties, NULL);

static struct attribute *input_dev_attrs[] = {
	&dev_attr_name.attr,
	&dev_attr_phys.attr,
	&dev_attr_uniq.attr,
	&dev_attr_modalias.attr,
	&dev_attr_properties.attr,
	NULL
};

static const struct attribute_group input_dev_attr_group = {
	.attrs	= input_dev_attrs,
};

#define INPUT_DEV_ID_ATTR(name)						\
static ssize_t input_dev_show_id_##name(struct device *dev,		\
					struct device_attribute *attr,	\
					char *buf)			\
{									\
	struct input_dev *input_dev = to_input_dev(dev);		\
	return scnprintf(buf, PAGE_SIZE, "%04x\n", input_dev->id.name);	\
}									\
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_id_##name, NULL)

static struct attribute *input_dev_id_attrs[] = {
	&dev_attr_bustype.attr,
	&dev_attr_vendor.attr,
	&dev_attr_product.attr,
	&dev_attr_version.attr,
	NULL
};

static const struct attribute_group input_dev_id_attr_group = {
	.name	= "id",
	.attrs	= input_dev_id_attrs,
};


static int input_proc_handlers_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &input_handlers_seq_ops);
}