/* Id */

/*
 * Copyright (c) 1988-1997 Sam Leffler
 * Copyright (c) 1991-1997 Silicon Graphics, Inc.
 *
 * Permission to use, copy, modify, distribute, and sell this software and 
 * its documentation for any purpose is hereby granted without fee, provided
 * that (i) the above copyright notices and this permission notice appear in
 * all copies of the software and related documentation, and (ii) the names of
 * Sam Leffler and Silicon Graphics may not be used in any advertising or
 * publicity relating to the software without the specific, prior written
 * permission of Sam Leffler and Silicon Graphics.
 * 
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
 * 
 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
 * OF THIS SOFTWARE.
 */

/*
 * TIFF Library.
 *
 * Core Directory Tag Support.
 */
#include "tiffiop.h"
#include <stdlib.h>

/*
 * NB: NB: THIS ARRAY IS ASSUMED TO BE SORTED BY TAG.
 *       If a tag can have both LONG and SHORT types then the LONG must be
 *       placed before the SHORT for writing to work properly.
 *
 * NOTE: The second field (field_readcount) and third field (field_writecount)
 *       sometimes use the values TIFF_VARIABLE (-1), TIFF_VARIABLE2 (-3)
 *       and TIFFTAG_SPP (-2). The macros should be used but would throw off 
 *       the formatting of the code, so please interprete the -1, -2 and -3 
 *       values accordingly.
 */
