/src/libraw/src/metadata/exif_gps.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- C++ -*- |
2 | | * Copyright 2019-2024 LibRaw LLC (info@libraw.org) |
3 | | * |
4 | | LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, |
5 | | dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. |
6 | | LibRaw do not use RESTRICTED code from dcraw.c |
7 | | |
8 | | LibRaw is free software; you can redistribute it and/or modify |
9 | | it under the terms of the one of two licenses as you choose: |
10 | | |
11 | | 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 |
12 | | (See file LICENSE.LGPL provided in LibRaw distribution archive for details). |
13 | | |
14 | | 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 |
15 | | (See file LICENSE.CDDL provided in LibRaw distribution archive for details). |
16 | | |
17 | | */ |
18 | | |
19 | | #include "../../internal/dcraw_defs.h" |
20 | | #include "../../internal/libraw_cameraids.h" |
21 | | |
22 | | void LibRaw::parse_exif_interop(INT64 base) |
23 | 1.50k | { |
24 | 1.50k | unsigned entries, tag, type, len; |
25 | 1.50k | INT64 save; |
26 | 1.50k | char value[4] = { 0,0,0,0 }; |
27 | 1.50k | entries = get2(); |
28 | 1.50k | INT64 fsize = ifp->size(); |
29 | 196k | while (entries--) |
30 | 194k | { |
31 | 194k | tiff_get(base, &tag, &type, &len, &save); |
32 | | |
33 | 194k | INT64 savepos = ftell(ifp); |
34 | 194k | if (len > 8 && savepos + len > fsize * 2) |
35 | 154k | { |
36 | 154k | fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! |
37 | 154k | continue; |
38 | 154k | } |
39 | 40.7k | if (callbacks.exif_cb) |
40 | 0 | { |
41 | 0 | callbacks.exif_cb(callbacks.exifparser_data, tag | 0x40000, type, len, order, ifp, base); |
42 | 0 | fseek(ifp, savepos, SEEK_SET); |
43 | 0 | } |
44 | | |
45 | 40.7k | switch (tag) |
46 | 40.7k | { |
47 | 2.39k | case 0x0001: // InteropIndex |
48 | 2.39k | fread(value, 1, MIN(4, len), ifp); |
49 | 2.39k | if (strncmp(value, "R98", 3) == 0 && |
50 | | // Canon bug, when [Canon].ColorSpace = AdobeRGB, |
51 | | // but [ExifIFD].ColorSpace = Uncalibrated and |
52 | | // [InteropIFD].InteropIndex = "R98" |
53 | 2.39k | imgdata.color.ExifColorSpace == LIBRAW_COLORSPACE_Unknown) |
54 | 10 | imgdata.color.ExifColorSpace = LIBRAW_COLORSPACE_sRGB; |
55 | 2.38k | else if (strncmp(value, "R03", 3) == 0) |
56 | 116 | imgdata.color.ExifColorSpace = LIBRAW_COLORSPACE_AdobeRGB; |
57 | 2.39k | break; |
58 | 40.7k | } |
59 | 40.6k | fseek(ifp, save, SEEK_SET); |
60 | 40.6k | } |
61 | 1.50k | } |
62 | | |
63 | | void LibRaw::parse_exif(INT64 base) |
64 | 167k | { |
65 | 167k | unsigned entries, tag, type, len, c; |
66 | 167k | double expo, ape; |
67 | 167k | INT64 save; |
68 | | |
69 | 167k | unsigned kodak = !strncmp(make, "EASTMAN", 7) && tiff_nifds < 3; |
70 | | |
71 | 167k | if (!libraw_internal_data.unpacker_data.exif_subdir_offset) |
72 | 18.0k | { |
73 | 18.0k | libraw_internal_data.unpacker_data.exif_offset = base; |
74 | 18.0k | libraw_internal_data.unpacker_data.exif_subdir_offset = ftell(ifp); |
75 | 18.0k | } |
76 | | |
77 | 167k | entries = get2(); |
78 | 167k | if (!strncmp(make, "Hasselblad", 10) && (tiff_nifds > 3) && (entries > 512)) |
79 | 860 | return; |
80 | 166k | INT64 fsize = ifp->size(); |
81 | 20.7M | while (entries--) |
82 | 20.5M | { |
83 | 20.5M | tiff_get(base, &tag, &type, &len, &save); |
84 | | |
85 | 20.5M | INT64 savepos = ftell(ifp); |
86 | 20.5M | if (len > 8 && savepos + INT64(len) > fsize * 2LL) |
87 | 16.4M | { |
88 | 16.4M | fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! |
89 | 16.4M | continue; |
90 | 16.4M | } |
91 | 4.14M | if (callbacks.exif_cb) |
92 | 0 | { |
93 | 0 | callbacks.exif_cb(callbacks.exifparser_data, tag, type, len, order, ifp, |
94 | 0 | base); |
95 | 0 | fseek(ifp, savepos, SEEK_SET); |
96 | 0 | } |
97 | | |
98 | 4.14M | switch (tag) |
99 | 4.14M | { |
100 | 1.50k | case 0xA005: // Interoperability IFD |
101 | 1.50k | fseek(ifp, get4() + base, SEEK_SET); |
102 | 1.50k | parse_exif_interop(base); |
103 | 1.50k | break; |
104 | 1.13k | case 0xA001: // ExifIFD.ColorSpace |
105 | 1.13k | c = get2(); |
106 | 1.13k | if (c == 1 && imgdata.color.ExifColorSpace == LIBRAW_COLORSPACE_Unknown) |
107 | 38 | imgdata.color.ExifColorSpace = LIBRAW_COLORSPACE_sRGB; |
108 | 1.09k | else if (c == 2) |
109 | 165 | imgdata.color.ExifColorSpace = LIBRAW_COLORSPACE_AdobeRGB; |
110 | 1.13k | break; |
111 | 2.38k | case 0x9400: |
112 | 2.38k | imCommon.exifAmbientTemperature = getrealf(type); |
113 | 2.38k | if ((imCommon.CameraTemperature > -273.15f) && |
114 | 2.38k | ((OlyID == OlyID_TG_5) || |
115 | 599 | (OlyID == OlyID_TG_6)) |
116 | 2.38k | ) |
117 | 0 | imCommon.CameraTemperature += imCommon.exifAmbientTemperature; |
118 | 2.38k | break; |
119 | 615 | case 0x9401: |
120 | 615 | imCommon.exifHumidity = getrealf(type); |
121 | 615 | break; |
122 | 1.78k | case 0x9402: |
123 | 1.78k | imCommon.exifPressure = getrealf(type); |
124 | 1.78k | break; |
125 | 480 | case 0x9403: |
126 | 480 | imCommon.exifWaterDepth = getrealf(type); |
127 | 480 | break; |
128 | 339 | case 0x9404: |
129 | 339 | imCommon.exifAcceleration = getrealf(type); |
130 | 339 | break; |
131 | 940 | case 0x9405: |
132 | 940 | imCommon.exifCameraElevationAngle = getrealf(type); |
133 | 940 | break; |
134 | | |
135 | 407 | case 0xa405: // FocalLengthIn35mmFormat |
136 | 407 | imgdata.lens.FocalLengthIn35mmFormat = get2(); |
137 | 407 | break; |
138 | 3.05k | case 0xa431: // BodySerialNumber |
139 | 3.05k | stmread(imgdata.shootinginfo.BodySerial, len, ifp); |
140 | 3.05k | break; |
141 | 1.18k | case 0xa432: // LensInfo, 42034dec, Lens Specification per EXIF standard |
142 | 1.18k | imgdata.lens.MinFocal = getrealf(type); |
143 | 1.18k | imgdata.lens.MaxFocal = getrealf(type); |
144 | 1.18k | imgdata.lens.MaxAp4MinFocal = getrealf(type); |
145 | 1.18k | imgdata.lens.MaxAp4MaxFocal = getrealf(type); |
146 | 1.18k | break; |
147 | 1.90k | case 0xa435: // LensSerialNumber |
148 | 1.90k | stmread(imgdata.lens.LensSerial, len, ifp); |
149 | 1.90k | if (!strncmp(imgdata.lens.LensSerial, "----", 4)) |
150 | 461 | imgdata.lens.LensSerial[0] = '\0'; |
151 | 1.90k | break; |
152 | 627 | case 0xa420: /* 42016, ImageUniqueID */ |
153 | 627 | stmread(imgdata.color.ImageUniqueID, len, ifp); |
154 | 627 | break; |
155 | 186 | case 0xc65d: /* 50781, RawDataUniqueID */ |
156 | 186 | imgdata.color.RawDataUniqueID[16] = 0; |
157 | 186 | fread(imgdata.color.RawDataUniqueID, 1, 16, ifp); |
158 | 186 | break; |
159 | 591 | case 0xc630: // DNG LensInfo, Lens Specification per EXIF standard |
160 | 591 | imgdata.lens.dng.MinFocal = getrealf(type); |
161 | 591 | imgdata.lens.dng.MaxFocal = getrealf(type); |
162 | 591 | imgdata.lens.dng.MaxAp4MinFocal = getrealf(type); |
163 | 591 | imgdata.lens.dng.MaxAp4MaxFocal = getrealf(type); |
164 | 591 | break; |
165 | 462 | case 0xc68b: /* 50827, OriginalRawFileName */ |
166 | 462 | stmread(imgdata.color.OriginalRawFileName, len, ifp); |
167 | 462 | break; |
168 | 7.24k | case 0xa433: // LensMake |
169 | 7.24k | stmread(imgdata.lens.LensMake, len, ifp); |
170 | 7.24k | break; |
171 | 1.67k | case 0xa434: // LensModel |
172 | 1.67k | stmread(imgdata.lens.Lens, len, ifp); |
173 | 1.67k | if (!strncmp(imgdata.lens.Lens, "----", 4)) |
174 | 288 | imgdata.lens.Lens[0] = '\0'; |
175 | 1.67k | break; |
176 | 7.42k | case 0x9205: |
177 | 7.42k | imgdata.lens.EXIF_MaxAp = libraw_powf64l(2.0f, getrealf(type) / 2.0f); |
178 | 7.42k | break; |
179 | 790 | case 0x829a: // 33434 |
180 | 790 | shutter = getrealf(type); |
181 | 790 | if (tiff_nifds > 0 && tiff_nifds <= LIBRAW_IFD_MAXCOUNT) |
182 | 790 | tiff_ifd[tiff_nifds - 1].t_shutter = shutter; |
183 | 790 | break; |
184 | 841 | case 0x829d: // 33437, FNumber |
185 | 841 | aperture = getrealf(type); |
186 | 841 | break; |
187 | 2.09k | case 0x8827: // 34855 |
188 | 2.09k | iso_speed = get2(); |
189 | 2.09k | break; |
190 | 666 | case 0x8831: // 34865 |
191 | 666 | if (iso_speed == 0xffff && !strncasecmp(make, "FUJI", 4)) |
192 | 74 | iso_speed = getrealf(type); |
193 | 666 | break; |
194 | 834 | case 0x8832: // 34866 |
195 | 834 | if (iso_speed == 0xffff && |
196 | 834 | (!strncasecmp(make, "SONY", 4) || !strncasecmp(make, "CANON", 5))) |
197 | 175 | iso_speed = getrealf(type); |
198 | 834 | break; |
199 | 2.14k | case 0x9003: // 36867 |
200 | 3.29k | case 0x9004: // 36868 |
201 | 3.29k | get_timestamp(0); |
202 | 3.29k | break; |
203 | 2.32k | case 0x9201: // 37377 |
204 | 2.32k | if ((expo = -getreal(type)) < 128 && shutter == 0.) |
205 | 1.29k | { |
206 | 1.29k | shutter = libraw_powf64l(2.0f, float(expo)); |
207 | 1.29k | if (tiff_nifds > 0 && tiff_nifds <= LIBRAW_IFD_MAXCOUNT) |
208 | 1.29k | tiff_ifd[tiff_nifds - 1].t_shutter = shutter; |
209 | 1.29k | } |
210 | 2.32k | break; |
211 | 2.61k | case 0x9202: // 37378 ApertureValue |
212 | 2.61k | if ((fabs(ape = getreal(type)) < 256.0) && (!aperture)) |
213 | 979 | aperture = libraw_powf64l(2.0f, float(ape / 2.0)); |
214 | 2.61k | break; |
215 | 744 | case 0x9209: // 37385 |
216 | 744 | flash_used = getrealf(type); |
217 | 744 | break; |
218 | 968 | case 0x920a: // 37386 |
219 | 968 | focal_len = getrealf(type); |
220 | 968 | break; |
221 | 569k | case 0x927c: // 37500 |
222 | 569k | #ifndef USE_6BY9RPI |
223 | 569k | if (((make[0] == '\0') && !strncmp(model, "ov5647", 6)) || |
224 | 569k | (!strncmp(make, "RaspberryPi", 11) && |
225 | 569k | (!strncmp(model, "RP_OV5647", 9) || |
226 | 2.17k | !strncmp(model, "RP_imx219", 9)))) |
227 | | #else |
228 | | if (((make[0] == '\0') && !strncmp(model, "ov5647", 6)) || |
229 | | (!strncmp(make, "RaspberryPi", 11) && |
230 | | (!strncmp(model, "RP_", 3) || !strncmp(model,"imx477",6)))) |
231 | | #endif |
232 | 1.70k | { |
233 | 1.70k | char mn_text[512]; |
234 | 1.70k | char *pos; |
235 | 1.70k | char ccms[512]; |
236 | 1.70k | ushort l; |
237 | 1.70k | float num; |
238 | | |
239 | 1.70k | fgets(mn_text, MIN(len, 511), ifp); |
240 | 1.70k | mn_text[511] = 0; |
241 | | |
242 | 1.70k | pos = strstr(mn_text, "ev="); |
243 | 1.70k | if (pos) |
244 | 32 | imCommon.ExposureCalibrationShift = float(atof(pos + 3)); |
245 | | |
246 | 1.70k | pos = strstr(mn_text, "gain_r="); |
247 | 1.70k | if (pos) |
248 | 100 | cam_mul[0] = float(atof(pos + 7)); |
249 | 1.70k | pos = strstr(mn_text, "gain_b="); |
250 | 1.70k | if (pos) |
251 | 30 | cam_mul[2] = float(atof(pos + 7)); |
252 | 1.70k | if ((cam_mul[0] > 0.001f) && (cam_mul[2] > 0.001f)) |
253 | 83 | cam_mul[1] = cam_mul[3] = 1.0f; |
254 | 1.61k | else |
255 | 1.61k | cam_mul[0] = cam_mul[2] = 0.0f; |
256 | | |
257 | 1.70k | pos = strstr(mn_text, "ccm="); |
258 | 1.70k | if (pos) |
259 | 131 | { |
260 | 131 | pos += 4; |
261 | 131 | char *pos2 = strstr(pos, " "); |
262 | 131 | if (pos2) |
263 | 90 | { |
264 | 90 | l = LIM(ushort(pos2 - pos), 0, 511); |
265 | 90 | memcpy(ccms, pos, l); |
266 | 90 | ccms[l] = '\0'; |
267 | | #ifdef LIBRAW_WIN32_CALLS |
268 | | // Win32 strtok is already thread-safe |
269 | | pos = strtok(ccms, ","); |
270 | | #else |
271 | 90 | char *last = 0; |
272 | 90 | pos = strtok_r(ccms, ",", &last); |
273 | 90 | #endif |
274 | 90 | if (pos) |
275 | 86 | { |
276 | 262 | for (l = 0; l < 3; l++) // skip last row |
277 | 229 | { |
278 | 229 | num = 0.0; |
279 | 785 | for (c = 0; c < 3; c++) |
280 | 609 | { |
281 | 609 | cmatrix[l][c] = (float)atoi(pos); |
282 | 609 | num += cmatrix[c][l]; |
283 | | #ifdef LIBRAW_WIN32_CALLS |
284 | | pos = strtok(NULL, ","); |
285 | | #else |
286 | 609 | pos = strtok_r(NULL, ",", &last); |
287 | 609 | #endif |
288 | 609 | if (!pos) |
289 | 53 | goto end; // broken |
290 | 609 | } |
291 | 176 | if (num > 0.01) |
292 | 201 | FORC3 cmatrix[l][c] = cmatrix[l][c] / num; |
293 | 176 | } |
294 | 86 | } |
295 | 90 | } |
296 | 131 | } |
297 | 1.70k | end:; |
298 | 1.70k | } |
299 | 568k | else if (!strncmp(make, "SONY", 4) && |
300 | 568k | (!strncmp(model, "DSC-V3", 6) || !strncmp(model, "DSC-F828", 8))) |
301 | 1.04k | { |
302 | 1.04k | parseSonySRF(len); |
303 | 1.04k | break; |
304 | 1.04k | } |
305 | 567k | else if ((len == 1) && !strncmp(make, "NIKON", 5)) |
306 | 18.2k | { |
307 | 18.2k | c = get4(); |
308 | 18.2k | if (c) |
309 | 16.7k | fseek(ifp, c, SEEK_SET); |
310 | 18.2k | is_NikonTransfer = 1; |
311 | 18.2k | } |
312 | 568k | parse_makernote(base, 0); |
313 | 568k | break; |
314 | 1.23k | case 0xa002: // 40962 |
315 | 1.23k | if (kodak) |
316 | 32 | raw_width = get4(); |
317 | 1.23k | break; |
318 | 1.12k | case 0xa003: // 40963 |
319 | 1.12k | if (kodak) |
320 | 48 | raw_height = get4(); |
321 | 1.12k | break; |
322 | 341 | case 0xa302: // 41730 |
323 | 341 | if (get4() == 0x20002) |
324 | 435 | for (exif_cfa = c = 0; c < 8; c += 2) |
325 | 348 | exif_cfa |= fgetc(ifp) * 0x01010101U << c; |
326 | 4.14M | } |
327 | 4.13M | fseek(ifp, save, SEEK_SET); |
328 | 4.13M | } |
329 | 166k | } |
330 | | |
331 | | void LibRaw::parse_gps_libraw(INT64 base) |
332 | 4.83k | { |
333 | 4.83k | unsigned entries, tag, type, len, c; |
334 | 4.83k | INT64 save; |
335 | | |
336 | 4.83k | entries = get2(); |
337 | 4.83k | if (entries > 40) |
338 | 2.18k | return; |
339 | 2.64k | if (entries > 0) |
340 | 2.44k | imgdata.other.parsed_gps.gpsparsed = 1; |
341 | 2.64k | INT64 fsize = ifp->size(); |
342 | 67.5k | while (entries--) |
343 | 64.9k | { |
344 | 64.9k | tiff_get(base, &tag, &type, &len, &save); |
345 | 64.9k | if (len > 1024) |
346 | 41.7k | { |
347 | 41.7k | fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! |
348 | 41.7k | continue; // no GPS tags are 1k or larger |
349 | 41.7k | } |
350 | 23.2k | INT64 savepos = ftell(ifp); |
351 | 23.2k | if (len > 8 && savepos + len > fsize * 2) |
352 | 2.69k | { |
353 | 2.69k | fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! |
354 | 2.69k | continue; |
355 | 2.69k | } |
356 | | |
357 | 20.5k | if (callbacks.exif_cb) |
358 | 0 | { |
359 | 0 | callbacks.exif_cb(callbacks.exifparser_data, tag | 0x50000, type, len, order, ifp, base); |
360 | 0 | fseek(ifp, savepos, SEEK_SET); |
361 | 0 | } |
362 | | |
363 | 20.5k | switch (tag) |
364 | 20.5k | { |
365 | 395 | case 0x0001: |
366 | 395 | imgdata.other.parsed_gps.latref = getc(ifp); |
367 | 395 | break; |
368 | 717 | case 0x0003: |
369 | 717 | imgdata.other.parsed_gps.longref = getc(ifp); |
370 | 717 | break; |
371 | 359 | case 0x0005: |
372 | 359 | imgdata.other.parsed_gps.altref = getc(ifp); |
373 | 359 | break; |
374 | 1.47k | case 0x0002: |
375 | 1.47k | if (len == 3) |
376 | 2.43k | FORC(3) imgdata.other.parsed_gps.latitude[c] = getrealf(type); |
377 | 1.47k | break; |
378 | 963 | case 0x0004: |
379 | 963 | if (len == 3) |
380 | 1.27k | FORC(3) imgdata.other.parsed_gps.longitude[c] = getrealf(type); |
381 | 963 | break; |
382 | 715 | case 0x0007: |
383 | 715 | if (len == 3) |
384 | 1.33k | FORC(3) imgdata.other.parsed_gps.gpstimestamp[c] = getrealf(type); |
385 | 715 | break; |
386 | 558 | case 0x0006: |
387 | 558 | imgdata.other.parsed_gps.altitude = getrealf(type); |
388 | 558 | break; |
389 | 132 | case 0x0009: |
390 | 132 | imgdata.other.parsed_gps.gpsstatus = getc(ifp); |
391 | 132 | break; |
392 | 20.5k | } |
393 | 20.5k | fseek(ifp, save, SEEK_SET); |
394 | 20.5k | } |
395 | 2.64k | } |
396 | | |
397 | | void LibRaw::parse_gps(INT64 base) |
398 | 4.86k | { |
399 | 4.86k | unsigned entries, tag, type, len, c; |
400 | 4.86k | INT64 save; |
401 | | |
402 | 4.86k | entries = get2(); |
403 | 4.86k | if (entries > 40) |
404 | 2.18k | return; |
405 | 67.9k | while (entries--) |
406 | 65.2k | { |
407 | 65.2k | tiff_get(base, &tag, &type, &len, &save); |
408 | 65.2k | if (len > 1024) |
409 | 41.8k | { |
410 | 41.8k | fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! |
411 | 41.8k | continue; // no GPS tags are 1k or larger |
412 | 41.8k | } |
413 | 23.3k | switch (tag) |
414 | 23.3k | { |
415 | 483 | case 0x0001: |
416 | 1.28k | case 0x0003: |
417 | 1.65k | case 0x0005: |
418 | 1.65k | gpsdata[29 + tag / 2] = getc(ifp); |
419 | 1.65k | break; |
420 | 1.50k | case 0x0002: |
421 | 2.48k | case 0x0004: |
422 | 3.25k | case 0x0007: |
423 | 19.5k | FORC(6) gpsdata[tag / 3 * 6 + c] = get4(); |
424 | 3.25k | break; |
425 | 562 | case 0x0006: |
426 | 1.12k | FORC(2) gpsdata[18 + c] = get4(); |
427 | 562 | break; |
428 | 257 | case 0x0012: // 18 |
429 | 516 | case 0x001d: // 29 |
430 | 516 | fgets((char *)(gpsdata + 14 + tag / 3), MIN(len, 12), ifp); |
431 | 23.3k | } |
432 | 23.3k | fseek(ifp, save, SEEK_SET); |
433 | 23.3k | } |
434 | 2.68k | } |