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