static const TIFFFieldInfo
tiffFieldInfo[] = {
    { TIFFTAG_SUBFILETYPE,       1, 1,  TIFF_LONG,      FIELD_SUBFILETYPE,
      1,        0,      "SubfileType" },
/* XXX SHORT for compatibility w/ old versions of the library */
    { TIFFTAG_SUBFILETYPE,       1, 1,  TIFF_SHORT,     FIELD_SUBFILETYPE,
      1,        0,      "SubfileType" },
    { TIFFTAG_OSUBFILETYPE,      1, 1,  TIFF_SHORT,     FIELD_SUBFILETYPE,
      1,        0,      "OldSubfileType" },
    { TIFFTAG_IMAGEWIDTH,        1, 1,  TIFF_LONG,      FIELD_IMAGEDIMENSIONS,
      0,        0,      "ImageWidth" },
    { TIFFTAG_IMAGEWIDTH,        1, 1,  TIFF_SHORT,     FIELD_IMAGEDIMENSIONS,
      0,        0,      "ImageWidth" },
    { TIFFTAG_IMAGELENGTH,       1, 1,  TIFF_LONG,      FIELD_IMAGEDIMENSIONS,
      1,        0,      "ImageLength" },
    { TIFFTAG_IMAGELENGTH,       1, 1,  TIFF_SHORT,     FIELD_IMAGEDIMENSIONS,
      1,        0,      "ImageLength" },
    { TIFFTAG_BITSPERSAMPLE,    -1,-1,  TIFF_SHORT,     FIELD_BITSPERSAMPLE,
      0,        0,      "BitsPerSample" },
/* XXX LONG for compatibility with some broken TIFF writers */
    { TIFFTAG_BITSPERSAMPLE,    -1,-1,  TIFF_LONG,      FIELD_BITSPERSAMPLE,
      0,        0,      "BitsPerSample" },
    { TIFFTAG_COMPRESSION,      -1, 1,  TIFF_SHORT,     FIELD_COMPRESSION,
      0,        0,      "Compression" },
/* XXX LONG for compatibility with some broken TIFF writers */
    { TIFFTAG_COMPRESSION,      -1, 1,  TIFF_LONG,      FIELD_COMPRESSION,
      0,        0,      "Compression" },
    { TIFFTAG_PHOTOMETRIC,       1, 1,  TIFF_SHORT,     FIELD_PHOTOMETRIC,
      0,        0,      "PhotometricInterpretation" },
/* XXX LONG for compatibility with some broken TIFF writers */
    { TIFFTAG_PHOTOMETRIC,       1, 1,  TIFF_LONG,      FIELD_PHOTOMETRIC,
      0,        0,      "PhotometricInterpretation" },
    { TIFFTAG_THRESHHOLDING,     1, 1,  TIFF_SHORT,     FIELD_THRESHHOLDING,
      1,        0,      "Threshholding" },
    { TIFFTAG_CELLWIDTH,         1, 1,  TIFF_SHORT,     FIELD_IGNORE,
      1,        0,      "CellWidth" },
    { TIFFTAG_CELLLENGTH,        1, 1,  TIFF_SHORT,     FIELD_IGNORE,
      1,        0,      "CellLength" },
    { TIFFTAG_FILLORDER,         1, 1,  TIFF_SHORT,     FIELD_FILLORDER,
      0,        0,      "FillOrder" },
    { TIFFTAG_DOCUMENTNAME,     -1,-1,  TIFF_ASCII,     FIELD_CUSTOM,
      1,        0,      "DocumentName" },
    { TIFFTAG_IMAGEDESCRIPTION, -1,-1,  TIFF_ASCII,     FIELD_CUSTOM,
      1,        0,      "ImageDescription" },
    { TIFFTAG_MAKE,             -1,-1,  TIFF_ASCII,     FIELD_CUSTOM,
      1,        0,      "Make" },
    { TIFFTAG_MODEL,            -1,-1,  TIFF_ASCII,     FIELD_CUSTOM,
      1,        0,      "Model" },
    { TIFFTAG_STRIPOFFSETS,     -1,-1,  TIFF_LONG,      FIELD_STRIPOFFSETS,
      0,        0,      "StripOffsets" },
    { TIFFTAG_STRIPOFFSETS,     -1,-1,  TIFF_SHORT,     FIELD_STRIPOFFSETS,
      0,        0,      "StripOffsets" },
    { TIFFTAG_ORIENTATION,       1, 1,  TIFF_SHORT,     FIELD_ORIENTATION,
      0,        0,      "Orientation" },
    { TIFFTAG_SAMPLESPERPIXEL,   1, 1,  TIFF_SHORT,     FIELD_SAMPLESPERPIXEL,
      0,        0,      "SamplesPerPixel" },
    { TIFFTAG_ROWSPERSTRIP,      1, 1,  TIFF_LONG,      FIELD_ROWSPERSTRIP,
      0,        0,      "RowsPerStrip" },
    { TIFFTAG_ROWSPERSTRIP,      1, 1,  TIFF_SHORT,     FIELD_ROWSPERSTRIP,
      0,        0,      "RowsPerStrip" },
    { TIFFTAG_STRIPBYTECOUNTS,  -1,-1,  TIFF_LONG,      FIELD_STRIPBYTECOUNTS,
      0,        0,      "StripByteCounts" },
    { TIFFTAG_STRIPBYTECOUNTS,  -1,-1,  TIFF_SHORT,     FIELD_STRIPBYTECOUNTS,
      0,        0,      "StripByteCounts" },
    { TIFFTAG_MINSAMPLEVALUE,   -2,-1,  TIFF_SHORT,     FIELD_MINSAMPLEVALUE,
      1,        0,      "MinSampleValue" },
    { TIFFTAG_MAXSAMPLEVALUE,   -2,-1,  TIFF_SHORT,     FIELD_MAXSAMPLEVALUE,
      1,        0,      "MaxSampleValue" },
    { TIFFTAG_XRESOLUTION,       1, 1,  TIFF_RATIONAL,  FIELD_RESOLUTION,
      1,        0,      "XResolution" },
    { TIFFTAG_YRESOLUTION,       1, 1,  TIFF_RATIONAL,  FIELD_RESOLUTION,
      1,        0,      "YResolution" },
    { TIFFTAG_PLANARCONFIG,      1, 1,  TIFF_SHORT,     FIELD_PLANARCONFIG,
      0,        0,      "PlanarConfiguration" },
    { TIFFTAG_PAGENAME,         -1,-1,  TIFF_ASCII,     FIELD_CUSTOM,
      1,        0,      "PageName" },
    { TIFFTAG_XPOSITION,         1, 1,  TIFF_RATIONAL,  FIELD_POSITION,
      1,        0,      "XPosition" },
    { TIFFTAG_YPOSITION,         1, 1,  TIFF_RATIONAL,  FIELD_POSITION,
      1,        0,      "YPosition" },
    { TIFFTAG_FREEOFFSETS,      -1,-1,  TIFF_LONG,      FIELD_IGNORE,
      0,        0,      "FreeOffsets" },
    { TIFFTAG_FREEBYTECOUNTS,   -1,-1,  TIFF_LONG,      FIELD_IGNORE,
      0,        0,      "FreeByteCounts" },
    { TIFFTAG_GRAYRESPONSEUNIT,  1, 1,  TIFF_SHORT,     FIELD_IGNORE,
      1,        0,      "GrayResponseUnit" },
    { TIFFTAG_GRAYRESPONSECURVE,-1,-1,  TIFF_SHORT,     FIELD_IGNORE,
      1,        0,      "GrayResponseCurve" },
    { TIFFTAG_RESOLUTIONUNIT,    1, 1,  TIFF_SHORT,     FIELD_RESOLUTIONUNIT,
      1,        0,      "ResolutionUnit" },
    { TIFFTAG_PAGENUMBER,        2, 2,  TIFF_SHORT,     FIELD_PAGENUMBER,
      1,        0,      "PageNumber" },
    { TIFFTAG_COLORRESPONSEUNIT, 1, 1,  TIFF_SHORT,     FIELD_IGNORE,
      1,        0,      "ColorResponseUnit" },
    { TIFFTAG_TRANSFERFUNCTION, -1,-1,  TIFF_SHORT,     FIELD_TRANSFERFUNCTION,
      1,        0,      "TransferFunction" },
    { TIFFTAG_SOFTWARE,         -1,-1,  TIFF_ASCII,     FIELD_CUSTOM,
      1,        0,      "Software" },
    { TIFFTAG_DATETIME,         20,20,  TIFF_ASCII,     FIELD_CUSTOM,
      1,        0,      "DateTime" },
    { TIFFTAG_ARTIST,           -1,-1,  TIFF_ASCII,     FIELD_CUSTOM,
      1,        0,      "Artist" },
    { TIFFTAG_HOSTCOMPUTER,     -1,-1,  TIFF_ASCII,     FIELD_CUSTOM,
      1,        0,      "HostComputer" },
    { TIFFTAG_WHITEPOINT,        2, 2,  TIFF_RATIONAL,  FIELD_CUSTOM,
      1,        0,      "WhitePoint" },
    { TIFFTAG_PRIMARYCHROMATICITIES,6,6,TIFF_RATIONAL,  FIELD_CUSTOM,
      1,        0,      "PrimaryChromaticities" },
    { TIFFTAG_COLORMAP,         -1,-1,  TIFF_SHORT,     FIELD_COLORMAP,
      1,        0,      "ColorMap" },
    { TIFFTAG_HALFTONEHINTS,     2, 2,  TIFF_SHORT,     FIELD_HALFTONEHINTS,
      1,        0,      "HalftoneHints" },
    { TIFFTAG_TILEWIDTH,         1, 1,  TIFF_LONG,      FIELD_TILEDIMENSIONS,
      0,        0,      "TileWidth" },
    { TIFFTAG_TILEWIDTH,         1, 1,  TIFF_SHORT,     FIELD_TILEDIMENSIONS,
      0,        0,      "TileWidth" },
    { TIFFTAG_TILELENGTH,        1, 1,  TIFF_LONG,      FIELD_TILEDIMENSIONS,
      0,        0,      "TileLength" },
    { TIFFTAG_TILELENGTH,        1, 1,  TIFF_SHORT,     FIELD_TILEDIMENSIONS,
      0,        0,      "TileLength" },
    { TIFFTAG_TILEOFFSETS,      -1, 1,  TIFF_LONG,      FIELD_STRIPOFFSETS,
      0,        0,      "TileOffsets" },
    { TIFFTAG_TILEBYTECOUNTS,   -1, 1,  TIFF_LONG,      FIELD_STRIPBYTECOUNTS,
      0,        0,      "TileByteCounts" },
    { TIFFTAG_TILEBYTECOUNTS,   -1, 1,  TIFF_SHORT,     FIELD_STRIPBYTECOUNTS,
      0,        0,      "TileByteCounts" },
    { TIFFTAG_SUBIFD,           -1,-1,  TIFF_IFD,       FIELD_SUBIFD,
      1,        1,      "SubIFD" },
    { TIFFTAG_SUBIFD,           -1,-1,  TIFF_LONG,      FIELD_SUBIFD,
      1,        1,      "SubIFD" },
    { TIFFTAG_INKSET,            1, 1,  TIFF_SHORT,     FIELD_CUSTOM,
      0,        0,      "InkSet" },
    { TIFFTAG_INKNAMES,         -1,-1,  TIFF_ASCII,     FIELD_INKNAMES,
      1,        1,      "InkNames" },
    { TIFFTAG_NUMBEROFINKS,      1, 1,  TIFF_SHORT,     FIELD_CUSTOM,
      1,        0,      "NumberOfInks" },
    { TIFFTAG_DOTRANGE,          2, 2,  TIFF_SHORT,     FIELD_CUSTOM,
      0,        0,      "DotRange" },
    { TIFFTAG_DOTRANGE,          2, 2,  TIFF_BYTE,      FIELD_CUSTOM,
      0,        0,      "DotRange" },
    { TIFFTAG_TARGETPRINTER,    -1,-1,  TIFF_ASCII,     FIELD_CUSTOM,
      1,        0,      "TargetPrinter" },
    { TIFFTAG_EXTRASAMPLES,     -1,-1,  TIFF_SHORT,     FIELD_EXTRASAMPLES,
      0,        1,      "ExtraSamples" },
/* XXX for bogus Adobe Photoshop v2.5 files */
    { TIFFTAG_EXTRASAMPLES,     -1,-1,  TIFF_BYTE,      FIELD_EXTRASAMPLES,
      0,        1,      "ExtraSamples" },
    { TIFFTAG_SAMPLEFORMAT,     -1,-1,  TIFF_SHORT,     FIELD_SAMPLEFORMAT,
      0,        0,      "SampleFormat" },
    { TIFFTAG_SMINSAMPLEVALUE,  -2,-1,  TIFF_ANY,       FIELD_SMINSAMPLEVALUE,
      1,        0,      "SMinSampleValue" },
    { TIFFTAG_SMAXSAMPLEVALUE,  -2,-1,  TIFF_ANY,       FIELD_SMAXSAMPLEVALUE,
      1,        0,      "SMaxSampleValue" },
    { TIFFTAG_CLIPPATH,         -1, -3, TIFF_BYTE,      FIELD_CUSTOM,
      0,        1,      "ClipPath" },
    { TIFFTAG_XCLIPPATHUNITS,    1, 1,  TIFF_SLONG,     FIELD_CUSTOM,
      0,        0,      "XClipPathUnits" },
    { TIFFTAG_XCLIPPATHUNITS,    1, 1,  TIFF_SSHORT,    FIELD_CUSTOM,
      0,        0,      "XClipPathUnits" },
    { TIFFTAG_XCLIPPATHUNITS,    1, 1,  TIFF_SBYTE,     FIELD_CUSTOM,
      0,        0,      "XClipPathUnits" },
    { TIFFTAG_YCLIPPATHUNITS,    1, 1,  TIFF_SLONG,     FIELD_CUSTOM,
      0,        0,      "YClipPathUnits" },
    { TIFFTAG_YCLIPPATHUNITS,    1, 1,  TIFF_SSHORT,    FIELD_CUSTOM,
      0,        0,      "YClipPathUnits" },
    { TIFFTAG_YCLIPPATHUNITS,    1, 1,  TIFF_SBYTE,     FIELD_CUSTOM,
      0,        0,      "YClipPathUnits" },
    { TIFFTAG_YCBCRCOEFFICIENTS, 3, 3,  TIFF_RATIONAL,  FIELD_CUSTOM,
      0,        0,      "YCbCrCoefficients" },
    { TIFFTAG_YCBCRSUBSAMPLING,  2, 2,  TIFF_SHORT,     FIELD_YCBCRSUBSAMPLING,
      0,        0,      "YCbCrSubsampling" },
    { TIFFTAG_YCBCRPOSITIONING,  1, 1,  TIFF_SHORT,     FIELD_YCBCRPOSITIONING,
      0,        0,      "YCbCrPositioning" },
    { TIFFTAG_REFERENCEBLACKWHITE, 6, 6, TIFF_RATIONAL, FIELD_CUSTOM,
      1,        0,      "ReferenceBlackWhite" },
/* XXX temporarily accept LONG for backwards compatibility */
    { TIFFTAG_REFERENCEBLACKWHITE, 6, 6, TIFF_LONG,     FIELD_CUSTOM,
      1,        0,      "ReferenceBlackWhite" },
    { TIFFTAG_XMLPACKET,        -3,-3,  TIFF_BYTE,      FIELD_CUSTOM,
      0,        1,      "XMLPacket" },
/* begin SGI tags */
    { TIFFTAG_MATTEING,          1, 1,  TIFF_SHORT,     FIELD_EXTRASAMPLES,
      0,        0,      "Matteing" },
    { TIFFTAG_DATATYPE,         -2,-1,  TIFF_SHORT,     FIELD_SAMPLEFORMAT,
      0,        0,      "DataType" },
    { TIFFTAG_IMAGEDEPTH,        1, 1,  TIFF_LONG,      FIELD_IMAGEDEPTH,
      0,        0,      "ImageDepth" },
    { TIFFTAG_IMAGEDEPTH,        1, 1,  TIFF_SHORT,     FIELD_IMAGEDEPTH,
      0,        0,      "ImageDepth" },
    { TIFFTAG_TILEDEPTH,         1, 1,  TIFF_LONG,      FIELD_TILEDEPTH,
      0,        0,      "TileDepth" },
    { TIFFTAG_TILEDEPTH,         1, 1,  TIFF_SHORT,     FIELD_TILEDEPTH,
      0,        0,      "TileDepth" },
/* end SGI tags */
/* begin Pixar tags */
    { TIFFTAG_PIXAR_IMAGEFULLWIDTH,  1, 1, TIFF_LONG,   FIELD_CUSTOM,
      1,        0,      "ImageFullWidth" },
    { TIFFTAG_PIXAR_IMAGEFULLLENGTH, 1, 1, TIFF_LONG,   FIELD_CUSTOM,
      1,        0,      "ImageFullLength" },
    { TIFFTAG_PIXAR_TEXTUREFORMAT,  -1, -1, TIFF_ASCII, FIELD_CUSTOM,
      1,        0,      "TextureFormat" },
    { TIFFTAG_PIXAR_WRAPMODES,      -1, -1, TIFF_ASCII, FIELD_CUSTOM,
      1,        0,      "TextureWrapModes" },
    { TIFFTAG_PIXAR_FOVCOT,          1, 1, TIFF_FLOAT,  FIELD_CUSTOM,
      1,        0,      "FieldOfViewCotangent" },
    { TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN,       16,16,  TIFF_FLOAT,
      FIELD_CUSTOM,     1,      0,      "MatrixWorldToScreen" },
    { TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA,       16,16,  TIFF_FLOAT,
       FIELD_CUSTOM,    1,      0,      "MatrixWorldToCamera" },
    { TIFFTAG_COPYRIGHT,        -1, -1, TIFF_ASCII,     FIELD_CUSTOM,
      1,        0,      "Copyright" },
/* end Pixar tags */
    { TIFFTAG_RICHTIFFIPTC, -3, -3,     TIFF_LONG,      FIELD_CUSTOM, 
      0,    1,   "RichTIFFIPTC" },
    { TIFFTAG_PHOTOSHOP,    -3, -3,     TIFF_BYTE,      FIELD_CUSTOM, 
      0,    1,   "Photoshop" },
    { TIFFTAG_EXIFIFD,          1, 1,   TIFF_LONG,      FIELD_CUSTOM,
      0,        0,      "EXIFIFDOffset" },
    { TIFFTAG_ICCPROFILE,       -3, -3, TIFF_UNDEFINED, FIELD_CUSTOM,
      0,        1,      "ICC Profile" },
    { TIFFTAG_GPSIFD,           1, 1,   TIFF_LONG,      FIELD_CUSTOM,
      0,        0,      "GPSIFDOffset" },
    { TIFFTAG_STONITS,           1, 1,  TIFF_DOUBLE,    FIELD_CUSTOM,
      0,        0,      "StoNits" },
    { TIFFTAG_INTEROPERABILITYIFD, 1, 1, TIFF_LONG,     FIELD_CUSTOM,
      0,        0,      "InteroperabilityIFDOffset" },
/* begin DNG tags */
    { TIFFTAG_DNGVERSION,       4, 4,   TIFF_BYTE,      FIELD_CUSTOM, 
      0,        0,      "DNGVersion" },
    { TIFFTAG_DNGBACKWARDVERSION, 4, 4, TIFF_BYTE,      FIELD_CUSTOM, 
      0,        0,      "DNGBackwardVersion" },
    { TIFFTAG_UNIQUECAMERAMODEL,    -1, -1, TIFF_ASCII, FIELD_CUSTOM,
      1,        0,      "UniqueCameraModel" },
    { TIFFTAG_LOCALIZEDCAMERAMODEL, -1, -1, TIFF_ASCII, FIELD_CUSTOM,
      1,        0,      "LocalizedCameraModel" },
    { TIFFTAG_LOCALIZEDCAMERAMODEL, -1, -1, TIFF_BYTE,  FIELD_CUSTOM,
      1,        1,      "LocalizedCameraModel" },
    { TIFFTAG_CFAPLANECOLOR,    -1, -1, TIFF_BYTE,      FIELD_CUSTOM, 
      0,        1,      "CFAPlaneColor" },
    { TIFFTAG_CFALAYOUT,        1, 1,   TIFF_SHORT,     FIELD_CUSTOM, 
      0,        0,      "CFALayout" },
    { TIFFTAG_LINEARIZATIONTABLE, -1, -1, TIFF_SHORT,   FIELD_CUSTOM, 
      0,        1,      "LinearizationTable" },
    { TIFFTAG_BLACKLEVELREPEATDIM, 2, 2, TIFF_SHORT,    FIELD_CUSTOM, 
      0,        0,      "BlackLevelRepeatDim" },
    { TIFFTAG_BLACKLEVEL,       -1, -1, TIFF_LONG,      FIELD_CUSTOM, 
      0,        1,      "BlackLevel" },
    { TIFFTAG_BLACKLEVEL,       -1, -1, TIFF_SHORT,     FIELD_CUSTOM, 
      0,        1,      "BlackLevel" },
    { TIFFTAG_BLACKLEVEL,       -1, -1, TIFF_RATIONAL,  FIELD_CUSTOM, 
      0,        1,      "BlackLevel" },
    { TIFFTAG_BLACKLEVELDELTAH, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, 
      0,        1,      "BlackLevelDeltaH" },
    { TIFFTAG_BLACKLEVELDELTAV, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, 
      0,        1,      "BlackLevelDeltaV" },
    { TIFFTAG_WHITELEVEL,       -2, -2, TIFF_LONG,      FIELD_CUSTOM, 
      0,        0,      "WhiteLevel" },
    { TIFFTAG_WHITELEVEL,       -2, -2, TIFF_SHORT,     FIELD_CUSTOM, 
      0,        0,      "WhiteLevel" },
    { TIFFTAG_DEFAULTSCALE,     2, 2,   TIFF_RATIONAL,  FIELD_CUSTOM, 
      0,        0,      "DefaultScale" },
    { TIFFTAG_BESTQUALITYSCALE, 1, 1,   TIFF_RATIONAL,  FIELD_CUSTOM, 
      0,        0,      "BestQualityScale" },
    { TIFFTAG_DEFAULTCROPORIGIN,        2, 2,   TIFF_LONG,      FIELD_CUSTOM, 
      0,        0,      "DefaultCropOrigin" },
    { TIFFTAG_DEFAULTCROPORIGIN,        2, 2,   TIFF_SHORT,     FIELD_CUSTOM, 
      0,        0,      "DefaultCropOrigin" },
    { TIFFTAG_DEFAULTCROPORIGIN,        2, 2,   TIFF_RATIONAL,  FIELD_CUSTOM, 
      0,        0,      "DefaultCropOrigin" },
    { TIFFTAG_DEFAULTCROPSIZE,  2, 2,   TIFF_LONG,      FIELD_CUSTOM, 
      0,        0,      "DefaultCropSize" },
    { TIFFTAG_DEFAULTCROPSIZE,  2, 2,   TIFF_SHORT,     FIELD_CUSTOM, 
      0,        0,      "DefaultCropSize" },
    { TIFFTAG_DEFAULTCROPSIZE,  2, 2,   TIFF_RATIONAL,  FIELD_CUSTOM, 
      0,        0,      "DefaultCropSize" },
    { TIFFTAG_COLORMATRIX1,     -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, 
      0,        1,      "ColorMatrix1" },
    { TIFFTAG_COLORMATRIX2,     -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, 
      0,        1,      "ColorMatrix2" },
    { TIFFTAG_CAMERACALIBRATION1,       -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, 
      0,        1,      "CameraCalibration1" },
    { TIFFTAG_CAMERACALIBRATION2,       -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, 
      0,        1,      "CameraCalibration2" },
    { TIFFTAG_REDUCTIONMATRIX1, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, 
      0,        1,      "ReductionMatrix1" },
    { TIFFTAG_REDUCTIONMATRIX2, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, 
      0,        1,      "ReductionMatrix2" },
    { TIFFTAG_ANALOGBALANCE,    -1, -1, TIFF_RATIONAL,  FIELD_CUSTOM, 
      0,        1,      "AnalogBalance" },
    { TIFFTAG_ASSHOTNEUTRAL,    -1, -1, TIFF_SHORT,     FIELD_CUSTOM, 
      0,        1,      "AsShotNeutral" },
    { TIFFTAG_ASSHOTNEUTRAL,    -1, -1, TIFF_RATIONAL,  FIELD_CUSTOM, 
      0,        1,      "AsShotNeutral" },
    { TIFFTAG_ASSHOTWHITEXY,    2, 2,   TIFF_RATIONAL,  FIELD_CUSTOM, 
      0,        0,      "AsShotWhiteXY" },
    { TIFFTAG_BASELINEEXPOSURE, 1, 1,   TIFF_SRATIONAL, FIELD_CUSTOM, 
      0,        0,      "BaselineExposure" },
    { TIFFTAG_BASELINENOISE,    1, 1,   TIFF_RATIONAL,  FIELD_CUSTOM, 
      0,        0,      "BaselineNoise" },
    { TIFFTAG_BASELINESHARPNESS,        1, 1,   TIFF_RATIONAL,  FIELD_CUSTOM, 
      0,        0,      "BaselineSharpness" },
    { TIFFTAG_BAYERGREENSPLIT,  1, 1,   TIFF_LONG,      FIELD_CUSTOM, 
      0,        0,      "BayerGreenSplit" },
    { TIFFTAG_LINEARRESPONSELIMIT,      1, 1,   TIFF_RATIONAL,  FIELD_CUSTOM, 
      0,        0,      "LinearResponseLimit" },
    { TIFFTAG_CAMERASERIALNUMBER,    -1, -1, TIFF_ASCII,        FIELD_CUSTOM,
      1,        0,      "CameraSerialNumber" },
    { TIFFTAG_LENSINFO, 4, 4,   TIFF_RATIONAL,  FIELD_CUSTOM, 
      0,        0,      "LensInfo" },
    { TIFFTAG_CHROMABLURRADIUS, 1, 1,   TIFF_RATIONAL,  FIELD_CUSTOM, 
      0,        0,      "ChromaBlurRadius" },
    { TIFFTAG_ANTIALIASSTRENGTH,        1, 1,   TIFF_RATIONAL,  FIELD_CUSTOM, 
      0,        0,      "AntiAliasStrength" },
    { TIFFTAG_SHADOWSCALE,      1, 1,   TIFF_RATIONAL,  FIELD_CUSTOM, 
      0,        0,      "ShadowScale" },
    { TIFFTAG_DNGPRIVATEDATA,    -1, -1, TIFF_BYTE,     FIELD_CUSTOM,
      0,        1,      "DNGPrivateData" },
    { TIFFTAG_MAKERNOTESAFETY,  1, 1,   TIFF_SHORT,     FIELD_CUSTOM, 
      0,        0,      "MakerNoteSafety" },
    { TIFFTAG_CALIBRATIONILLUMINANT1,   1, 1,   TIFF_SHORT,     FIELD_CUSTOM, 
      0,        0,      "CalibrationIlluminant1" },
    { TIFFTAG_CALIBRATIONILLUMINANT2,   1, 1,   TIFF_SHORT,     FIELD_CUSTOM, 
      0,        0,      "CalibrationIlluminant2" },
    { TIFFTAG_RAWDATAUNIQUEID,  16, 16, TIFF_BYTE,      FIELD_CUSTOM, 
      0,        0,      "RawDataUniqueID" },
    { TIFFTAG_ORIGINALRAWFILENAME,    -1, -1, TIFF_ASCII,       FIELD_CUSTOM,
      1,        0,      "OriginalRawFileName" },
    { TIFFTAG_ORIGINALRAWFILENAME,    -1, -1, TIFF_BYTE,        FIELD_CUSTOM,
      1,        1,      "OriginalRawFileName" },
    { TIFFTAG_ORIGINALRAWFILEDATA,    -1, -1, TIFF_UNDEFINED,   FIELD_CUSTOM,
      0,        1,      "OriginalRawFileData" },
    { TIFFTAG_ACTIVEAREA,       4, 4,   TIFF_LONG,      FIELD_CUSTOM, 
      0,        0,      "ActiveArea" },
    { TIFFTAG_ACTIVEAREA,       4, 4,   TIFF_SHORT,     FIELD_CUSTOM, 
      0,        0,      "ActiveArea" },
    { TIFFTAG_MASKEDAREAS,      -1, -1, TIFF_LONG,      FIELD_CUSTOM, 
      0,        1,      "MaskedAreas" },
    { TIFFTAG_ASSHOTICCPROFILE,    -1, -1, TIFF_UNDEFINED,      FIELD_CUSTOM,
      0,        1,      "AsShotICCProfile" },
    { TIFFTAG_ASSHOTPREPROFILEMATRIX,   -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, 
      0,        1,      "AsShotPreProfileMatrix" },
    { TIFFTAG_CURRENTICCPROFILE,    -1, -1, TIFF_UNDEFINED,     FIELD_CUSTOM,
      0,        1,      "CurrentICCProfile" },
    { TIFFTAG_CURRENTPREPROFILEMATRIX,  -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, 
      0,        1,      "CurrentPreProfileMatrix" },
/* end DNG tags */
};

