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
|