LCOV - code coverage report
Current view: top level - gcore - gdalexif.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 548 671 81.7 %
Date: 2024-05-03 15:49:35 Functions: 14 14 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Implements a EXIF directory reader
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2000, Frank Warmerdam
       9             :  * Copyright (c) 2012,2017, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * Portions Copyright (c) Her majesty the Queen in right of Canada as
      12             :  * represented by the Minister of National Defence, 2006.
      13             :  *
      14             :  * Permission is hereby granted, free of charge, to any person obtaining a
      15             :  * copy of this software and associated documentation files (the "Software"),
      16             :  * to deal in the Software without restriction, including without limitation
      17             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      18             :  * and/or sell copies of the Software, and to permit persons to whom the
      19             :  * Software is furnished to do so, subject to the following conditions:
      20             :  *
      21             :  * The above copyright notice and this permission notice shall be included
      22             :  * in all copies or substantial portions of the Software.
      23             :  *
      24             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      25             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      26             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      27             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      28             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      29             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      30             :  * DEALINGS IN THE SOFTWARE.
      31             :  ****************************************************************************/
      32             : 
      33             : #include "cpl_port.h"
      34             : #include "gdal_priv.h"
      35             : #include "gdalexif.h"
      36             : 
      37             : #include <climits>
      38             : #include <cstddef>
      39             : #include <cstdio>
      40             : #include <cstring>
      41             : #if HAVE_FCNTL_H
      42             : #include <fcntl.h>
      43             : #endif
      44             : 
      45             : #include <algorithm>
      46             : #include <limits>
      47             : #include <vector>
      48             : 
      49             : #include "cpl_conv.h"
      50             : #include "cpl_error.h"
      51             : #include "cpl_string.h"
      52             : #include "cpl_vsi.h"
      53             : 
      54             : using std::vector;
      55             : 
      56             : constexpr int MAXSTRINGLENGTH = 65535;
      57             : constexpr int EXIFOFFSETTAG = 0x8769;
      58             : constexpr int INTEROPERABILITYOFFSET = 0xA005;
      59             : constexpr int GPSOFFSETTAG = 0x8825;
      60             : 
      61             : constexpr GUInt16 TAG_SIZE = 12;
      62             : constexpr GUInt16 EXIF_HEADER_SIZE = 6;
      63             : 
      64             : constexpr char COND_MANDATORY = 'M';
      65             : constexpr char COND_RECOMMENDED = 'R';
      66             : constexpr char COND_OPTIONAL = 'O';
      67             : constexpr char COND_NOT_ALLOWED = 'N';
      68             : constexpr char COND_NOT_ALLOWED_EVEN_IN_JPEG_MARKER = 'J';
      69             : 
      70             : struct EXIFTagDesc
      71             : {
      72             :     GUInt16 tag;
      73             :     GDALEXIFTIFFDataType datatype;
      74             :     GUInt32 length;
      75             :     const char *name;
      76             :     // comprCond is only used when DUMP_EXIF_ITEMS is defined
      77             :     // cppcheck-suppress unusedStructMember
      78             :     char comprCond;
      79             : };
      80             : 
      81             : static const EXIFTagDesc gpstags[] = {
      82             :     {0x00, TIFF_BYTE, 4, "EXIF_GPSVersionID", COND_OPTIONAL},
      83             :     {0x01, TIFF_ASCII, 2, "EXIF_GPSLatitudeRef", COND_OPTIONAL},
      84             :     {0x02, TIFF_RATIONAL, 3, "EXIF_GPSLatitude", COND_OPTIONAL},
      85             :     {0x03, TIFF_ASCII, 2, "EXIF_GPSLongitudeRef", COND_OPTIONAL},
      86             :     {0x04, TIFF_RATIONAL, 3, "EXIF_GPSLongitude", COND_OPTIONAL},
      87             :     {0x05, TIFF_BYTE, 1, "EXIF_GPSAltitudeRef", COND_OPTIONAL},
      88             :     {0x06, TIFF_RATIONAL, 1, "EXIF_GPSAltitude", COND_OPTIONAL},
      89             :     {0x07, TIFF_RATIONAL, 3, "EXIF_GPSTimeStamp", COND_OPTIONAL},
      90             :     {0x08, TIFF_ASCII, 0, "EXIF_GPSSatellites", COND_OPTIONAL},
      91             :     {0x09, TIFF_ASCII, 2, "EXIF_GPSStatus", COND_OPTIONAL},
      92             :     {0x0a, TIFF_ASCII, 2, "EXIF_GPSMeasureMode", COND_OPTIONAL},
      93             :     {0x0b, TIFF_RATIONAL, 1, "EXIF_GPSDOP", COND_OPTIONAL},
      94             :     {0x0c, TIFF_ASCII, 2, "EXIF_GPSSpeedRef", COND_OPTIONAL},
      95             :     {0x0d, TIFF_RATIONAL, 1, "EXIF_GPSSpeed", COND_OPTIONAL},
      96             :     {0x0e, TIFF_ASCII, 2, "EXIF_GPSTrackRef", COND_OPTIONAL},
      97             :     {0x0f, TIFF_RATIONAL, 1, "EXIF_GPSTrack", COND_OPTIONAL},
      98             :     {0x10, TIFF_ASCII, 2, "EXIF_GPSImgDirectionRef", COND_OPTIONAL},
      99             :     {0x11, TIFF_RATIONAL, 1, "EXIF_GPSImgDirection", COND_OPTIONAL},
     100             :     {0x12, TIFF_ASCII, 0, "EXIF_GPSMapDatum", COND_OPTIONAL},
     101             :     {0x13, TIFF_ASCII, 2, "EXIF_GPSDestLatitudeRef", COND_OPTIONAL},
     102             :     {0x14, TIFF_RATIONAL, 3, "EXIF_GPSDestLatitude", COND_OPTIONAL},
     103             :     {0x15, TIFF_ASCII, 2, "EXIF_GPSDestLongitudeRef", COND_OPTIONAL},
     104             :     {0x16, TIFF_RATIONAL, 3, "EXIF_GPSDestLongitude", COND_OPTIONAL},
     105             :     {0x17, TIFF_ASCII, 2, "EXIF_GPSDestBearingRef", COND_OPTIONAL},
     106             :     {0x18, TIFF_RATIONAL, 1, "EXIF_GPSDestBearing", COND_OPTIONAL},
     107             :     {0x19, TIFF_ASCII, 2, "EXIF_GPSDestDistanceRef", COND_OPTIONAL},
     108             :     {0x1a, TIFF_RATIONAL, 1, "EXIF_GPSDestDistance", COND_OPTIONAL},
     109             :     {0x1b, TIFF_UNDEFINED, 0, "EXIF_GPSProcessingMethod", COND_OPTIONAL},
     110             :     {0x1c, TIFF_UNDEFINED, 0, "EXIF_GPSAreaInformation", COND_OPTIONAL},
     111             :     {0x1d, TIFF_ASCII, 11, "EXIF_GPSDateStamp", COND_OPTIONAL},
     112             :     {0x1e, TIFF_SHORT, 1, "EXIF_GPSDifferential", COND_OPTIONAL},
     113             :     {0x1f, TIFF_RATIONAL, 1, "EXIF_GPSHPositioningError", COND_OPTIONAL},
     114             :     {0xffff, TIFF_NOTYPE, 0, "", COND_NOT_ALLOWED}};
     115             : 
     116             : static const EXIFTagDesc exiftags[] = {
     117             :     //{ 0x100, "EXIF_Image_Width"},
     118             :     //  { 0x101, "EXIF_Image_Length"},
     119             :     {0x102, TIFF_NOTYPE, 0, "EXIF_BitsPerSample",
     120             :      COND_NOT_ALLOWED_EVEN_IN_JPEG_MARKER},
     121             :     {0x103, TIFF_NOTYPE, 0, "EXIF_Compression",
     122             :      COND_NOT_ALLOWED_EVEN_IN_JPEG_MARKER},
     123             :     {0x106, TIFF_NOTYPE, 0, "EXIF_PhotometricInterpretation", COND_NOT_ALLOWED},
     124             :     {0x10A, TIFF_NOTYPE, 0, "EXIF_Fill_Order",
     125             :      COND_NOT_ALLOWED_EVEN_IN_JPEG_MARKER},  // not sure of cond
     126             :     {0x10D, TIFF_ASCII, 0, "EXIF_Document_Name",
     127             :      COND_OPTIONAL},  // not sure of cond
     128             :     {0x10E, TIFF_ASCII, 0, "EXIF_ImageDescription", COND_RECOMMENDED},
     129             :     {0x10F, TIFF_ASCII, 0, "EXIF_Make", COND_RECOMMENDED},
     130             :     {0x110, TIFF_ASCII, 0, "EXIF_Model", COND_RECOMMENDED},
     131             :     {0x111, TIFF_NOTYPE, 0, "EXIF_StripOffsets", COND_NOT_ALLOWED},
     132             :     {0x112, TIFF_SHORT, 1, "EXIF_Orientation", COND_RECOMMENDED},
     133             :     {0x115, TIFF_NOTYPE, 0, "EXIF_SamplesPerPixel",
     134             :      COND_NOT_ALLOWED_EVEN_IN_JPEG_MARKER},
     135             :     {0x116, TIFF_NOTYPE, 0, "EXIF_RowsPerStrip", COND_NOT_ALLOWED},
     136             :     {0x117, TIFF_NOTYPE, 0, "EXIF_StripByteCounts", COND_NOT_ALLOWED},
     137             :     {0x11A, TIFF_RATIONAL, 1, "EXIF_XResolution", COND_MANDATORY},
     138             :     {0x11B, TIFF_RATIONAL, 1, "EXIF_YResolution", COND_MANDATORY},
     139             :     {0x11C, TIFF_NOTYPE, 0, "EXIF_PlanarConfiguration",
     140             :      COND_NOT_ALLOWED_EVEN_IN_JPEG_MARKER},
     141             :     {0x128, TIFF_SHORT, 1, "EXIF_ResolutionUnit", COND_MANDATORY},
     142             :     {0x12D, TIFF_SHORT, 768, "EXIF_TransferFunction", COND_OPTIONAL},
     143             :     {0x131, TIFF_ASCII, 0, "EXIF_Software", COND_OPTIONAL},
     144             :     {0x132, TIFF_ASCII, 20, "EXIF_DateTime", COND_RECOMMENDED},
     145             :     {0x13B, TIFF_ASCII, 0, "EXIF_Artist", COND_OPTIONAL},
     146             :     {0x13E, TIFF_RATIONAL, 2, "EXIF_WhitePoint", COND_OPTIONAL},
     147             :     {0x13F, TIFF_RATIONAL, 6, "EXIF_PrimaryChromaticities", COND_OPTIONAL},
     148             :     {0x156, TIFF_NOTYPE, 0, "EXIF_Transfer_Range",
     149             :      COND_NOT_ALLOWED},  // not sure of cond
     150             :     {0x200, TIFF_NOTYPE, 0, "EXIF_JPEG_Proc",
     151             :      COND_NOT_ALLOWED},  // not sure of cond
     152             :     {0x201, TIFF_NOTYPE, 0, "EXIF_JPEGInterchangeFormat", COND_NOT_ALLOWED},
     153             :     {0x202, TIFF_NOTYPE, 0, "EXIF_JPEGInterchangeFormatLength",
     154             :      COND_NOT_ALLOWED},
     155             :     {0x211, TIFF_RATIONAL, 3, "EXIF_YCbCrCoefficients", COND_OPTIONAL},
     156             :     {0x212, TIFF_NOTYPE, 0, "EXIF_YCbCrSubSampling",
     157             :      COND_NOT_ALLOWED_EVEN_IN_JPEG_MARKER},
     158             :     {0x213, TIFF_SHORT, 1, "EXIF_YCbCrPositioning", COND_MANDATORY},
     159             :     {0x214, TIFF_RATIONAL, 6, "EXIF_ReferenceBlackWhite", COND_OPTIONAL},
     160             :     {0x2BC, TIFF_ASCII, 0, "EXIF_XmlPacket",
     161             :      COND_OPTIONAL},  // not in the EXIF standard. But found in some images
     162             :     {0x828D, TIFF_NOTYPE, 0, "EXIF_CFA_Repeat_Pattern_Dim", COND_OPTIONAL},
     163             :     {0x828E, TIFF_NOTYPE, 0, "EXIF_CFA_Pattern", COND_OPTIONAL},
     164             :     {0x828F, TIFF_NOTYPE, 0, "EXIF_Battery_Level", COND_OPTIONAL},
     165             :     {0x8298, TIFF_ASCII, 0, "EXIF_Copyright",
     166             :      COND_OPTIONAL},  // that one is an exception: high tag number, but should
     167             :                       // go to main IFD
     168             :     {0x829A, TIFF_RATIONAL, 1, "EXIF_ExposureTime", COND_RECOMMENDED},
     169             :     {0x829D, TIFF_RATIONAL, 1, "EXIF_FNumber", COND_OPTIONAL},
     170             :     {0x83BB, TIFF_NOTYPE, 0, "EXIF_IPTC/NAA", COND_OPTIONAL},
     171             :     // { 0x8769, "EXIF_Offset"},
     172             :     {0x8773, TIFF_NOTYPE, 0, "EXIF_Inter_Color_Profile", COND_OPTIONAL},
     173             :     {0x8822, TIFF_SHORT, 1, "EXIF_ExposureProgram", COND_OPTIONAL},
     174             :     {0x8824, TIFF_ASCII, 0, "EXIF_SpectralSensitivity", COND_OPTIONAL},
     175             :     // { 0x8825, "EXIF_GPSOffset"},
     176             :     {0x8827, TIFF_SHORT, 0, "EXIF_ISOSpeedRatings", COND_OPTIONAL},
     177             :     {0x8828, TIFF_UNDEFINED, 0, "EXIF_OECF", COND_OPTIONAL},
     178             :     {0x8830, TIFF_SHORT, 1, "EXIF_SensitivityType", COND_OPTIONAL},
     179             :     {0x8831, TIFF_LONG, 1, "EXIF_StandardOutputSensitivity", COND_OPTIONAL},
     180             :     {0x8832, TIFF_LONG, 1, "EXIF_RecommendedExposureIndex", COND_OPTIONAL},
     181             :     {0x8833, TIFF_LONG, 1, "EXIF_ISOSpeed", COND_OPTIONAL},
     182             :     {0x8834, TIFF_LONG, 1, "EXIF_ISOSpeedLatitudeyyy", COND_OPTIONAL},
     183             :     {0x8835, TIFF_LONG, 1, "EXIF_ISOSpeedLatitudezzz", COND_OPTIONAL},
     184             :     {0x9000, TIFF_UNDEFINED, 4, "EXIF_ExifVersion", COND_MANDATORY},
     185             :     {0x9003, TIFF_ASCII, 20, "EXIF_DateTimeOriginal", COND_OPTIONAL},
     186             :     {0x9004, TIFF_ASCII, 20, "EXIF_DateTimeDigitized", COND_OPTIONAL},
     187             :     {0x9010, TIFF_ASCII, 7, "EXIF_OffsetTime", COND_OPTIONAL},
     188             :     {0x9011, TIFF_ASCII, 7, "EXIF_OffsetTimeOriginal", COND_OPTIONAL},
     189             :     {0x9012, TIFF_ASCII, 7, "EXIF_OffsetTimeDigitized", COND_OPTIONAL},
     190             :     {0x9101, TIFF_UNDEFINED, 4, "EXIF_ComponentsConfiguration", COND_MANDATORY},
     191             :     {0x9102, TIFF_RATIONAL, 1, "EXIF_CompressedBitsPerPixel", COND_OPTIONAL},
     192             :     {0x9201, TIFF_SRATIONAL, 1, "EXIF_ShutterSpeedValue", COND_OPTIONAL},
     193             :     {0x9202, TIFF_RATIONAL, 1, "EXIF_ApertureValue", COND_OPTIONAL},
     194             :     {0x9203, TIFF_SRATIONAL, 1, "EXIF_BrightnessValue", COND_OPTIONAL},
     195             :     {0x9204, TIFF_SRATIONAL, 1, "EXIF_ExposureBiasValue", COND_OPTIONAL},
     196             :     {0x9205, TIFF_RATIONAL, 1, "EXIF_MaxApertureValue", COND_OPTIONAL},
     197             :     {0x9206, TIFF_RATIONAL, 1, "EXIF_SubjectDistance", COND_OPTIONAL},
     198             :     {0x9207, TIFF_SHORT, 1, "EXIF_MeteringMode", COND_OPTIONAL},
     199             :     {0x9208, TIFF_SHORT, 1, "EXIF_LightSource", COND_OPTIONAL},
     200             :     {0x9209, TIFF_SHORT, 1, "EXIF_Flash", COND_RECOMMENDED},
     201             :     {0x920A, TIFF_RATIONAL, 1, "EXIF_FocalLength", COND_OPTIONAL},
     202             :     {0x9214, TIFF_SHORT, 0, "EXIF_SubjectArea",
     203             :      COND_OPTIONAL},  // count = 2, 3 or 4
     204             :     {0x927C, TIFF_UNDEFINED, 0, "EXIF_MakerNote", COND_OPTIONAL},
     205             :     {0x9286, TIFF_UNDEFINED, 0, "EXIF_UserComment", COND_OPTIONAL},
     206             :     {0x9290, TIFF_ASCII, 0, "EXIF_SubSecTime", COND_OPTIONAL},
     207             :     {0x9291, TIFF_ASCII, 0, "EXIF_SubSecTime_Original", COND_OPTIONAL},
     208             :     {0x9292, TIFF_ASCII, 0, "EXIF_SubSecTime_Digitized", COND_OPTIONAL},
     209             :     {0xA000, TIFF_UNDEFINED, 4, "EXIF_FlashpixVersion", COND_MANDATORY},
     210             :     {0xA001, TIFF_SHORT, 1, "EXIF_ColorSpace", COND_MANDATORY},
     211             :     {0xA002, TIFF_LONG, 1, "EXIF_PixelXDimension",
     212             :      COND_MANDATORY},  // SHORT also OK
     213             :     {0xA003, TIFF_LONG, 1, "EXIF_PixelYDimension",
     214             :      COND_MANDATORY},  // SHORT also OK
     215             :     {0xA004, TIFF_ASCII, 13, "EXIF_RelatedSoundFile", COND_OPTIONAL},
     216             :     // { 0xA005, "EXIF_InteroperabilityOffset"},
     217             :     {0xA20B, TIFF_RATIONAL, 1, "EXIF_FlashEnergy",
     218             :      COND_OPTIONAL},  // 0x920B in TIFF/EP
     219             :     {0xA20C, TIFF_UNDEFINED, 0, "EXIF_SpatialFrequencyResponse",
     220             :      COND_OPTIONAL},  // 0x920C    -  -
     221             :     {0xA20E, TIFF_RATIONAL, 1, "EXIF_FocalPlaneXResolution",
     222             :      COND_OPTIONAL},  // 0x920E    -  -
     223             :     {0xA20F, TIFF_RATIONAL, 1, "EXIF_FocalPlaneYResolution",
     224             :      COND_OPTIONAL},  // 0x920F    -  -
     225             :     {0xA210, TIFF_SHORT, 1, "EXIF_FocalPlaneResolutionUnit",
     226             :      COND_OPTIONAL},  // 0x9210    -  -
     227             :     {0xA214, TIFF_SHORT, 2, "EXIF_SubjectLocation",
     228             :      COND_OPTIONAL},  // 0x9214    -  -
     229             :     {0xA215, TIFF_RATIONAL, 1, "EXIF_ExposureIndex",
     230             :      COND_OPTIONAL},  // 0x9215    -  -
     231             :     {0xA217, TIFF_SHORT, 1, "EXIF_SensingMethod", COND_OPTIONAL},  // 0x9217 - -
     232             :     {0xA300, TIFF_UNDEFINED, 1, "EXIF_FileSource", COND_OPTIONAL},
     233             :     {0xA301, TIFF_UNDEFINED, 1, "EXIF_SceneType", COND_OPTIONAL},
     234             :     {0xA302, TIFF_UNDEFINED, 0, "EXIF_CFAPattern", COND_OPTIONAL},
     235             :     {0xA401, TIFF_SHORT, 1, "EXIF_CustomRendered", COND_OPTIONAL},
     236             :     {0xA402, TIFF_SHORT, 1, "EXIF_ExposureMode", COND_RECOMMENDED},
     237             :     {0XA403, TIFF_SHORT, 1, "EXIF_WhiteBalance", COND_RECOMMENDED},
     238             :     {0xA404, TIFF_RATIONAL, 1, "EXIF_DigitalZoomRatio", COND_OPTIONAL},
     239             :     {0xA405, TIFF_SHORT, 1, "EXIF_FocalLengthIn35mmFilm", COND_OPTIONAL},
     240             :     {0xA406, TIFF_SHORT, 1, "EXIF_SceneCaptureType", COND_RECOMMENDED},
     241             :     {0xA407, TIFF_RATIONAL, 1, "EXIF_GainControl", COND_OPTIONAL},
     242             :     {0xA408, TIFF_SHORT, 1, "EXIF_Contrast", COND_OPTIONAL},
     243             :     {0xA409, TIFF_SHORT, 1, "EXIF_Saturation", COND_OPTIONAL},
     244             :     {0xA40A, TIFF_SHORT, 1, "EXIF_Sharpness", COND_OPTIONAL},
     245             :     {0xA40B, TIFF_UNDEFINED, 0, "EXIF_DeviceSettingDescription", COND_OPTIONAL},
     246             :     {0xA40C, TIFF_SHORT, 1, "EXIF_SubjectDistanceRange", COND_OPTIONAL},
     247             :     {0xA420, TIFF_ASCII, 33, "EXIF_ImageUniqueID", COND_OPTIONAL},
     248             :     {0xA430, TIFF_ASCII, 0, "EXIF_CameraOwnerName", COND_OPTIONAL},
     249             :     {0xA431, TIFF_ASCII, 0, "EXIF_BodySerialNumber", COND_OPTIONAL},
     250             :     {0xA432, TIFF_RATIONAL, 4, "EXIF_LensSpecification", COND_OPTIONAL},
     251             :     {0xA433, TIFF_ASCII, 0, "EXIF_LensMake", COND_OPTIONAL},
     252             :     {0xA434, TIFF_ASCII, 0, "EXIF_LensModel", COND_OPTIONAL},
     253             :     {0xA435, TIFF_ASCII, 0, "EXIF_LensSerialNumber", COND_OPTIONAL},
     254             :     {0x0000, TIFF_NOTYPE, 0, "", COND_NOT_ALLOWED}};
     255             : 
     256             : static const struct intr_tag
     257             : {
     258             :     GInt16 tag;
     259             :     const char *name;
     260             : } intr_tags[] = {
     261             : 
     262             :     {0x1, "EXIF_Interoperability_Index"},
     263             :     {0x2, "EXIF_Interoperability_Version"},
     264             :     {0x1000, "EXIF_Related_Image_File_Format"},
     265             :     {0x1001, "EXIF_Related_Image_Width"},
     266             :     {0x1002, "EXIF_Related_Image_Length"},
     267             :     {0x0000, ""}};
     268             : 
     269             : /************************************************************************/
     270             : /*                         EXIFPrintData()                              */
     271             : /************************************************************************/
     272         517 : static void EXIFPrintData(char *pszData, GUInt16 type, GUInt32 count,
     273             :                           const unsigned char *data)
     274             : {
     275         517 :     const char *sep = "";
     276             :     char szTemp[128];
     277         517 :     char *pszDataEnd = pszData;
     278             : 
     279         517 :     pszData[0] = '\0';
     280             : 
     281         517 :     switch (type)
     282             :     {
     283             : 
     284         198 :         case TIFF_UNDEFINED:
     285             :         case TIFF_BYTE:
     286         198 :             for (; count > 0; count--)
     287             :             {
     288         158 :                 snprintf(szTemp, sizeof(szTemp), "%s0x%02x", sep, *data);
     289         158 :                 data++;
     290         158 :                 sep = " ";
     291         158 :                 if (strlen(szTemp) + pszDataEnd - pszData >= MAXSTRINGLENGTH)
     292           0 :                     break;
     293         158 :                 strcat(pszDataEnd, szTemp);
     294         158 :                 pszDataEnd += strlen(pszDataEnd);
     295             :             }
     296          40 :             break;
     297             : 
     298           0 :         case TIFF_SBYTE:
     299           0 :             for (; count > 0; count--)
     300             :             {
     301           0 :                 snprintf(szTemp, sizeof(szTemp), "%s%d", sep,
     302           0 :                          *reinterpret_cast<const char *>(data));
     303           0 :                 data++;
     304           0 :                 sep = " ";
     305           0 :                 if (strlen(szTemp) + pszDataEnd - pszData >= MAXSTRINGLENGTH)
     306           0 :                     break;
     307           0 :                 strcat(pszDataEnd, szTemp);
     308           0 :                 pszDataEnd += strlen(pszDataEnd);
     309             :             }
     310           0 :             break;
     311             : 
     312         242 :         case TIFF_ASCII:
     313         242 :             memcpy(pszData, data, count);
     314         242 :             pszData[count] = '\0';
     315         242 :             break;
     316             : 
     317          80 :         case TIFF_SHORT:
     318             :         {
     319          80 :             const GUInt16 *wp = reinterpret_cast<const GUInt16 *>(data);
     320         929 :             for (; count > 0; count--)
     321             :             {
     322         849 :                 snprintf(szTemp, sizeof(szTemp), "%s%u", sep, *wp);
     323         849 :                 wp++;
     324         849 :                 sep = " ";
     325         849 :                 if (strlen(szTemp) + pszDataEnd - pszData >= MAXSTRINGLENGTH)
     326           0 :                     break;
     327         849 :                 strcat(pszDataEnd, szTemp);
     328         849 :                 pszDataEnd += strlen(pszDataEnd);
     329             :             }
     330          80 :             break;
     331             :         }
     332           0 :         case TIFF_SSHORT:
     333             :         {
     334           0 :             const GInt16 *wp = reinterpret_cast<const GInt16 *>(data);
     335           0 :             for (; count > 0; count--)
     336             :             {
     337           0 :                 snprintf(szTemp, sizeof(szTemp), "%s%d", sep, *wp);
     338           0 :                 wp++;
     339           0 :                 sep = " ";
     340           0 :                 if (strlen(szTemp) + pszDataEnd - pszData >= MAXSTRINGLENGTH)
     341           0 :                     break;
     342           0 :                 strcat(pszDataEnd, szTemp);
     343           0 :                 pszDataEnd += strlen(pszDataEnd);
     344             :             }
     345           0 :             break;
     346             :         }
     347          23 :         case TIFF_LONG:
     348             :         {
     349          23 :             const GUInt32 *lp = reinterpret_cast<const GUInt32 *>(data);
     350          46 :             for (; count > 0; count--)
     351             :             {
     352          23 :                 snprintf(szTemp, sizeof(szTemp), "%s%u", sep, *lp);
     353          23 :                 lp++;
     354          23 :                 sep = " ";
     355          23 :                 if (strlen(szTemp) + pszDataEnd - pszData >= MAXSTRINGLENGTH)
     356           0 :                     break;
     357          23 :                 strcat(pszDataEnd, szTemp);
     358          23 :                 pszDataEnd += strlen(pszDataEnd);
     359             :             }
     360          23 :             break;
     361             :         }
     362           0 :         case TIFF_SLONG:
     363             :         {
     364           0 :             const GInt32 *lp = reinterpret_cast<const GInt32 *>(data);
     365           0 :             for (; count > 0; count--)
     366             :             {
     367           0 :                 snprintf(szTemp, sizeof(szTemp), "%s%d", sep, *lp);
     368           0 :                 lp++;
     369           0 :                 sep = " ";
     370           0 :                 if (strlen(szTemp) + pszDataEnd - pszData >= MAXSTRINGLENGTH)
     371           0 :                     break;
     372           0 :                 strcat(pszDataEnd, szTemp);
     373           0 :                 pszDataEnd += strlen(pszDataEnd);
     374             :             }
     375           0 :             break;
     376             :         }
     377         125 :         case TIFF_RATIONAL:
     378             :         {
     379         125 :             const GUInt32 *lp = reinterpret_cast<const GUInt32 *>(data);
     380             :             //      if(bSwabflag)
     381             :             //      TIFFSwabArrayOfLong((GUInt32*) data, 2*count);
     382         372 :             for (; count > 0; count--)
     383             :             {
     384         247 :                 if ((lp[0] == 0) || (lp[1] == 0))
     385             :                 {
     386           9 :                     snprintf(szTemp, sizeof(szTemp), "%s(0)", sep);
     387             :                 }
     388             :                 else
     389             :                 {
     390         238 :                     CPLsnprintf(szTemp, sizeof(szTemp), "%s(%g)", sep,
     391         238 :                                 static_cast<double>(lp[0]) /
     392         238 :                                     static_cast<double>(lp[1]));
     393             :                 }
     394         247 :                 sep = " ";
     395         247 :                 lp += 2;
     396         247 :                 if (strlen(szTemp) + pszDataEnd - pszData >= MAXSTRINGLENGTH)
     397           0 :                     break;
     398         247 :                 strcat(pszDataEnd, szTemp);
     399         247 :                 pszDataEnd += strlen(pszDataEnd);
     400             :             }
     401         125 :             break;
     402             :         }
     403           7 :         case TIFF_SRATIONAL:
     404             :         {
     405           7 :             const GInt32 *lp = reinterpret_cast<const GInt32 *>(data);
     406          14 :             for (; count > 0; count--)
     407             :             {
     408           7 :                 if ((lp[0] == 0) || (lp[1] == 0))
     409             :                 {
     410           1 :                     snprintf(szTemp, sizeof(szTemp), "%s(0)", sep);
     411             :                 }
     412             :                 else
     413             :                 {
     414           6 :                     CPLsnprintf(szTemp, sizeof(szTemp), "%s(%g)", sep,
     415           6 :                                 static_cast<double>(lp[0]) /
     416           6 :                                     static_cast<double>(lp[1]));
     417             :                 }
     418           7 :                 sep = " ";
     419           7 :                 lp += 2;
     420           7 :                 if (strlen(szTemp) + pszDataEnd - pszData >= MAXSTRINGLENGTH)
     421           0 :                     break;
     422           7 :                 strcat(pszDataEnd, szTemp);
     423           7 :                 pszDataEnd += strlen(pszDataEnd);
     424             :             }
     425           7 :             break;
     426             :         }
     427           0 :         case TIFF_FLOAT:
     428             :         {
     429           0 :             const float *fp = reinterpret_cast<const float *>(data);
     430           0 :             for (; count > 0; count--)
     431             :             {
     432           0 :                 CPLsnprintf(szTemp, sizeof(szTemp), "%s%g", sep, *fp);
     433           0 :                 fp++;
     434           0 :                 sep = " ";
     435           0 :                 if (strlen(szTemp) + pszDataEnd - pszData >= MAXSTRINGLENGTH)
     436           0 :                     break;
     437           0 :                 strcat(pszDataEnd, szTemp);
     438           0 :                 pszDataEnd += strlen(pszDataEnd);
     439             :             }
     440           0 :             break;
     441             :         }
     442           0 :         case TIFF_DOUBLE:
     443             :         {
     444           0 :             const double *dp = reinterpret_cast<const double *>(data);
     445           0 :             for (; count > 0; count--)
     446             :             {
     447           0 :                 CPLsnprintf(szTemp, sizeof(szTemp), "%s%g", sep, *dp);
     448           0 :                 dp++;
     449           0 :                 sep = " ";
     450           0 :                 if (strlen(szTemp) + pszDataEnd - pszData >= MAXSTRINGLENGTH)
     451           0 :                     break;
     452           0 :                 strcat(pszDataEnd, szTemp);
     453           0 :                 pszDataEnd += strlen(pszDataEnd);
     454             :             }
     455           0 :             break;
     456             :         }
     457             : 
     458           0 :         default:
     459           0 :             return;
     460             :     }
     461             : 
     462         517 :     if (type != TIFF_ASCII && count != 0)
     463             :     {
     464           0 :         CPLError(CE_Warning, CPLE_AppDefined, "EXIF metadata truncated");
     465             :     }
     466             : }
     467             : 
     468             : /*
     469             :  * Return size of TIFFDataType in bytes
     470             :  */
     471         517 : static int EXIF_TIFFDataWidth(int /* GDALEXIFTIFFDataType */ type)
     472             : {
     473         517 :     switch (type)
     474             :     {
     475         282 :         case 0: /* nothing */
     476             :         case TIFF_BYTE:
     477             :         case TIFF_ASCII:
     478             :         case TIFF_SBYTE:
     479             :         case TIFF_UNDEFINED:
     480         282 :             return 1;
     481          80 :         case TIFF_SHORT:
     482             :         case TIFF_SSHORT:
     483          80 :             return 2;
     484          23 :         case TIFF_LONG:
     485             :         case TIFF_SLONG:
     486             :         case TIFF_FLOAT:
     487             :         case TIFF_IFD:
     488          23 :             return 4;
     489         132 :         case TIFF_RATIONAL:
     490             :         case TIFF_SRATIONAL:
     491             :         case TIFF_DOUBLE:
     492             :             // case TIFF_LONG8:
     493             :             // case TIFF_SLONG8:
     494             :             // case TIFF_IFD8:
     495         132 :             return 8;
     496           0 :         default:
     497           0 :             return 0; /* will return 0 for unknown types */
     498             :     }
     499             : }
     500             : 
     501             : /************************************************************************/
     502             : /*                        EXIFExtractMetadata()                         */
     503             : /*                                                                      */
     504             : /*      Extract all entry from a IFD                                    */
     505             : /************************************************************************/
     506         145 : CPLErr EXIFExtractMetadata(char **&papszMetadata, void *fpInL, int nOffset,
     507             :                            int bSwabflag, int nTIFFHEADER, int &nExifOffset,
     508             :                            int &nInterOffset, int &nGPSOffset)
     509             : {
     510             :     /* -------------------------------------------------------------------- */
     511             :     /*      Read number of entry in directory                               */
     512             :     /* -------------------------------------------------------------------- */
     513             :     GUInt16 nEntryCount;
     514         145 :     VSILFILE *const fp = static_cast<VSILFILE *>(fpInL);
     515             : 
     516         435 :     if (nOffset > INT_MAX - nTIFFHEADER ||
     517         290 :         VSIFSeekL(fp, nOffset + nTIFFHEADER, SEEK_SET) != 0 ||
     518         145 :         VSIFReadL(&nEntryCount, 1, sizeof(GUInt16), fp) != sizeof(GUInt16))
     519             :     {
     520           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     521             :                  "Error reading EXIF Directory count at " CPL_FRMT_GUIB,
     522           0 :                  static_cast<vsi_l_offset>(nOffset) + nTIFFHEADER);
     523           0 :         return CE_Failure;
     524             :     }
     525             : 
     526         145 :     if (bSwabflag)
     527           4 :         CPL_SWAP16PTR(&nEntryCount);
     528             : 
     529             :     // Some apps write empty directories - see bug 1523.
     530         145 :     if (nEntryCount == 0)
     531           1 :         return CE_None;
     532             : 
     533             :     // Some files are corrupt, a large entry count is a sign of this.
     534         144 :     if (nEntryCount > 125)
     535             :     {
     536           1 :         CPLError(CE_Warning, CPLE_AppDefined,
     537             :                  "Ignoring EXIF directory with unlikely entry count (%d).",
     538             :                  nEntryCount);
     539           1 :         return CE_Warning;
     540             :     }
     541             : 
     542             :     GDALEXIFTIFFDirEntry *poTIFFDir = static_cast<GDALEXIFTIFFDirEntry *>(
     543         143 :         CPLMalloc(nEntryCount * sizeof(GDALEXIFTIFFDirEntry)));
     544             : 
     545             :     /* -------------------------------------------------------------------- */
     546             :     /*      Read all directory entries                                      */
     547             :     /* -------------------------------------------------------------------- */
     548             :     {
     549         286 :         const unsigned int n = static_cast<int>(VSIFReadL(
     550         143 :             poTIFFDir, 1, nEntryCount * sizeof(GDALEXIFTIFFDirEntry), fp));
     551         143 :         if (n != nEntryCount * sizeof(GDALEXIFTIFFDirEntry))
     552             :         {
     553           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     554             :                      "Could not read all directories");
     555           0 :             CPLFree(poTIFFDir);
     556           0 :             return CE_Failure;
     557             :         }
     558             :     }
     559             : 
     560             :     /* -------------------------------------------------------------------- */
     561             :     /*      Parse all entry information in this directory                   */
     562             :     /* -------------------------------------------------------------------- */
     563         143 :     vector<char> oTempStorage(MAXSTRINGLENGTH + 1, 0);
     564         143 :     char *const szTemp = &oTempStorage[0];
     565             : 
     566             :     char szName[128];
     567             : 
     568         143 :     GDALEXIFTIFFDirEntry *poTIFFDirEntry = poTIFFDir;
     569             : 
     570         735 :     for (unsigned int i = nEntryCount; i > 0; i--, poTIFFDirEntry++)
     571             :     {
     572         592 :         if (bSwabflag)
     573             :         {
     574          12 :             CPL_SWAP16PTR(&poTIFFDirEntry->tdir_tag);
     575          12 :             CPL_SWAP16PTR(&poTIFFDirEntry->tdir_type);
     576          12 :             CPL_SWAP32PTR(&poTIFFDirEntry->tdir_count);
     577          12 :             CPL_SWAP32PTR(&poTIFFDirEntry->tdir_offset);
     578             :         }
     579             : 
     580             :         /* --------------------------------------------------------------------
     581             :          */
     582             :         /*      Find Tag name in table */
     583             :         /* --------------------------------------------------------------------
     584             :          */
     585         592 :         szName[0] = '\0';
     586         592 :         szTemp[0] = '\0';
     587             : 
     588       39972 :         for (const EXIFTagDesc *poExifTags = exiftags; poExifTags->tag;
     589             :              poExifTags++)
     590             :         {
     591       39743 :             if (poExifTags->tag == poTIFFDirEntry->tdir_tag)
     592             :             {
     593         363 :                 CPLAssert(nullptr != poExifTags->name);
     594             : 
     595         363 :                 CPLStrlcpy(szName, poExifTags->name, sizeof(szName));
     596         363 :                 break;
     597             :             }
     598             :         }
     599             : 
     600         592 :         if (nOffset == nGPSOffset)
     601             :         {
     602         459 :             for (const EXIFTagDesc *poGPSTags = gpstags;
     603         459 :                  poGPSTags->tag != 0xffff; poGPSTags++)
     604             :             {
     605         459 :                 if (poGPSTags->tag == poTIFFDirEntry->tdir_tag)
     606             :                 {
     607         154 :                     CPLAssert(nullptr != poGPSTags->name);
     608         154 :                     CPLStrlcpy(szName, poGPSTags->name, sizeof(szName));
     609         154 :                     break;
     610             :                 }
     611             :             }
     612             :         }
     613             :         /* --------------------------------------------------------------------
     614             :          */
     615             :         /*      If the tag was not found, look into the interoperability table
     616             :          */
     617             :         /* --------------------------------------------------------------------
     618             :          */
     619         592 :         if (nOffset == nInterOffset)
     620             :         {
     621           0 :             const struct intr_tag *poInterTags = intr_tags;
     622           0 :             for (; poInterTags->tag; poInterTags++)
     623           0 :                 if (poInterTags->tag == poTIFFDirEntry->tdir_tag)
     624             :                 {
     625           0 :                     CPLAssert(nullptr != poInterTags->name);
     626           0 :                     CPLStrlcpy(szName, poInterTags->name, sizeof(szName));
     627           0 :                     break;
     628             :                 }
     629             :         }
     630             : 
     631             :         /* --------------------------------------------------------------------
     632             :          */
     633             :         /*      Save important directory tag offset */
     634             :         /* --------------------------------------------------------------------
     635             :          */
     636             : 
     637             :         // Our current API uses int32 and not uint32
     638         592 :         if (poTIFFDirEntry->tdir_offset < INT_MAX)
     639             :         {
     640         591 :             if (poTIFFDirEntry->tdir_tag == EXIFOFFSETTAG)
     641          45 :                 nExifOffset = poTIFFDirEntry->tdir_offset;
     642         546 :             else if (poTIFFDirEntry->tdir_tag == INTEROPERABILITYOFFSET)
     643           0 :                 nInterOffset = poTIFFDirEntry->tdir_offset;
     644         546 :             else if (poTIFFDirEntry->tdir_tag == GPSOFFSETTAG)
     645          30 :                 nGPSOffset = poTIFFDirEntry->tdir_offset;
     646             :         }
     647             : 
     648             :         /* --------------------------------------------------------------------
     649             :          */
     650             :         /*      If we didn't recognise the tag just ignore it.  To see all */
     651             :         /*      tags comment out the continue. */
     652             :         /* --------------------------------------------------------------------
     653             :          */
     654         592 :         if (szName[0] == '\0')
     655             :         {
     656          75 :             snprintf(szName, sizeof(szName), "EXIF_%u",
     657          75 :                      poTIFFDirEntry->tdir_tag);
     658          75 :             continue;
     659             :         }
     660             : 
     661         517 :         vsi_l_offset nTagValueOffset = poTIFFDirEntry->tdir_offset;
     662             : 
     663             :         /* --------------------------------------------------------------------
     664             :          */
     665             :         /*      For UserComment we need to ignore the language binding and */
     666             :         /*      just return the actual contents. */
     667             :         /* --------------------------------------------------------------------
     668             :          */
     669         517 :         if (EQUAL(szName, "EXIF_UserComment"))
     670             :         {
     671           0 :             poTIFFDirEntry->tdir_type = TIFF_ASCII;
     672             : 
     673           0 :             if (poTIFFDirEntry->tdir_count >= 8)
     674             :             {
     675           0 :                 poTIFFDirEntry->tdir_count -= 8;
     676           0 :                 nTagValueOffset += 8;
     677             :             }
     678             :         }
     679             : 
     680             :         /* --------------------------------------------------------------------
     681             :          */
     682             :         /*      Make some UNDEFINED or BYTE fields ASCII for readability. */
     683             :         /* --------------------------------------------------------------------
     684             :          */
     685         517 :         if (EQUAL(szName, "EXIF_ExifVersion") ||
     686         481 :             EQUAL(szName, "EXIF_FlashPixVersion") ||
     687         454 :             EQUAL(szName, "EXIF_MakerNote") ||
     688         453 :             EQUAL(szName, "GPSProcessingMethod") ||
     689         453 :             EQUAL(szName, "EXIF_XmlPacket"))
     690          64 :             poTIFFDirEntry->tdir_type = TIFF_ASCII;
     691             : 
     692             :         /* --------------------------------------------------------------------
     693             :          */
     694             :         /*      Print tags */
     695             :         /* --------------------------------------------------------------------
     696             :          */
     697         517 :         if (poTIFFDirEntry->tdir_count > static_cast<GUInt32>(MAXSTRINGLENGTH))
     698             :         {
     699           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     700             :                      "Too many bytes in tag: %u, ignoring tag.",
     701             :                      poTIFFDirEntry->tdir_count);
     702           0 :             continue;
     703             :         }
     704             : 
     705         517 :         const int nDataWidth = EXIF_TIFFDataWidth(poTIFFDirEntry->tdir_type);
     706         517 :         if (nDataWidth == 0 || poTIFFDirEntry->tdir_type >= TIFF_IFD)
     707             :         {
     708           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     709             :                      "Invalid or unhandled EXIF data type: %d, ignoring tag.",
     710           0 :                      poTIFFDirEntry->tdir_type);
     711           0 :             continue;
     712             :         }
     713             : 
     714             :         /* --------------------------------------------------------------------
     715             :          */
     716             :         /*      This is at most 4 byte data so we can read it from tdir_offset
     717             :          */
     718             :         /* --------------------------------------------------------------------
     719             :          */
     720         517 :         const int space = poTIFFDirEntry->tdir_count * nDataWidth;
     721         517 :         if (space >= 0 && space <= 4)
     722             :         {
     723             : 
     724             :             unsigned char data[4];
     725         315 :             memcpy(data, &poTIFFDirEntry->tdir_offset, 4);
     726         315 :             if (bSwabflag)
     727             :             {
     728             :                 GUInt32 nValUInt32;
     729             :                 // Unswab 32bit value, and reswab per data type.
     730           6 :                 memcpy(&nValUInt32, data, 4);
     731           6 :                 CPL_SWAP32PTR(&nValUInt32);
     732           6 :                 memcpy(data, &nValUInt32, 4);
     733             : 
     734           6 :                 switch (poTIFFDirEntry->tdir_type)
     735             :                 {
     736           0 :                     case TIFF_LONG:
     737             :                     case TIFF_SLONG:
     738             :                     case TIFF_FLOAT:
     739           0 :                         memcpy(&nValUInt32, data, 4);
     740           0 :                         CPL_SWAP32PTR(&nValUInt32);
     741           0 :                         memcpy(data, &nValUInt32, 4);
     742           0 :                         break;
     743             : 
     744           3 :                     case TIFF_SSHORT:
     745             :                     case TIFF_SHORT:
     746           6 :                         for (unsigned j = 0; j < poTIFFDirEntry->tdir_count;
     747             :                              j++)
     748             :                         {
     749           3 :                             CPL_SWAP16PTR(reinterpret_cast<GUInt16 *>(data) +
     750             :                                           j);
     751             :                         }
     752           3 :                         break;
     753             : 
     754           3 :                     default:
     755           3 :                         break;
     756             :                 }
     757             :             }
     758             : 
     759             :             /* coverity[overrun-buffer-arg] */
     760         315 :             EXIFPrintData(szTemp, poTIFFDirEntry->tdir_type,
     761         315 :                           poTIFFDirEntry->tdir_count, data);
     762             :         }
     763             :         /* --------------------------------------------------------------------
     764             :          */
     765             :         /*      The data is being read where tdir_offset point to in the file */
     766             :         /* --------------------------------------------------------------------
     767             :          */
     768         202 :         else if (space > 0 && space < MAXSTRINGLENGTH)
     769             :         {
     770             :             unsigned char *data =
     771         202 :                 static_cast<unsigned char *>(VSIMalloc(space));
     772             : 
     773         202 :             if (data)
     774             :             {
     775         202 :                 CPL_IGNORE_RET_VAL(
     776         202 :                     VSIFSeekL(fp, nTagValueOffset + nTIFFHEADER, SEEK_SET));
     777         202 :                 CPL_IGNORE_RET_VAL(VSIFReadL(data, 1, space, fp));
     778             : 
     779         202 :                 if (bSwabflag)
     780             :                 {
     781           4 :                     switch (poTIFFDirEntry->tdir_type)
     782             :                     {
     783           0 :                         case TIFF_SHORT:
     784             :                         case TIFF_SSHORT:
     785             :                         {
     786           0 :                             for (unsigned j = 0; j < poTIFFDirEntry->tdir_count;
     787             :                                  j++)
     788             :                             {
     789           0 :                                 CPL_SWAP16PTR(
     790             :                                     reinterpret_cast<GUInt16 *>(data) + j);
     791             :                             }
     792           0 :                             break;
     793             :                         }
     794           0 :                         case TIFF_LONG:
     795             :                         case TIFF_SLONG:
     796             :                         case TIFF_FLOAT:
     797             :                         {
     798           0 :                             for (unsigned j = 0; j < poTIFFDirEntry->tdir_count;
     799             :                                  j++)
     800             :                             {
     801           0 :                                 CPL_SWAP32PTR(
     802             :                                     reinterpret_cast<GUInt32 *>(data) + j);
     803             :                             }
     804           0 :                             break;
     805             :                         }
     806           2 :                         case TIFF_RATIONAL:
     807             :                         case TIFF_SRATIONAL:
     808             :                         {
     809           2 :                             for (unsigned j = 0;
     810           6 :                                  j < 2 * poTIFFDirEntry->tdir_count; j++)
     811             :                             {
     812           4 :                                 CPL_SWAP32PTR(
     813             :                                     reinterpret_cast<GUInt32 *>(data) + j);
     814             :                             }
     815           2 :                             break;
     816             :                         }
     817           0 :                         case TIFF_DOUBLE:
     818             :                         {
     819           0 :                             for (unsigned j = 0; j < poTIFFDirEntry->tdir_count;
     820             :                                  j++)
     821             :                             {
     822           0 :                                 CPL_SWAPDOUBLE(
     823             :                                     reinterpret_cast<double *>(data) + j);
     824             :                             }
     825           0 :                             break;
     826             :                         }
     827           2 :                         default:
     828           2 :                             break;
     829             :                     }
     830             :                 }
     831             : 
     832         202 :                 EXIFPrintData(szTemp, poTIFFDirEntry->tdir_type,
     833             :                               poTIFFDirEntry->tdir_count, data);
     834         202 :                 CPLFree(data);
     835         202 :             }
     836             :         }
     837             :         else
     838             :         {
     839           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     840             :                      "Invalid EXIF header size: %ld, ignoring tag.",
     841             :                      static_cast<long>(space));
     842             :         }
     843             : 
     844         517 :         papszMetadata = CSLSetNameValue(papszMetadata, szName, szTemp);
     845             :     }
     846         143 :     CPLFree(poTIFFDir);
     847             : 
     848         143 :     return CE_None;
     849             : }
     850             : 
     851             : /************************************************************************/
     852             : /*                        WriteLEUInt16()                               */
     853             : /************************************************************************/
     854             : 
     855         575 : static void WriteLEUInt16(GByte *pabyData, GUInt32 &nBufferOff, GUInt16 nVal)
     856             : {
     857         575 :     pabyData[nBufferOff] = static_cast<GByte>(nVal & 0xff);
     858         575 :     pabyData[nBufferOff + 1] = static_cast<GByte>(nVal >> 8);
     859         575 :     nBufferOff += 2;
     860         575 : }
     861             : 
     862             : /************************************************************************/
     863             : /*                        WriteLEUInt32()                               */
     864             : /************************************************************************/
     865             : 
     866         627 : static void WriteLEUInt32(GByte *pabyData, GUInt32 &nBufferOff, GUInt32 nVal)
     867             : {
     868         627 :     pabyData[nBufferOff] = static_cast<GByte>(nVal & 0xff);
     869         627 :     pabyData[nBufferOff + 1] = static_cast<GByte>((nVal >> 8) & 0xff);
     870         627 :     pabyData[nBufferOff + 2] = static_cast<GByte>((nVal >> 16) & 0xff);
     871         627 :     pabyData[nBufferOff + 3] = static_cast<GByte>(nVal >> 24);
     872         627 :     nBufferOff += 4;
     873         627 : }
     874             : 
     875             : /************************************************************************/
     876             : /*                          GetHexValue()                               */
     877             : /************************************************************************/
     878             : 
     879         195 : static int GetHexValue(char ch)
     880             : {
     881         195 :     const char chDEC_ZERO = '0';
     882         195 :     if (ch >= chDEC_ZERO && ch <= '9')
     883         183 :         return ch - chDEC_ZERO;
     884          12 :     if (ch >= 'a' && ch <= 'f')
     885           5 :         return ch - 'a' + 10;
     886           7 :     if (ch >= 'A' && ch <= 'F')
     887           7 :         return ch - 'A' + 10;
     888           0 :     return -1;
     889             : }
     890             : 
     891             : /************************************************************************/
     892             : /*                         ParseUndefined()                             */
     893             : /************************************************************************/
     894             : 
     895          32 : static GByte *ParseUndefined(const char *pszVal, GUInt32 *pnLength)
     896             : {
     897          32 :     GUInt32 nSize = 0;
     898          32 :     bool bIsHexExcaped = true;
     899          32 :     const char chDEC_ZERO = '0';
     900          32 :     GByte *pabyData = reinterpret_cast<GByte *>(CPLMalloc(strlen(pszVal) + 1));
     901             : 
     902             :     // Is it a hexadecimal string like "0xA 0x1E 00 0xDF..." ?
     903          60 :     for (size_t i = 0; pszVal[i] != '\0';)
     904             :     {
     905             :         // 0xA
     906          97 :         if (pszVal[i] == chDEC_ZERO && pszVal[i + 1] == 'x' &&
     907         157 :             GetHexValue(pszVal[i + 2]) >= 0 &&
     908          39 :             (pszVal[i + 3] == ' ' || pszVal[i + 3] == '\0'))
     909             :         {
     910           0 :             pabyData[nSize] = static_cast<GByte>(GetHexValue(pszVal[i + 2]));
     911           0 :             nSize++;
     912           0 :             if (pszVal[i + 3] == '\0')
     913           0 :                 break;
     914           0 :             i += 4;
     915             :         }
     916             :         // 0xAA
     917          97 :         else if (pszVal[i] == chDEC_ZERO && pszVal[i + 1] == 'x' &&
     918          78 :                  GetHexValue(pszVal[i + 2]) >= 0 &&
     919         157 :                  GetHexValue(pszVal[i + 3]) >= 0 &&
     920          39 :                  (pszVal[i + 4] == ' ' || pszVal[i + 4] == '\0'))
     921             :         {
     922          39 :             pabyData[nSize] = static_cast<GByte>(
     923          39 :                 GetHexValue(pszVal[i + 2]) * 16 + GetHexValue(pszVal[i + 3]));
     924          39 :             nSize++;
     925          39 :             if (pszVal[i + 4] == '\0')
     926          11 :                 break;
     927          28 :             i += 5;
     928             :         }
     929             :         // 00
     930          21 :         else if (pszVal[i] == chDEC_ZERO && pszVal[i + 1] == chDEC_ZERO &&
     931           0 :                  (pszVal[i + 2] == ' ' || pszVal[i + 2] == '\0'))
     932             :         {
     933           0 :             pabyData[nSize] = 0;
     934           0 :             nSize++;
     935           0 :             if (pszVal[i + 2] == '\0')
     936           0 :                 break;
     937           0 :             i += 3;
     938             :         }
     939             :         else
     940             :         {
     941          21 :             bIsHexExcaped = false;
     942          21 :             break;
     943             :         }
     944             :     }
     945             : 
     946          32 :     if (bIsHexExcaped)
     947             :     {
     948          11 :         *pnLength = nSize;
     949          11 :         return pabyData;
     950             :     }
     951             : 
     952             :     // Otherwise take the string value as a byte value
     953          21 :     memcpy(pabyData, pszVal, strlen(pszVal) + 1);
     954          21 :     *pnLength = static_cast<GUInt32>(strlen(pszVal));
     955          21 :     return pabyData;
     956             : }
     957             : 
     958             : /************************************************************************/
     959             : /*                           EXIFTagSort()                              */
     960             : /************************************************************************/
     961             : 
     962             : struct TagValue
     963             : {
     964             :     GUInt16 tag;
     965             :     GDALEXIFTIFFDataType datatype;
     966             :     GByte *pabyVal;
     967             :     GUInt32 nLength;
     968             :     GUInt32 nLengthBytes;
     969             :     int nRelOffset;
     970             : };
     971             : 
     972         226 : static bool EXIFTagSort(const TagValue &a, const TagValue &b)
     973             : {
     974         226 :     return a.tag <= b.tag;
     975             : }
     976             : 
     977             : /************************************************************************/
     978             : /*                        GetNumDenomFromDouble()                       */
     979             : /************************************************************************/
     980             : 
     981          80 : static bool GetNumDenomFromDouble(GDALEXIFTIFFDataType datatype, double dfVal,
     982             :                                   GUInt32 &nNum, GUInt32 &nDenom)
     983             : {
     984          80 :     nNum = 0;
     985          80 :     nDenom = 1;
     986          80 :     if (CPLIsNan(dfVal))
     987             :     {
     988           1 :         return false;
     989             :     }
     990          79 :     else if (datatype == TIFF_RATIONAL)
     991             :     {
     992          72 :         if (dfVal < 0)
     993             :         {
     994           1 :             return false;
     995             :         }
     996         142 :         else if (dfVal <= std::numeric_limits<unsigned int>::max() &&
     997          71 :                  dfVal == static_cast<GUInt32>(dfVal))
     998             :         {
     999          54 :             nNum = static_cast<GUInt32>(dfVal);
    1000          54 :             nDenom = 1;
    1001             :         }
    1002          17 :         else if (dfVal < 1.0)
    1003             :         {
    1004           1 :             nNum = static_cast<GUInt32>(
    1005           1 :                 dfVal * std::numeric_limits<unsigned int>::max());
    1006           1 :             nDenom = std::numeric_limits<unsigned int>::max();
    1007             :         }
    1008             :         else
    1009             :         {
    1010          16 :             nNum = std::numeric_limits<unsigned int>::max();
    1011          16 :             nDenom = static_cast<GUInt32>(
    1012          16 :                 std::numeric_limits<unsigned int>::max() / dfVal);
    1013             :         }
    1014             :     }
    1015           7 :     else if (dfVal < 0.0)
    1016             :     {
    1017           6 :         if (dfVal >= std::numeric_limits<int>::min() &&
    1018           3 :             dfVal == static_cast<GInt32>(dfVal))
    1019             :         {
    1020           1 :             nNum = static_cast<GInt32>(dfVal);
    1021           1 :             nDenom = 1;
    1022             :         }
    1023           2 :         else if (dfVal > -1.0)
    1024             :         {
    1025           2 :             nNum = -static_cast<GInt32>((-dfVal) *
    1026           1 :                                         std::numeric_limits<int>::max());
    1027           1 :             nDenom = std::numeric_limits<int>::max();
    1028             :         }
    1029             :         else
    1030             :         {
    1031           1 :             nNum = -std::numeric_limits<int>::max();
    1032           1 :             nDenom =
    1033           1 :                 static_cast<GInt32>(std::numeric_limits<int>::max() / (-dfVal));
    1034             :         }
    1035             :     }
    1036             :     else
    1037             :     {
    1038           8 :         if (dfVal <= std::numeric_limits<int>::max() &&
    1039           4 :             dfVal == static_cast<GInt32>(dfVal))
    1040             :         {
    1041           2 :             nNum = static_cast<GInt32>(dfVal);
    1042           2 :             nDenom = 1;
    1043             :         }
    1044           2 :         else if (dfVal < 1.0)
    1045             :         {
    1046           1 :             nNum = static_cast<GInt32>(dfVal * std::numeric_limits<int>::max());
    1047           1 :             nDenom = std::numeric_limits<int>::max();
    1048             :         }
    1049             :         else
    1050             :         {
    1051           1 :             nNum = std::numeric_limits<int>::max();
    1052           1 :             nDenom =
    1053           1 :                 static_cast<GInt32>(std::numeric_limits<int>::max() / dfVal);
    1054             :         }
    1055             :     }
    1056          78 :     return true;
    1057             : }
    1058             : 
    1059             : /************************************************************************/
    1060             : /*                       EXIFFormatTagValue()                           */
    1061             : /************************************************************************/
    1062             : 
    1063             : enum class EXIFLocation
    1064             : {
    1065             :     MAIN_IFD,
    1066             :     EXIF_IFD,
    1067             :     GPS_IFD
    1068             : };
    1069             : 
    1070          90 : static std::vector<TagValue> EXIFFormatTagValue(char **papszEXIFMetadata,
    1071             :                                                 EXIFLocation location,
    1072             :                                                 GUInt32 *pnOfflineSize)
    1073             : {
    1074          90 :     std::vector<TagValue> tags;
    1075          90 :     int nRelOffset = 0;
    1076          90 :     const EXIFTagDesc *tagdescArray =
    1077          90 :         (location == EXIFLocation::GPS_IFD) ? gpstags : exiftags;
    1078             : 
    1079         561 :     for (char **papszIter = papszEXIFMetadata; papszIter && *papszIter;
    1080             :          ++papszIter)
    1081             :     {
    1082         471 :         if (!STARTS_WITH_CI(*papszIter, "EXIF_"))
    1083         316 :             continue;
    1084         465 :         if (location == EXIFLocation::GPS_IFD &&
    1085         155 :             !STARTS_WITH_CI(*papszIter, "EXIF_GPS"))
    1086         111 :             continue;
    1087         354 :         if (location != EXIFLocation::GPS_IFD &&
    1088         310 :             STARTS_WITH_CI(*papszIter, "EXIF_GPS"))
    1089          88 :             continue;
    1090             : 
    1091         266 :         bool bFound = false;
    1092         266 :         size_t i = 0;  // needed after loop
    1093        9985 :         for (; tagdescArray[i].name[0] != '\0'; i++)
    1094             :         {
    1095        9983 :             if (STARTS_WITH_CI(*papszIter, tagdescArray[i].name) &&
    1096         312 :                 (*papszIter)[strlen(tagdescArray[i].name)] == '=')
    1097             :             {
    1098         264 :                 bFound = true;
    1099         264 :                 break;
    1100             :             }
    1101             :         }
    1102             : 
    1103         266 :         if (location == EXIFLocation::MAIN_IFD)
    1104             :         {
    1105         111 :             if (tagdescArray[i].tag > 0x8298)  // EXIF_Copyright
    1106             :             {
    1107          70 :                 continue;
    1108             :             }
    1109             :         }
    1110         155 :         else if (location == EXIFLocation::EXIF_IFD)
    1111             :         {
    1112         111 :             if (tagdescArray[i].tag <= 0x8298)  // EXIF_Copyright
    1113             :             {
    1114          41 :                 continue;
    1115             :             }
    1116             :         }
    1117             : 
    1118         155 :         char *pszKey = nullptr;
    1119         155 :         const char *pszValue = CPLParseNameValue(*papszIter, &pszKey);
    1120         155 :         if (!bFound || pszKey == nullptr || pszValue == nullptr)
    1121             :         {
    1122           1 :             CPLError(CE_Warning, CPLE_NotSupported,
    1123           1 :                      "Cannot write unknown %s tag", pszKey ? pszKey : "");
    1124             :         }
    1125         154 :         else if (tagdescArray[i].datatype == TIFF_NOTYPE)
    1126             :         {
    1127           0 :             CPLDebug("EXIF", "Tag %s ignored on write", tagdescArray[i].name);
    1128             :         }
    1129             :         else
    1130             :         {
    1131             :             TagValue tag;
    1132         154 :             tag.tag = tagdescArray[i].tag;
    1133         154 :             tag.datatype = tagdescArray[i].datatype;
    1134         154 :             tag.pabyVal = nullptr;
    1135         154 :             tag.nLength = 0;
    1136         154 :             tag.nLengthBytes = 0;
    1137         154 :             tag.nRelOffset = -1;
    1138             : 
    1139         154 :             if (tag.datatype == TIFF_ASCII)
    1140             :             {
    1141          50 :                 if (tagdescArray[i].length == 0 ||
    1142          36 :                     strlen(pszValue) + 1 == tagdescArray[i].length)
    1143             :                 {
    1144          34 :                     tag.pabyVal =
    1145          34 :                         reinterpret_cast<GByte *>(CPLStrdup(pszValue));
    1146          34 :                     tag.nLength = 1 + static_cast<int>(strlen(pszValue));
    1147             :                 }
    1148          16 :                 else if (strlen(pszValue) >= tagdescArray[i].length)
    1149             :                 {
    1150           1 :                     CPLError(CE_Warning, CPLE_AppDefined,
    1151             :                              "Value of %s will be truncated",
    1152           1 :                              tagdescArray[i].name);
    1153           1 :                     tag.pabyVal = reinterpret_cast<GByte *>(
    1154           1 :                         CPLMalloc(tagdescArray[i].length));
    1155           1 :                     memcpy(tag.pabyVal, pszValue, tagdescArray[i].length);
    1156           1 :                     tag.nLength = tagdescArray[i].length;
    1157           1 :                     tag.pabyVal[tag.nLength - 1] = '\0';
    1158             :                 }
    1159             :                 else
    1160             :                 {
    1161          15 :                     tag.pabyVal = reinterpret_cast<GByte *>(
    1162          15 :                         CPLMalloc(tagdescArray[i].length));
    1163          15 :                     memset(tag.pabyVal, ' ', tagdescArray[i].length);
    1164          15 :                     memcpy(tag.pabyVal, pszValue, strlen(pszValue));
    1165          15 :                     tag.nLength = tagdescArray[i].length;
    1166          15 :                     tag.pabyVal[tag.nLength - 1] = '\0';
    1167             :                 }
    1168          50 :                 tag.nLengthBytes = tag.nLength;
    1169             :             }
    1170         104 :             else if (tag.datatype == TIFF_BYTE ||
    1171          96 :                      tag.datatype == TIFF_UNDEFINED)
    1172             :             {
    1173          32 :                 GUInt32 nValLength = 0;
    1174          32 :                 GByte *pabyVal = ParseUndefined(pszValue, &nValLength);
    1175          32 :                 if (tagdescArray[i].length == 0 ||
    1176          30 :                     nValLength == tagdescArray[i].length)
    1177             :                 {
    1178          30 :                     if (tag.tag == 0x9286 &&
    1179           1 :                         strncmp(pszValue, "0x", 2) != 0)  // EXIF_UserComment
    1180             :                     {
    1181           1 :                         const char *pszRealVal =
    1182             :                             reinterpret_cast<char *>(pabyVal);
    1183           1 :                         const int nValueLen =
    1184           1 :                             static_cast<int>(strlen(pszRealVal));
    1185             :                         // 8 first bytes are the character code
    1186             :                         // Set them to 0 to mean undefined
    1187           1 :                         tag.pabyVal =
    1188           1 :                             static_cast<GByte *>(CPLCalloc(1, 8 + nValueLen));
    1189           1 :                         tag.nLength = 8 + nValueLen;
    1190           1 :                         memcpy(tag.pabyVal + 8, pszRealVal, nValueLen);
    1191           1 :                         CPLFree(pabyVal);
    1192             :                     }
    1193             :                     else
    1194             :                     {
    1195          29 :                         tag.pabyVal = pabyVal;
    1196          29 :                         tag.nLength = nValLength;
    1197          30 :                     }
    1198             :                 }
    1199           2 :                 else if (nValLength > tagdescArray[i].length)
    1200             :                 {
    1201           1 :                     CPLError(CE_Warning, CPLE_AppDefined,
    1202             :                              "Value of %s will be truncated",
    1203           1 :                              tagdescArray[i].name);
    1204           1 :                     tag.pabyVal = pabyVal;
    1205           1 :                     tag.nLength = tagdescArray[i].length;
    1206             :                 }
    1207             :                 else
    1208             :                 {
    1209           1 :                     tag.pabyVal = reinterpret_cast<GByte *>(
    1210           1 :                         CPLRealloc(pabyVal, tagdescArray[i].length));
    1211           1 :                     memset(tag.pabyVal + nValLength, '\0',
    1212           1 :                            tagdescArray[i].length - nValLength);
    1213           1 :                     tag.nLength = tagdescArray[i].length;
    1214             :                 }
    1215          32 :                 tag.nLengthBytes = tag.nLength;
    1216             :             }
    1217          72 :             else if (tag.datatype == TIFF_SHORT || tag.datatype == TIFF_LONG)
    1218             :             {
    1219          26 :                 char **papszTokens = CSLTokenizeString2(pszValue, " ", 0);
    1220          26 :                 GUInt32 nTokens = static_cast<GUInt32>(CSLCount(papszTokens));
    1221          26 :                 const GUInt32 nDataTypeSize =
    1222          26 :                     (tag.datatype == TIFF_SHORT) ? 2 : 4;
    1223          26 :                 if (tagdescArray[i].length == 0 ||
    1224          25 :                     nTokens == tagdescArray[i].length)
    1225             :                 {
    1226             :                     // ok
    1227             :                 }
    1228           2 :                 else if (nTokens > tagdescArray[i].length)
    1229             :                 {
    1230           1 :                     CPLError(CE_Warning, CPLE_AppDefined,
    1231             :                              "Value of %s will be truncated",
    1232           1 :                              tagdescArray[i].name);
    1233             :                 }
    1234             :                 else
    1235             :                 {
    1236           1 :                     CPLError(CE_Warning, CPLE_AppDefined,
    1237             :                              "Not enough values for %s: %d expected. "
    1238             :                              "Filling with zeroes",
    1239           1 :                              tagdescArray[i].name, tagdescArray[i].length);
    1240             :                 }
    1241             : 
    1242          52 :                 tag.nLength = (tagdescArray[i].length == 0)
    1243          26 :                                   ? nTokens
    1244          25 :                                   : tagdescArray[i].length;
    1245          26 :                 tag.pabyVal = reinterpret_cast<GByte *>(CPLCalloc(
    1246          26 :                     1, cpl::fits_on<int>(nDataTypeSize * tag.nLength)));
    1247             : 
    1248          26 :                 GUInt32 nOffset = 0;
    1249          55 :                 for (GUInt32 j = 0; j < std::min(nTokens, tag.nLength); j++)
    1250             :                 {
    1251          29 :                     GUInt32 nVal = atoi(papszTokens[j]);
    1252          29 :                     if (tag.datatype == TIFF_SHORT)
    1253          14 :                         WriteLEUInt16(tag.pabyVal, nOffset,
    1254             :                                       static_cast<GUInt16>(nVal));
    1255             :                     else
    1256          15 :                         WriteLEUInt32(tag.pabyVal, nOffset, nVal);
    1257             :                 }
    1258          26 :                 CSLDestroy(papszTokens);
    1259             : 
    1260          26 :                 tag.nLengthBytes = tag.nLength * nDataTypeSize;
    1261             :             }
    1262          46 :             else if (tag.datatype == TIFF_RATIONAL ||
    1263           7 :                      tag.datatype == TIFF_SRATIONAL)
    1264             :             {
    1265          46 :                 char **papszTokens = CSLTokenizeString2(pszValue, " ", 0);
    1266          46 :                 GUInt32 nTokens = static_cast<GUInt32>(CSLCount(papszTokens));
    1267          46 :                 const GUInt32 nDataTypeSize = 8;
    1268          46 :                 if (tagdescArray[i].length == 0 ||
    1269          46 :                     nTokens == tagdescArray[i].length)
    1270             :                 {
    1271             :                     // ok
    1272             :                 }
    1273           1 :                 else if (nTokens > tagdescArray[i].length)
    1274             :                 {
    1275           1 :                     CPLError(CE_Warning, CPLE_AppDefined,
    1276             :                              "Value of %s will be truncated",
    1277           1 :                              tagdescArray[i].name);
    1278             :                 }
    1279             :                 else
    1280             :                 {
    1281           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
    1282             :                              "Not enough values for %s: %d expected. "
    1283             :                              "Filling with zeroes",
    1284           0 :                              tagdescArray[i].name, tagdescArray[i].length);
    1285             :                 }
    1286             : 
    1287          92 :                 tag.nLength = (tagdescArray[i].length == 0)
    1288          46 :                                   ? nTokens
    1289          46 :                                   : tagdescArray[i].length;
    1290          46 :                 tag.pabyVal = reinterpret_cast<GByte *>(
    1291          46 :                     CPLCalloc(1, nDataTypeSize * tag.nLength));
    1292             : 
    1293          46 :                 GUInt32 nOffset = 0;
    1294         126 :                 for (GUInt32 j = 0; j < std::min(nTokens, tag.nLength); j++)
    1295             :                 {
    1296             :                     double dfVal =
    1297          98 :                         CPLAtof(papszTokens[j][0] == '(' ? papszTokens[j] + 1
    1298          18 :                                                          : papszTokens[j]);
    1299          80 :                     GUInt32 nNum = 1;
    1300          80 :                     GUInt32 nDenom = 0;
    1301          80 :                     if (!GetNumDenomFromDouble(tag.datatype, dfVal, nNum,
    1302             :                                                nDenom))
    1303             :                     {
    1304           2 :                         CPLError(CE_Warning, CPLE_AppDefined,
    1305             :                                  "Value %f is illegal for tag %s", dfVal,
    1306           2 :                                  tagdescArray[i].name);
    1307             :                     }
    1308             : 
    1309          80 :                     WriteLEUInt32(tag.pabyVal, nOffset, nNum);
    1310          80 :                     WriteLEUInt32(tag.pabyVal, nOffset, nDenom);
    1311             :                 }
    1312          46 :                 CSLDestroy(papszTokens);
    1313             : 
    1314          46 :                 tag.nLengthBytes = tag.nLength * nDataTypeSize;
    1315             :             }
    1316             :             else
    1317             :             {
    1318             :                 // Shouldn't happen. Programming error
    1319           0 :                 CPLError(CE_Warning, CPLE_NotSupported,
    1320           0 :                          "Unhandled type %d for tag %s", tag.datatype,
    1321           0 :                          tagdescArray[i].name);
    1322             :             }
    1323             : 
    1324         154 :             if (tag.nLengthBytes != 0)
    1325             :             {
    1326         154 :                 if (tag.nLengthBytes > 4)
    1327             :                 {
    1328          68 :                     tag.nRelOffset = nRelOffset;
    1329          68 :                     nRelOffset += tag.nLengthBytes + (tag.nLengthBytes % 1);
    1330             :                 }
    1331         154 :                 tags.push_back(tag);
    1332             :             }
    1333             :         }
    1334         155 :         CPLFree(pszKey);
    1335             :     }
    1336             : 
    1337             :     // Sort tags by ascending order
    1338          90 :     std::sort(tags.begin(), tags.end(), EXIFTagSort);
    1339             : 
    1340             : #ifdef notdef
    1341             :     if (location == EXIF_IFD &&
    1342             :         CSLFetchNameValue(papszEXIFMetadata, "EXIF_ExifVersion") == nullptr)
    1343             :     {
    1344             :         const GUInt16 EXIF_VERSION = 0x9000;
    1345             :         TagValue tag;
    1346             :         tag.tag = EXIF_VERSION;
    1347             :         tag.datatype = TIFF_UNDEFINED;
    1348             :         tag.pabyVal = reinterpret_cast<GByte *>(CPLStrdup("0231"));
    1349             :         tag.nLength = 4;
    1350             :         tag.nLengthBytes = 4;
    1351             :         tag.nRelOffset = -1;
    1352             :         tags.push_back(tag);
    1353             :     }
    1354             : #endif
    1355             : 
    1356          90 :     *pnOfflineSize = nRelOffset;
    1357             : 
    1358          90 :     return tags;
    1359             : }
    1360             : 
    1361             : /************************************************************************/
    1362             : /*                            WriteTag()                                */
    1363             : /************************************************************************/
    1364             : 
    1365          64 : static void WriteTag(GByte *pabyData, GUInt32 &nBufferOff, GUInt16 nTag,
    1366             :                      GDALEXIFTIFFDataType nType, GUInt32 nCount, GUInt32 nVal)
    1367             : {
    1368          64 :     WriteLEUInt16(pabyData, nBufferOff, nTag);
    1369          64 :     WriteLEUInt16(pabyData, nBufferOff, static_cast<GUInt16>(nType));
    1370          64 :     WriteLEUInt32(pabyData, nBufferOff, nCount);
    1371          64 :     WriteLEUInt32(pabyData, nBufferOff, nVal);
    1372          64 : }
    1373             : 
    1374             : /************************************************************************/
    1375             : /*                            WriteTags()                               */
    1376             : /************************************************************************/
    1377             : 
    1378          42 : static void WriteTags(GByte *pabyData, GUInt32 &nBufferOff,
    1379             :                       GUInt32 offsetIFDData, const std::vector<TagValue> &tags)
    1380             : {
    1381         195 :     for (const auto &tag : tags)
    1382             :     {
    1383         153 :         WriteLEUInt16(pabyData, nBufferOff, tag.tag);
    1384         153 :         WriteLEUInt16(pabyData, nBufferOff, static_cast<GUInt16>(tag.datatype));
    1385         153 :         WriteLEUInt32(pabyData, nBufferOff, tag.nLength);
    1386         153 :         if (tag.nRelOffset < 0)
    1387             :         {
    1388          86 :             CPLAssert(tag.nLengthBytes <= 4);
    1389          86 :             memcpy(pabyData + nBufferOff, tag.pabyVal, tag.nLengthBytes);
    1390          86 :             nBufferOff += 4;
    1391             :         }
    1392             :         else
    1393             :         {
    1394          67 :             WriteLEUInt32(pabyData, nBufferOff, tag.nRelOffset + offsetIFDData);
    1395          67 :             memcpy(pabyData + EXIF_HEADER_SIZE + tag.nRelOffset + offsetIFDData,
    1396          67 :                    tag.pabyVal, tag.nLengthBytes);
    1397             :         }
    1398             :     }
    1399          42 : }
    1400             : 
    1401             : /************************************************************************/
    1402             : /*                            FreeTags()                                */
    1403             : /************************************************************************/
    1404             : 
    1405          90 : static void FreeTags(std::vector<TagValue> &tags)
    1406             : {
    1407         244 :     for (auto &tag : tags)
    1408             :     {
    1409         154 :         CPLFree(tag.pabyVal);
    1410             :     }
    1411          90 : }
    1412             : 
    1413             : /************************************************************************/
    1414             : /*                          EXIFCreate()                                */
    1415             : /************************************************************************/
    1416             : 
    1417         262 : GByte *EXIFCreate(char **papszEXIFMetadata, GByte *pabyThumbnail,
    1418             :                   GUInt32 nThumbnailSize, GUInt32 nThumbnailWidth,
    1419             :                   GUInt32 nThumbnailHeight, GUInt32 *pnOutBufferSize)
    1420             : {
    1421         262 :     *pnOutBufferSize = 0;
    1422             : 
    1423         262 :     bool bHasEXIFMetadata = false;
    1424         292 :     for (char **papszIter = papszEXIFMetadata; papszIter && *papszIter;
    1425             :          ++papszIter)
    1426             :     {
    1427          55 :         if (STARTS_WITH_CI(*papszIter, "EXIF_"))
    1428             :         {
    1429          25 :             bHasEXIFMetadata = true;
    1430          25 :             break;
    1431             :         }
    1432             :     }
    1433         262 :     if (!bHasEXIFMetadata && pabyThumbnail == nullptr)
    1434             :     {
    1435             :         // Nothing to do
    1436         232 :         return nullptr;
    1437             :     }
    1438             : 
    1439          30 :     GUInt32 nOfflineSizeMain = 0;
    1440             :     std::vector<TagValue> mainTags = EXIFFormatTagValue(
    1441          60 :         papszEXIFMetadata, EXIFLocation::MAIN_IFD, &nOfflineSizeMain);
    1442             : 
    1443          30 :     GUInt32 nOfflineSizeEXIF = 0;
    1444             :     std::vector<TagValue> exifTags = EXIFFormatTagValue(
    1445          60 :         papszEXIFMetadata, EXIFLocation::EXIF_IFD, &nOfflineSizeEXIF);
    1446             : 
    1447          30 :     GUInt32 nOfflineSizeGPS = 0;
    1448             :     std::vector<TagValue> gpsTags = EXIFFormatTagValue(
    1449          60 :         papszEXIFMetadata, EXIFLocation::GPS_IFD, &nOfflineSizeGPS);
    1450             : 
    1451          30 :     const GUInt16 nEXIFTags = static_cast<GUInt16>(exifTags.size());
    1452          30 :     const GUInt16 nGPSTags = static_cast<GUInt16>(gpsTags.size());
    1453             : 
    1454             :     // including TIFFTAG_EXIFIFD and TIFFTAG_GPSIFD
    1455          30 :     GUInt16 nIFD0Entries = (nEXIFTags ? 1 : 0) + (nGPSTags ? 1 : 0) +
    1456          30 :                            static_cast<GUInt16>(mainTags.size());
    1457             : 
    1458          30 :     GUInt32 nBufferSize = EXIF_HEADER_SIZE +  // Exif header
    1459             :                           4 +                 // Tiff signature
    1460             :                           4 +                 // Offset of IFD0
    1461             :                           2 +                 // Number of entries of IFD0
    1462          30 :                           nIFD0Entries * TAG_SIZE +  // Entries of IFD0
    1463             :                           nOfflineSizeMain;
    1464             : 
    1465          30 :     if (nEXIFTags)
    1466             :     {
    1467          24 :         nBufferSize += 2 +  // Number of entries of private EXIF IFD
    1468          24 :                        nEXIFTags * TAG_SIZE + nOfflineSizeEXIF;
    1469             :     }
    1470             : 
    1471          30 :     if (nGPSTags)
    1472             :     {
    1473          11 :         nBufferSize += 2 +  // Number of entries of private GPS IFD
    1474          11 :                        nGPSTags * TAG_SIZE + nOfflineSizeGPS;
    1475             :     }
    1476             : 
    1477          30 :     GUInt16 nIFD1Entries = 0;
    1478          30 :     if (pabyThumbnail)
    1479             :     {
    1480           6 :         nIFD1Entries = 5;
    1481           6 :         nBufferSize += 4 +                        // Offset of IFD1
    1482             :                        2 +                        // Number of entries of IFD1
    1483           6 :                        nIFD1Entries * TAG_SIZE +  // Entries of IFD1
    1484             :                        nThumbnailSize;
    1485             :     }
    1486          30 :     nBufferSize += 4;  // Offset of next IFD
    1487             : 
    1488          30 :     GByte *pabyData = nullptr;
    1489          30 :     if (nBufferSize > 65536)
    1490             :     {
    1491           1 :         CPLError(CE_Warning, CPLE_AppDefined,
    1492             :                  "Cannot write EXIF segment. "
    1493             :                  "The size of the EXIF segment exceeds 65536 bytes");
    1494             :     }
    1495             :     else
    1496             :     {
    1497          29 :         pabyData = static_cast<GByte *>(VSI_CALLOC_VERBOSE(1, nBufferSize));
    1498             :     }
    1499          30 :     if (pabyData == nullptr)
    1500             :     {
    1501           1 :         FreeTags(mainTags);
    1502           1 :         FreeTags(exifTags);
    1503           1 :         FreeTags(gpsTags);
    1504           1 :         return nullptr;
    1505             :     }
    1506             : 
    1507          29 :     memcpy(pabyData, "Exif\0\0", EXIF_HEADER_SIZE);
    1508          29 :     GUInt32 nBufferOff = EXIF_HEADER_SIZE;
    1509          29 :     GUInt32 nTIFFStartOff = nBufferOff;
    1510             : 
    1511             :     // TIFF little-endian signature.
    1512          29 :     const GUInt16 TIFF_LITTLEENDIAN = 0x4949;
    1513          29 :     WriteLEUInt16(pabyData, nBufferOff, TIFF_LITTLEENDIAN);
    1514          29 :     const GUInt16 TIFF_VERSION = 42;
    1515          29 :     WriteLEUInt16(pabyData, nBufferOff, TIFF_VERSION);
    1516             : 
    1517             :     // Offset of IFD0
    1518          29 :     WriteLEUInt32(pabyData, nBufferOff, nBufferOff - nTIFFStartOff + 4);
    1519             : 
    1520             :     // Number of entries of IFD0
    1521          29 :     WriteLEUInt16(pabyData, nBufferOff, nIFD0Entries);
    1522             : 
    1523          29 :     if (!mainTags.empty())
    1524             :     {
    1525           8 :         GUInt32 offsetIFDData =
    1526           8 :             nBufferOff - nTIFFStartOff + nIFD0Entries * TAG_SIZE + 4;
    1527           8 :         WriteTags(pabyData, nBufferOff, offsetIFDData, mainTags);
    1528             :     }
    1529             : 
    1530          29 :     GUInt32 nEXIFIFDOffset = 0;
    1531          29 :     if (nEXIFTags)
    1532             :     {
    1533          23 :         WriteTag(pabyData, nBufferOff, EXIFOFFSETTAG, TIFF_LONG, 1, 0);
    1534          23 :         nEXIFIFDOffset = nBufferOff - 4;
    1535             :     }
    1536             : 
    1537          29 :     GUInt32 nGPSIFDOffset = 0;
    1538          29 :     if (nGPSTags)
    1539             :     {
    1540          11 :         WriteTag(pabyData, nBufferOff, GPSOFFSETTAG, TIFF_LONG, 1, 0);
    1541          11 :         nGPSIFDOffset = nBufferOff - 4;  // offset to patch
    1542             :     }
    1543             : 
    1544             :     // Offset of next IFD
    1545          29 :     GUInt32 nOffsetOfIFDAfterIFD0 = nBufferOff;
    1546          29 :     WriteLEUInt32(pabyData, nBufferOff, 0);  // offset to patch
    1547             : 
    1548             :     // Space for offline tag values (already written)
    1549          29 :     nBufferOff += nOfflineSizeMain;
    1550             : 
    1551          29 :     if (nEXIFTags)
    1552             :     {
    1553             :         // Patch value of EXIFOFFSETTAG
    1554             :         {
    1555          23 :             GUInt32 nTmp = nEXIFIFDOffset;
    1556          23 :             WriteLEUInt32(pabyData, nTmp, nBufferOff - nTIFFStartOff);
    1557             :         }
    1558             : 
    1559             :         // Number of entries of EXIF IFD
    1560          23 :         WriteLEUInt16(pabyData, nBufferOff, nEXIFTags);
    1561             : 
    1562          23 :         GUInt32 offsetIFDData =
    1563          23 :             nBufferOff - nTIFFStartOff + nEXIFTags * TAG_SIZE;
    1564          23 :         WriteTags(pabyData, nBufferOff, offsetIFDData, exifTags);
    1565             : 
    1566             :         // Space for offline tag values (already written)
    1567          23 :         nBufferOff += nOfflineSizeEXIF;
    1568             :     }
    1569             : 
    1570          29 :     if (nGPSTags)
    1571             :     {
    1572             :         // Patch value of GPSOFFSETTAG
    1573             :         {
    1574          11 :             GUInt32 nTmp = nGPSIFDOffset;
    1575          11 :             WriteLEUInt32(pabyData, nTmp, nBufferOff - nTIFFStartOff);
    1576             :         }
    1577             : 
    1578             :         // Number of entries of GPS IFD
    1579          11 :         WriteLEUInt16(pabyData, nBufferOff, nGPSTags);
    1580             : 
    1581          11 :         GUInt32 offsetIFDData =
    1582          11 :             nBufferOff - nTIFFStartOff + nGPSTags * TAG_SIZE;
    1583          11 :         WriteTags(pabyData, nBufferOff, offsetIFDData, gpsTags);
    1584             : 
    1585             :         // Space for offline tag values (already written)
    1586          11 :         nBufferOff += nOfflineSizeGPS;
    1587             :     }
    1588             : 
    1589          29 :     if (nIFD1Entries)
    1590             :     {
    1591             :         // Patch value of offset after next IFD
    1592             :         {
    1593           6 :             GUInt32 nTmp = nOffsetOfIFDAfterIFD0;
    1594           6 :             WriteLEUInt32(pabyData, nTmp, nBufferOff - nTIFFStartOff);
    1595             :         }
    1596             : 
    1597             :         // Number of entries of IFD1
    1598           6 :         WriteLEUInt16(pabyData, nBufferOff, nIFD1Entries);
    1599             : 
    1600           6 :         const GUInt16 JPEG_TIFF_IMAGEWIDTH = 0x100;
    1601           6 :         const GUInt16 JPEG_TIFF_IMAGEHEIGHT = 0x101;
    1602           6 :         const GUInt16 JPEG_TIFF_COMPRESSION = 0x103;
    1603           6 :         const GUInt16 JPEG_EXIF_JPEGIFOFSET = 0x201;
    1604           6 :         const GUInt16 JPEG_EXIF_JPEGIFBYTECOUNT = 0x202;
    1605             : 
    1606           6 :         WriteTag(pabyData, nBufferOff, JPEG_TIFF_IMAGEWIDTH, TIFF_LONG, 1,
    1607             :                  nThumbnailWidth);
    1608           6 :         WriteTag(pabyData, nBufferOff, JPEG_TIFF_IMAGEHEIGHT, TIFF_LONG, 1,
    1609             :                  nThumbnailHeight);
    1610           6 :         WriteTag(pabyData, nBufferOff, JPEG_TIFF_COMPRESSION, TIFF_SHORT, 1,
    1611             :                  6);  // JPEG compression
    1612           6 :         WriteTag(pabyData, nBufferOff, JPEG_EXIF_JPEGIFOFSET, TIFF_LONG, 1,
    1613           6 :                  nBufferSize - EXIF_HEADER_SIZE - nThumbnailSize);
    1614           6 :         WriteTag(pabyData, nBufferOff, JPEG_EXIF_JPEGIFBYTECOUNT, TIFF_LONG, 1,
    1615             :                  nThumbnailSize);
    1616             : 
    1617             :         // Offset of next IFD
    1618           6 :         WriteLEUInt32(pabyData, nBufferOff, 0);
    1619             :     }
    1620             : 
    1621          29 :     CPLAssert(nBufferOff + nThumbnailSize == nBufferSize);
    1622          29 :     if (pabyThumbnail != nullptr && nThumbnailSize)
    1623           6 :         memcpy(pabyData + nBufferOff, pabyThumbnail, nThumbnailSize);
    1624             : 
    1625          29 :     FreeTags(mainTags);
    1626          29 :     FreeTags(exifTags);
    1627          29 :     FreeTags(gpsTags);
    1628             : 
    1629          29 :     *pnOutBufferSize = nBufferSize;
    1630          29 :     return pabyData;
    1631             : }
    1632             : 
    1633             : #ifdef DUMP_EXIF_ITEMS
    1634             : 
    1635             : // To help generate the doc page
    1636             : // g++ -DDUMP_EXIF_ITEMS gcore/gdalexif.cpp -o dumpexif -Iport -Igcore -Iogr -L.
    1637             : // -lgdal
    1638             : 
    1639             : int main()
    1640             : {
    1641             :     printf("<table border=\"1\">\n");                         /* ok */
    1642             :     printf("<tr><th>Metadata item name</th><th>Hex code</th>" /* ok */
    1643             :            "<th>Type</th><th>Number of values</th><th>Optionality</th></tr>\n");
    1644             :     for (size_t i = 0; exiftags[i].name[0] != '\0'; i++)
    1645             :     {
    1646             :         if (exiftags[i].datatype == TIFF_NOTYPE)
    1647             :             continue;
    1648             :         printf(/* ok */ "<tr><td>%s</td><td>0x%04X</td><td>%s</td><td>%s</"
    1649             :                         "td><td>%s</"
    1650             :                         "td></tr>\n",
    1651             :                exiftags[i].name, exiftags[i].tag,
    1652             :                exiftags[i].datatype == TIFF_BYTE        ? "BYTE"
    1653             :                : exiftags[i].datatype == TIFF_ASCII     ? "ASCII"
    1654             :                : exiftags[i].datatype == TIFF_UNDEFINED ? "UNDEFINED"
    1655             :                : exiftags[i].datatype == TIFF_SHORT     ? "SHORT"
    1656             :                : exiftags[i].datatype == TIFF_LONG      ? "LONG"
    1657             :                : exiftags[i].datatype == TIFF_RATIONAL  ? "RATIONAL"
    1658             :                : exiftags[i].datatype == TIFF_SRATIONAL ? "SRATIONAL"
    1659             :                                                         : "?????",
    1660             :                exiftags[i].length ? CPLSPrintf("%d", exiftags[i].length)
    1661             :                                   : "variable",
    1662             :                exiftags[i].comprCond == COND_MANDATORY     ? "<b>Mandatory</b>"
    1663             :                : exiftags[i].comprCond == COND_OPTIONAL    ? "Optional"
    1664             :                : exiftags[i].comprCond == COND_RECOMMENDED ? "Recommended"
    1665             :                                                            : "?????");
    1666             :     }
    1667             :     printf("</table>\n"); /* ok */
    1668             : 
    1669             :     printf("<table border=\"1\">\n");                         /* ok */
    1670             :     printf("<tr><th>Metadata item name</th><th>Hex code</th>" /* ok */
    1671             :            "<th>Type</th><th>Number of values</th><th>Optionality</th></tr>\n");
    1672             :     for (size_t i = 0; gpstags[i].name[0] != '\0'; i++)
    1673             :     {
    1674             :         if (gpstags[i].datatype == TIFF_NOTYPE)
    1675             :             continue;
    1676             :         printf(/* ok */
    1677             :                "<tr><td>%s</td><td>0x%04X</td><td>%s</td><td>%s</td><td>%s</"
    1678             :                "td></tr>\n",
    1679             :                gpstags[i].name, gpstags[i].tag,
    1680             :                gpstags[i].datatype == TIFF_BYTE        ? "BYTE"
    1681             :                : gpstags[i].datatype == TIFF_ASCII     ? "ASCII"
    1682             :                : gpstags[i].datatype == TIFF_UNDEFINED ? "UNDEFINED"
    1683             :                : gpstags[i].datatype == TIFF_SHORT     ? "SHORT"
    1684             :                : gpstags[i].datatype == TIFF_LONG      ? "LONG"
    1685             :                : gpstags[i].datatype == TIFF_RATIONAL  ? "RATIONAL"
    1686             :                : gpstags[i].datatype == TIFF_SRATIONAL ? "SRATIONAL"
    1687             :                                                        : "?????",
    1688             :                gpstags[i].length ? CPLSPrintf("%d", gpstags[i].length)
    1689             :                                  : "variable",
    1690             :                gpstags[i].comprCond == COND_MANDATORY     ? "<b>Mandatory</b>"
    1691             :                : gpstags[i].comprCond == COND_OPTIONAL    ? "Optional"
    1692             :                : gpstags[i].comprCond == COND_RECOMMENDED ? "Recommended"
    1693             :                                                           : "?????");
    1694             :     }
    1695             :     printf("</table>\n"); /* ok */
    1696             : 
    1697             :     return 0;
    1698             : }
    1699             : 
    1700             : #endif

Generated by: LCOV version 1.14