static const TIFFFieldInfo
exifFieldInfo[] = {
    { EXIFTAG_EXPOSURETIME,     1, 1,           TIFF_RATIONAL,  FIELD_CUSTOM, 
      1,        0,      "ExposureTime" },
    { EXIFTAG_FNUMBER,          1, 1,           TIFF_RATIONAL,  FIELD_CUSTOM, 
      1,        0,      "FNumber" },
    { EXIFTAG_EXPOSUREPROGRAM,  1, 1,           TIFF_SHORT,     FIELD_CUSTOM,
      1,        0,      "ExposureProgram" },
    { EXIFTAG_SPECTRALSENSITIVITY,    -1, -1,   TIFF_ASCII,     FIELD_CUSTOM,
      1,        0,      "SpectralSensitivity" },
    { EXIFTAG_ISOSPEEDRATINGS,  -1, -1,         TIFF_SHORT,     FIELD_CUSTOM,
      1,        1,      "ISOSpeedRatings" },
    { EXIFTAG_OECF,     -1, -1,                 TIFF_UNDEFINED, FIELD_CUSTOM,
      1,        1,      "OptoelectricConversionFactor" },
    { EXIFTAG_EXIFVERSION,      4, 4,           TIFF_UNDEFINED, FIELD_CUSTOM,
      1,        0,      "ExifVersion" },
    { EXIFTAG_DATETIMEORIGINAL, 20, 20,         TIFF_ASCII,     FIELD_CUSTOM,
      1,        0,      "DateTimeOriginal" },
    { EXIFTAG_DATETIMEDIGITIZED, 20, 20,        TIFF_ASCII,     FIELD_CUSTOM,
      1,        0,      "DateTimeDigitized" },
    { EXIFTAG_COMPONENTSCONFIGURATION,   4, 4,  TIFF_UNDEFINED, FIELD_CUSTOM,
      1,        0,      "ComponentsConfiguration" },
    { EXIFTAG_COMPRESSEDBITSPERPIXEL,    1, 1,  TIFF_RATIONAL,  FIELD_CUSTOM,
      1,        0,      "CompressedBitsPerPixel" },
    { EXIFTAG_SHUTTERSPEEDVALUE,        1, 1,   TIFF_SRATIONAL, FIELD_CUSTOM, 
      1,        0,      "ShutterSpeedValue" },
    { EXIFTAG_APERTUREVALUE,    1, 1,           TIFF_RATIONAL,  FIELD_CUSTOM, 
      1,        0,      "ApertureValue" },
    { EXIFTAG_BRIGHTNESSVALUE,  1, 1,           TIFF_SRATIONAL, FIELD_CUSTOM, 
      1,        0,      "BrightnessValue" },
    { EXIFTAG_EXPOSUREBIASVALUE,        1, 1,   TIFF_SRATIONAL, FIELD_CUSTOM, 
      1,        0,      "ExposureBiasValue" },
    { EXIFTAG_MAXAPERTUREVALUE, 1, 1,           TIFF_RATIONAL,  FIELD_CUSTOM, 
      1,        0,      "MaxApertureValue" },
    { EXIFTAG_SUBJECTDISTANCE,  1, 1,           TIFF_RATIONAL,  FIELD_CUSTOM, 
      1,        0,      "SubjectDistance" },
    { EXIFTAG_METERINGMODE,     1, 1,           TIFF_SHORT,     FIELD_CUSTOM,
      1,        0,      "MeteringMode" },
    { EXIFTAG_LIGHTSOURCE,      1, 1,           TIFF_SHORT,     FIELD_CUSTOM,
      1,        0,      "LightSource" },
    { EXIFTAG_FLASH,    1, 1,                   TIFF_SHORT,     FIELD_CUSTOM,
      1,        0,      "Flash" },
    { EXIFTAG_FOCALLENGTH,      1, 1,           TIFF_RATIONAL,  FIELD_CUSTOM, 
      1,        0,      "FocalLength" },
    { EXIFTAG_SUBJECTAREA,      -1, -1,         TIFF_SHORT,     FIELD_CUSTOM,
      1,        1,      "SubjectArea" },
    { EXIFTAG_MAKERNOTE,        -1, -1,         TIFF_UNDEFINED, FIELD_CUSTOM,
      1,        1,      "MakerNote" },
    { EXIFTAG_USERCOMMENT,      -1, -1,         TIFF_UNDEFINED, FIELD_CUSTOM,
      1,        1,      "UserComment" },
    { EXIFTAG_SUBSECTIME,    -1, -1,            TIFF_ASCII,     FIELD_CUSTOM,
      1,        0,      "SubSecTime" },
    { EXIFTAG_SUBSECTIMEORIGINAL, -1, -1,       TIFF_ASCII,     FIELD_CUSTOM,
      1,        0,      "SubSecTimeOriginal" },
    { EXIFTAG_SUBSECTIMEDIGITIZED,-1, -1,       TIFF_ASCII,     FIELD_CUSTOM,
      1,        0,      "SubSecTimeDigitized" },
    { EXIFTAG_FLASHPIXVERSION,  4, 4,           TIFF_UNDEFINED, FIELD_CUSTOM,
      1,        0,      "FlashpixVersion" },
    { EXIFTAG_PIXELXDIMENSION,  1, 1,           TIFF_LONG,      FIELD_CUSTOM,
      1,        0,      "PixelXDimension" },
    { EXIFTAG_PIXELXDIMENSION,  1, 1,           TIFF_SHORT,     FIELD_CUSTOM,
      1,        0,      "PixelXDimension" },
    { EXIFTAG_PIXELYDIMENSION,  1, 1,           TIFF_LONG,      FIELD_CUSTOM,
      1,        0,      "PixelYDimension" },
    { EXIFTAG_PIXELYDIMENSION,  1, 1,           TIFF_SHORT,     FIELD_CUSTOM,
      1,        0,      "PixelYDimension" },
    { EXIFTAG_RELATEDSOUNDFILE, 13, 13,         TIFF_ASCII,     FIELD_CUSTOM,
      1,        0,      "RelatedSoundFile" },
    { EXIFTAG_FLASHENERGY,      1, 1,           TIFF_RATIONAL,  FIELD_CUSTOM, 
      1,        0,      "FlashEnergy" },
    { EXIFTAG_SPATIALFREQUENCYRESPONSE, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM,
      1,        1,      "SpatialFrequencyResponse" },
    { EXIFTAG_FOCALPLANEXRESOLUTION,    1, 1,   TIFF_RATIONAL,  FIELD_CUSTOM, 
      1,        0,      "FocalPlaneXResolution" },
    { EXIFTAG_FOCALPLANEYRESOLUTION,    1, 1,   TIFF_RATIONAL,  FIELD_CUSTOM, 
      1,        0,      "FocalPlaneYResolution" },
    { EXIFTAG_FOCALPLANERESOLUTIONUNIT, 1, 1,   TIFF_SHORT,     FIELD_CUSTOM,
      1,        0,      "FocalPlaneResolutionUnit" },
    { EXIFTAG_SUBJECTLOCATION,  2, 2,           TIFF_SHORT,     FIELD_CUSTOM,
      1,        0,      "SubjectLocation" },
    { EXIFTAG_EXPOSUREINDEX,    1, 1,           TIFF_RATIONAL,  FIELD_CUSTOM, 
      1,        0,      "ExposureIndex" },
    { EXIFTAG_SENSINGMETHOD,    1, 1,           TIFF_SHORT,     FIELD_CUSTOM,
      1,        0,      "SensingMethod" },
    { EXIFTAG_FILESOURCE,       1, 1,           TIFF_UNDEFINED, FIELD_CUSTOM,
      1,        0,      "FileSource" },
    { EXIFTAG_SCENETYPE,        1, 1,           TIFF_UNDEFINED, FIELD_CUSTOM,
      1,        0,      "SceneType" },
    { EXIFTAG_CFAPATTERN,       -1, -1,         TIFF_UNDEFINED, FIELD_CUSTOM,
      1,        1,      "CFAPattern" },
    { EXIFTAG_CUSTOMRENDERED,   1, 1,           TIFF_SHORT,     FIELD_CUSTOM,
      1,        0,      "CustomRendered" },
    { EXIFTAG_EXPOSUREMODE,     1, 1,           TIFF_SHORT,     FIELD_CUSTOM,
      1,        0,      "ExposureMode" },
    { EXIFTAG_WHITEBALANCE,     1, 1,           TIFF_SHORT,     FIELD_CUSTOM,
      1,        0,      "WhiteBalance" },
    { EXIFTAG_DIGITALZOOMRATIO, 1, 1,           TIFF_RATIONAL,  FIELD_CUSTOM, 
      1,        0,      "DigitalZoomRatio" },
    { EXIFTAG_FOCALLENGTHIN35MMFILM, 1, 1,      TIFF_SHORT,     FIELD_CUSTOM,
      1,        0,      "FocalLengthIn35mmFilm" },
    { EXIFTAG_SCENECAPTURETYPE, 1, 1,           TIFF_SHORT,     FIELD_CUSTOM,
      1,        0,      "SceneCaptureType" },
    { EXIFTAG_GAINCONTROL,      1, 1,           TIFF_RATIONAL,  FIELD_CUSTOM, 
      1,        0,      "GainControl" },
    { EXIFTAG_CONTRAST,         1, 1,           TIFF_SHORT,     FIELD_CUSTOM,
      1,        0,      "Contrast" },
    { EXIFTAG_SATURATION,       1, 1,           TIFF_SHORT,     FIELD_CUSTOM,
      1,        0,      "Saturation" },
    { EXIFTAG_SHARPNESS,        1, 1,           TIFF_SHORT,     FIELD_CUSTOM,
      1,        0,      "Sharpness" },
    { EXIFTAG_DEVICESETTINGDESCRIPTION, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM,
      1,        1,      "DeviceSettingDescription" },
    { EXIFTAG_SUBJECTDISTANCERANGE, 1, 1,       TIFF_SHORT,     FIELD_CUSTOM,
      1,        0,      "SubjectDistanceRange" },
    { EXIFTAG_IMAGEUNIQUEID,    33, 33,         TIFF_ASCII,     FIELD_CUSTOM,
      1,        0,      "ImageUniqueID" }
};

const TIFFFieldInfo *
_TIFFGetFieldInfo(size_t *size)
{
        *size = TIFFArrayCount(tiffFieldInfo);
        return tiffFieldInfo;
}

const TIFFFieldInfo *
_TIFFGetExifFieldInfo(size_t *size)
{
        *size = TIFFArrayCount(exifFieldInfo);
        return exifFieldInfo;
}

void
_TIFFSetupFieldInfo(TIFF* tif, const TIFFFieldInfo info[], size_t n)
{
        if (tif->tif_fieldinfo) {
                size_t  i;

                for (i = 0; i < tif->tif_nfields; i++) 
                {
                        TIFFFieldInfo *fld = tif->tif_fieldinfo[i];
                        if (fld->field_bit == FIELD_CUSTOM && 
                                strncmp("Tag ", fld->field_name, 4) == 0) {
                                        _TIFFfree(fld->field_name);
                                        _TIFFfree(fld);
                                }
                }   
      
                _TIFFfree(tif->tif_fieldinfo);
                tif->tif_nfields = 0;
        }
        _TIFFMergeFieldInfo(tif, info, n);
}

static int
tagCompare(const void* a, const void* b)
{
        const TIFFFieldInfo* ta = *(const TIFFFieldInfo**) a;
        const TIFFFieldInfo* tb = *(const TIFFFieldInfo**) b;
        /* NB: be careful of return values for 16-bit platforms */
        if (ta->field_tag != tb->field_tag)
                return (ta->field_tag < tb->field_tag ? -1 : 1);
        else
                return ((int)tb->field_type - (int)ta->field_type);
}

static int
tagNameCompare(const void* a, const void* b)
{
        const TIFFFieldInfo* ta = *(const TIFFFieldInfo**) a;
        const TIFFFieldInfo* tb = *(const TIFFFieldInfo**) b;

        return strcmp(ta->field_name, tb->field_name);
}

void
_TIFFMergeFieldInfo(TIFF* tif, const TIFFFieldInfo info[], int n)
{
        TIFFFieldInfo** tp;
        int i;

        tif->tif_foundfield = NULL;

        if (tif->tif_nfields > 0) {
                tif->tif_fieldinfo = (TIFFFieldInfo**)
                    _TIFFrealloc(tif->tif_fieldinfo,
                        (tif->tif_nfields+n) * sizeof (TIFFFieldInfo*));
        } else {
                tif->tif_fieldinfo = (TIFFFieldInfo**)
                    _TIFFmalloc(n * sizeof (TIFFFieldInfo*));
        }
        assert(tif->tif_fieldinfo != NULL);
        tp = tif->tif_fieldinfo + tif->tif_nfields;
        for (i = 0; i < n; i++)
                *tp++ = (TIFFFieldInfo*) (info + i);    /* XXX */

        /* Sort the field info by tag number */
        qsort(tif->tif_fieldinfo, tif->tif_nfields += n,
              sizeof (TIFFFieldInfo*), tagCompare);
}

void
_TIFFPrintFieldInfo(TIFF* tif, FILE* fd)
{
        size_t i;

        fprintf(fd, "%s: \n", tif->tif_name);
        for (i = 0; i < tif->tif_nfields; i++) {
                const TIFFFieldInfo* fip = tif->tif_fieldinfo[i];
                fprintf(fd, "field[%2d] %5lu, %2d, %2d, %d, %2d, %5s, %5s, %s\n"
                        , (int)i
                        , (unsigned long) fip->field_tag
                        , fip->field_readcount, fip->field_writecount
                        , fip->field_type
                        , fip->field_bit
                        , fip->field_oktochange ? "TRUE" : "FALSE"
                        , fip->field_passcount ? "TRUE" : "FALSE"
                        , fip->field_name
                );
        }
}

/*
 * Return size of TIFFDataType in bytes
 */
int
TIFFDataWidth(TIFFDataType type)
{
        switch(type)
        {
        case 0:  /* nothing */
        case 1:  /* TIFF_BYTE */
        case 2:  /* TIFF_ASCII */
        case 6:  /* TIFF_SBYTE */
        case 7:  /* TIFF_UNDEFINED */
                return 1;
        case 3:  /* TIFF_SHORT */
        case 8:  /* TIFF_SSHORT */
                return 2;
        case 4:  /* TIFF_LONG */
        case 9:  /* TIFF_SLONG */
        case 11: /* TIFF_FLOAT */
        case 13: /* TIFF_IFD */
                return 4;
        case 5:  /* TIFF_RATIONAL */
        case 10: /* TIFF_SRATIONAL */
        case 12: /* TIFF_DOUBLE */
                return 8;
        default:
                return 0; /* will return 0 for unknown types */
        }
}

/*
 * Return size of TIFFDataType in bytes.
 *
 * XXX: We need a separate function to determine the space needed
 * to store the value. For TIFF_RATIONAL values TIFFDataWidth() returns 8,
 * but we use 4-byte float to represent rationals.
 */
int
_TIFFDataSize(TIFFDataType type)
{
        switch (type) {
                case TIFF_BYTE:
                case TIFF_SBYTE:
                case TIFF_ASCII:
                case TIFF_UNDEFINED:
                    return 1;
                case TIFF_SHORT:
                case TIFF_SSHORT:
                    return 2;
                case TIFF_LONG:
                case TIFF_SLONG:
                case TIFF_FLOAT:
                case TIFF_IFD:
                case TIFF_RATIONAL:
                case TIFF_SRATIONAL:
                    return 4;
                case TIFF_DOUBLE:
                    return 8;
                default:
                    return 0;
        }
}

/*
 * Return nearest TIFFDataType to the sample type of an image.
 */
TIFFDataType
_TIFFSampleToTagType(TIFF* tif)
{
        uint32 bps = TIFFhowmany8(tif->tif_dir.td_bitspersample);

        switch (tif->tif_dir.td_sampleformat) {
        case SAMPLEFORMAT_IEEEFP:
                return (bps == 4 ? TIFF_FLOAT : TIFF_DOUBLE);
        case SAMPLEFORMAT_INT:
                return (bps <= 1 ? TIFF_SBYTE :
                    bps <= 2 ? TIFF_SSHORT : TIFF_SLONG);
        case SAMPLEFORMAT_UINT:
                return (bps <= 1 ? TIFF_BYTE :
                    bps <= 2 ? TIFF_SHORT : TIFF_LONG);
        case SAMPLEFORMAT_VOID:
                return (TIFF_UNDEFINED);
        }
        /*NOTREACHED*/
        return (TIFF_UNDEFINED);
}

const TIFFFieldInfo*
_TIFFFindFieldInfo(TIFF* tif, ttag_t tag, TIFFDataType dt)
{
        int i, n;

        if (tif->tif_foundfield && tif->tif_foundfield->field_tag == tag &&
            (dt == TIFF_ANY || dt == tif->tif_foundfield->field_type))
                return (tif->tif_foundfield);
        /* NB: use sorted search (e.g. binary search) */
        if(dt != TIFF_ANY) {
            TIFFFieldInfo key = {0, 0, 0, TIFF_NOTYPE, 0, 0, 0, 0};
            TIFFFieldInfo* pkey = &key;
            const TIFFFieldInfo **ret;

            key.field_tag = tag;
            key.field_type = dt;

            ret = (const TIFFFieldInfo **) bsearch(&pkey,
                                                   tif->tif_fieldinfo, 
                                                   tif->tif_nfields,
                                                   sizeof(TIFFFieldInfo *), 
                                                   tagCompare);
            return (ret) ? (*ret) : NULL;
        } else for (i = 0, n = tif->tif_nfields; i < n; i++) {
                const TIFFFieldInfo* fip = tif->tif_fieldinfo[i];
                if (fip->field_tag == tag &&
                    (dt == TIFF_ANY || fip->field_type == dt))
                        return (tif->tif_foundfield = fip);
        }
        return ((const TIFFFieldInfo *)0);
}

const TIFFFieldInfo*
_TIFFFindFieldInfoByName(TIFF* tif, const char *field_name, TIFFDataType dt)
{
        int i, n;

        if (tif->tif_foundfield
            && streq(tif->tif_foundfield->field_name, field_name)
            && (dt == TIFF_ANY || dt == tif->tif_foundfield->field_type))
                return (tif->tif_foundfield);
        /* NB: use sorted search (e.g. binary search) */
        if(dt != TIFF_ANY) {
            TIFFFieldInfo key = {0, 0, 0, TIFF_NOTYPE, 0, 0, 0, 0};
            TIFFFieldInfo* pkey = &key;
            const TIFFFieldInfo **ret;

            key.field_name = (char *)field_name;
            key.field_type = dt;

            ret = (const TIFFFieldInfo **) lfind(&pkey,
                                                 tif->tif_fieldinfo, 
                                                 &tif->tif_nfields,
                                                 sizeof(TIFFFieldInfo *),
                                                 tagNameCompare);
            return (ret) ? (*ret) : NULL;
        } else
                for (i = 0, n = tif->tif_nfields; i < n; i++) {
                        const TIFFFieldInfo* fip = tif->tif_fieldinfo[i];
                        if (streq(fip->field_name, field_name) &&
                            (dt == TIFF_ANY || fip->field_type == dt))
                                return (tif->tif_foundfield = fip);
                }
        return ((const TIFFFieldInfo *)0);
}

const TIFFFieldInfo*
_TIFFFieldWithTag(TIFF* tif, ttag_t tag)
{
        const TIFFFieldInfo* fip = _TIFFFindFieldInfo(tif, tag, TIFF_ANY);
        if (!fip) {
                TIFFErrorExt(tif->tif_clientdata, "TIFFFieldWithTag",
                          "Internal error, unknown tag 0x%x",
                          (unsigned int) tag);
                assert(fip != NULL);
                /*NOTREACHED*/
        }
        return (fip);
}

const TIFFFieldInfo*
_TIFFFieldWithName(TIFF* tif, const char *field_name)
{
        const TIFFFieldInfo* fip =
                _TIFFFindFieldInfoByName(tif, field_name, TIFF_ANY);
        if (!fip) {
                TIFFErrorExt(tif->tif_clientdata, "TIFFFieldWithName",
                          "Internal error, unknown tag %s", field_name);
                assert(fip != NULL);
                /*NOTREACHED*/
        }
        return (fip);
}

const TIFFFieldInfo*
_TIFFFindOrRegisterFieldInfo( TIFF *tif, ttag_t tag, TIFFDataType dt )

{
    const TIFFFieldInfo *fld;

    fld = _TIFFFindFieldInfo( tif, tag, dt );
    if( fld == NULL )
    {
        fld = _TIFFCreateAnonFieldInfo( tif, tag, dt );
        _TIFFMergeFieldInfo( tif, fld, 1 );
    }

    return fld;
}

TIFFFieldInfo*
_TIFFCreateAnonFieldInfo(TIFF *tif, ttag_t tag, TIFFDataType field_type)
{
        TIFFFieldInfo *fld;
        (void) tif;

        fld = (TIFFFieldInfo *) _TIFFmalloc(sizeof (TIFFFieldInfo));
        if (fld == NULL)
            return NULL;
        _TIFFmemset( fld, 0, sizeof(TIFFFieldInfo) );

        fld->field_tag = tag;
        fld->field_readcount = TIFF_VARIABLE;
        fld->field_writecount = TIFF_VARIABLE;
        fld->field_type = field_type;
        fld->field_bit = FIELD_CUSTOM;
        fld->field_oktochange = TRUE;
        fld->field_passcount = TRUE;
        fld->field_name = (char *) _TIFFmalloc(32);
        if (fld->field_name == NULL) {
            _TIFFfree(fld);
            return NULL;
        }

        /* note that this name is a special sign to TIFFClose() and
         * _TIFFSetupFieldInfo() to free the field
         */
        sprintf(fld->field_name, "Tag %d", (int) tag);

        return fld;    
}

/* vim: set ts=8 sts=8 sw=8 noet: */
