Coverage Report

Created: 2026-07-25 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/LibRaw/src/metadata/exif_gps.cpp
Line
Count
Source
1
/* -*- C++ -*-
2
 * Copyright 2019-2025 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
2.74k
{
24
2.74k
  unsigned entries, tag, type, len;
25
2.74k
  INT64 save;
26
2.74k
  char value[4] = { 0,0,0,0 };
27
2.74k
  entries = get2();
28
2.74k
  INT64 fsize = ifp->size();
29
4.02M
  while (entries--)
30
4.01M
  {
31
4.01M
    tiff_get(base, &tag, &type, &len, &save);
32
33
4.01M
    INT64 savepos = ftell(ifp);
34
4.01M
    if (len > 8 && savepos + len > fsize * 2)
35
2.87M
    {
36
2.87M
      fseek(ifp, save, SEEK_SET); // Recover tiff-read position!!
37
2.87M
      continue;
38
2.87M
    }
39
1.14M
        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
1.14M
    switch (tag)
46
1.14M
    {
47
68.7k
    case 0x0001: // InteropIndex
48
68.7k
      fread(value, 1, MIN(4, len), ifp);
49
68.7k
      if (strncmp(value, "R98", 3) == 0 &&
50
        // Canon bug, when [Canon].ColorSpace = AdobeRGB,
51
        // but [ExifIFD].ColorSpace = Uncalibrated and
52
        // [InteropIFD].InteropIndex = "R98"
53
540
        imgdata.color.ExifColorSpace == LIBRAW_COLORSPACE_Unknown)
54
26
        imgdata.color.ExifColorSpace = LIBRAW_COLORSPACE_sRGB;
55
68.6k
      else if (strncmp(value, "R03", 3) == 0)
56
254
        imgdata.color.ExifColorSpace = LIBRAW_COLORSPACE_AdobeRGB;
57
68.7k
      break;
58
1.14M
    }
59
1.14M
    fseek(ifp, save, SEEK_SET);
60
1.14M
  }
61
2.74k
}
62
63
void LibRaw::parse_exif(INT64 base)
64
147k
{
65
147k
  unsigned entries, tag, type, len, c;
66
147k
  double expo, ape;
67
147k
  INT64 save;
68
69
147k
  unsigned kodak = !strncmp(make, "EASTMAN", 7) && tiff_nifds < 3;
70
71
147k
  if (!libraw_internal_data.unpacker_data.exif_subdir_offset)
72
16.9k
  {
73
16.9k
    libraw_internal_data.unpacker_data.exif_offset = base;
74
16.9k
    libraw_internal_data.unpacker_data.exif_subdir_offset = ftell(ifp);
75
16.9k
  }
76
77
147k
  entries = get2();
78
147k
  if (!strncmp(make, "Hasselblad", 10) && (tiff_nifds > 3) && (entries > 512))
79
486
    return;
80
147k
  INT64 fsize = ifp->size();
81
39.5M
  while (entries--)
82
39.3M
  {
83
39.3M
    tiff_get(base, &tag, &type, &len, &save);
84
85
39.3M
    INT64 savepos = ftell(ifp);
86
39.3M
    if (len > 8 && savepos + INT64(len) > fsize * 2LL)
87
28.9M
    {
88
28.9M
      fseek(ifp, save, SEEK_SET); // Recover tiff-read position!!
89
28.9M
      continue;
90
28.9M
    }
91
10.4M
    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
10.4M
    switch (tag)
99
10.4M
    {
100
2.74k
  case 0xA005: // Interoperability IFD
101
2.74k
    fseek(ifp, get4() + base, SEEK_SET);
102
2.74k
    parse_exif_interop(base);
103
2.74k
    break;
104
12.8k
  case 0xA001: // ExifIFD.ColorSpace
105
12.8k
    c = get2();
106
12.8k
    if (c == 1 && imgdata.color.ExifColorSpace == LIBRAW_COLORSPACE_Unknown)
107
932
      imgdata.color.ExifColorSpace = LIBRAW_COLORSPACE_sRGB;
108
11.9k
    else if (c == 2)
109
196
      imgdata.color.ExifColorSpace = LIBRAW_COLORSPACE_AdobeRGB;
110
12.8k
    break;
111
4.67k
    case 0x9400:
112
4.67k
      imCommon.exifAmbientTemperature = getrealf(type);
113
4.67k
      if ((imCommon.CameraTemperature > -273.15f) &&
114
1.64k
          ((OlyID == OlyID_TG_5) ||
115
1.64k
           (OlyID == OlyID_TG_6))
116
4.67k
      )
117
0
        imCommon.CameraTemperature += imCommon.exifAmbientTemperature;
118
4.67k
      break;
119
1.45k
    case 0x9401:
120
1.45k
      imCommon.exifHumidity = getrealf(type);
121
1.45k
      break;
122
2.03k
    case 0x9402:
123
2.03k
      imCommon.exifPressure = getrealf(type);
124
2.03k
      break;
125
2.39k
    case 0x9403:
126
2.39k
      imCommon.exifWaterDepth = getrealf(type);
127
2.39k
      break;
128
1.27k
    case 0x9404:
129
1.27k
      imCommon.exifAcceleration = getrealf(type);
130
1.27k
      break;
131
1.25k
    case 0x9405:
132
1.25k
      imCommon.exifCameraElevationAngle = getrealf(type);
133
1.25k
      break;
134
135
342
    case 0xa405: // FocalLengthIn35mmFormat
136
342
      imgdata.lens.FocalLengthIn35mmFormat = get2();
137
342
      break;
138
480
    case 0xa431: // BodySerialNumber
139
480
      stmread(imgdata.shootinginfo.BodySerial, len, ifp);
140
480
      break;
141
420
    case 0xa432: // LensInfo, 42034dec, Lens Specification per EXIF standard
142
420
      imgdata.lens.MinFocal = getrealf(type);
143
420
      imgdata.lens.MaxFocal = getrealf(type);
144
420
      imgdata.lens.MaxAp4MinFocal = getrealf(type);
145
420
      imgdata.lens.MaxAp4MaxFocal = getrealf(type);
146
420
      break;
147
1.59k
    case 0xa435: // LensSerialNumber
148
1.59k
      stmread(imgdata.lens.LensSerial, len, ifp);
149
1.59k
      if (!strncmp(imgdata.lens.LensSerial, "----", 4))
150
238
        imgdata.lens.LensSerial[0] = '\0';
151
1.59k
      break;
152
990
    case 0xa420: /* 42016, ImageUniqueID */
153
990
      stmread(imgdata.color.ImageUniqueID, len, ifp);
154
990
      break;
155
354
    case 0xc65d: /* 50781, RawDataUniqueID */
156
354
      imgdata.color.RawDataUniqueID[16] = 0;
157
354
      fread(imgdata.color.RawDataUniqueID, 1, 16, ifp);
158
354
      break;
159
750
    case 0xc630: // DNG LensInfo, Lens Specification per EXIF standard
160
750
      imgdata.lens.dng.MinFocal = getrealf(type);
161
750
      imgdata.lens.dng.MaxFocal = getrealf(type);
162
750
      imgdata.lens.dng.MaxAp4MinFocal = getrealf(type);
163
750
      imgdata.lens.dng.MaxAp4MaxFocal = getrealf(type);
164
750
      break;
165
854
    case 0xc68b: /* 50827, OriginalRawFileName */
166
854
      stmread(imgdata.color.OriginalRawFileName, len, ifp);
167
854
      break;
168
1.41k
    case 0xa433: // LensMake
169
1.41k
      stmread(imgdata.lens.LensMake, len, ifp);
170
1.41k
      break;
171
1.79k
    case 0xa434: // LensModel
172
1.79k
      stmread(imgdata.lens.Lens, len, ifp);
173
1.79k
      if (!strncmp(imgdata.lens.Lens, "----", 4))
174
1.21k
        imgdata.lens.Lens[0] = '\0';
175
1.79k
      break;
176
4.56k
    case 0x9205:
177
4.56k
      imgdata.lens.EXIF_MaxAp = libraw_powf64l(2.0f, getrealf(type) / 2.0f);
178
4.56k
      break;
179
7.14k
    case 0x829a: // 33434
180
7.14k
      shutter = getrealf(type);
181
7.14k
      if (tiff_nifds > 0 && tiff_nifds <= LIBRAW_IFD_MAXCOUNT)
182
7.14k
          tiff_ifd[tiff_nifds - 1].t_shutter = shutter;
183
7.14k
      break;
184
6.92k
    case 0x829d: // 33437, FNumber
185
6.92k
      aperture = getrealf(type);
186
6.92k
      break;
187
5.47k
    case 0x8827: // 34855
188
5.47k
      iso_speed = get2();
189
5.47k
      break;
190
412
    case 0x8831: // 34865
191
412
      if (iso_speed == 0xffff && !strncasecmp(make, "FUJI", 4))
192
36
        iso_speed = getrealf(type);
193
412
      break;
194
518
    case 0x8832: // 34866
195
518
      if (iso_speed == 0xffff &&
196
180
          (!strncasecmp(make, "SONY", 4) || !strncasecmp(make, "CANON", 5)))
197
108
        iso_speed = getrealf(type);
198
518
      break;
199
7.85k
    case 0x9003: // 36867
200
13.0k
    case 0x9004: // 36868
201
13.0k
      get_timestamp(0);
202
13.0k
      break;
203
4.76k
    case 0x9201: // 37377
204
4.76k
       if ((expo = -getreal(type)) < 128 && shutter == 0.)
205
1.78k
       {
206
1.78k
            shutter = libraw_powf64l(2.0f, float(expo));
207
1.78k
            if (tiff_nifds > 0 && tiff_nifds <= LIBRAW_IFD_MAXCOUNT)
208
1.78k
              tiff_ifd[tiff_nifds - 1].t_shutter = shutter;
209
1.78k
       }
210
4.76k
      break;
211
4.99k
    case 0x9202: // 37378 ApertureValue
212
4.99k
      if ((fabs(ape = getreal(type)) < 256.0) && (!aperture))
213
1.25k
        aperture = libraw_powf64l(2.0f, float(ape / 2.0));
214
4.99k
      break;
215
14.5k
    case 0x9209: // 37385
216
14.5k
      flash_used = getrealf(type);
217
14.5k
      break;
218
15.9k
    case 0x920a: // 37386
219
15.9k
      focal_len = getrealf(type);
220
15.9k
      break;
221
490k
    case 0x927c: // 37500
222
490k
#ifndef USE_6BY9RPI
223
490k
      if (((make[0] == '\0') && !strncmp(model, "ov5647", 6)) ||
224
490k
          (!strncmp(make, "RaspberryPi", 11) &&
225
2.06k
           (!strncmp(model, "RP_OV5647", 9) ||
226
504
            !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
2.14k
      {
233
2.14k
        char mn_text[512];
234
2.14k
        char *pos;
235
2.14k
        char ccms[512];
236
2.14k
        ushort l;
237
2.14k
        float num;
238
239
2.14k
    memset(mn_text, 0, sizeof(mn_text));
240
2.14k
        fgets(mn_text, MIN(len, 511), ifp);
241
2.14k
        mn_text[511] = 0;
242
243
2.14k
        pos = strstr(mn_text, "ev=");
244
2.14k
        if (pos)
245
72
          imCommon.ExposureCalibrationShift = float(atof(pos + 3));
246
247
2.14k
        pos = strstr(mn_text, "gain_r=");
248
2.14k
        if (pos)
249
180
          cam_mul[0] = float(atof(pos + 7));
250
2.14k
        pos = strstr(mn_text, "gain_b=");
251
2.14k
        if (pos)
252
74
          cam_mul[2] = float(atof(pos + 7));
253
2.14k
        if ((cam_mul[0] > 0.001f) && (cam_mul[2] > 0.001f))
254
372
          cam_mul[1] = cam_mul[3] = 1.0f;
255
1.77k
        else
256
1.77k
          cam_mul[0] = cam_mul[2] = 0.0f;
257
258
2.14k
        pos = strstr(mn_text, "ccm=");
259
2.14k
        if (pos)
260
924
        {
261
924
          pos += 4;
262
924
          char *pos2 = strstr(pos, " ");
263
924
          if (pos2)
264
782
          {
265
782
            l = LIM(ushort(pos2 - pos), 0, 511);
266
782
            memcpy(ccms, pos, l);
267
782
            ccms[l] = '\0';
268
#ifdef LIBRAW_WIN32_CALLS
269
            // Win32 strtok is already thread-safe
270
            pos = strtok(ccms, ",");
271
#else
272
782
            char *last = 0;
273
782
            pos = strtok_r(ccms, ",", &last);
274
782
#endif
275
782
            if (pos)
276
742
            {
277
1.68k
              for (l = 0; l < 3; l++) // skip last row
278
1.61k
              {
279
1.61k
                num = 0.0;
280
4.99k
                for (c = 0; c < 3; c++)
281
4.05k
                {
282
4.05k
                  cmatrix[l][c] = (float)atoi(pos);
283
4.05k
                  num += cmatrix[c][l];
284
#ifdef LIBRAW_WIN32_CALLS
285
                  pos = strtok(NULL, ",");
286
#else
287
4.05k
                  pos = strtok_r(NULL, ",", &last);
288
4.05k
#endif
289
4.05k
                  if (!pos)
290
668
                    goto end; // broken
291
4.05k
                }
292
942
                if (num > 0.01)
293
1.20k
                    FORC3 cmatrix[l][c] = cmatrix[l][c] / num;
294
942
              }
295
742
            }
296
782
          }
297
924
        }
298
2.14k
      end:;
299
2.14k
      }
300
488k
      else if (!strncmp(make, "SONY", 4) &&
301
86.1k
               (!strncmp(model, "DSC-V3", 6) || !strncmp(model, "DSC-F828", 8)))
302
12.7k
      {
303
12.7k
        parseSonySRF(len);
304
12.7k
        break;
305
12.7k
      }
306
475k
      else if ((len == 1) && !strncmp(make, "NIKON", 5))
307
4.16k
      {
308
4.16k
        c = get4();
309
4.16k
        if (c)
310
3.86k
          fseek(ifp, c, SEEK_SET);
311
4.16k
        is_NikonTransfer = 1;
312
4.16k
      }
313
478k
      parse_makernote(base, 0);
314
478k
      break;
315
3.53k
    case 0xa002: // 40962
316
3.53k
      if (kodak)
317
72
        raw_width = get4();
318
3.53k
      break;
319
3.99k
    case 0xa003: // 40963
320
3.99k
      if (kodak)
321
160
        raw_height = get4();
322
3.99k
      break;
323
1.53k
    case 0xa302: // 41730
324
1.53k
      if (get4() == 0x20002)
325
1.17k
        for (exif_cfa = c = 0; c < 8; c += 2)
326
936
          exif_cfa |= fgetc(ifp) * 0x01010101U << c;
327
10.4M
    }
328
10.4M
    fseek(ifp, save, SEEK_SET);
329
10.4M
  }
330
147k
}
331
332
void LibRaw::parse_gps_libraw(INT64 base)
333
3.53k
{
334
3.53k
  unsigned entries, tag, type, len, c;
335
3.53k
  INT64 save;
336
337
3.53k
  entries = get2();
338
3.53k
  if (entries > 40)
339
842
    return;
340
2.68k
  if (entries > 0)
341
2.21k
    imgdata.other.parsed_gps.gpsparsed = 1;
342
2.68k
  INT64 fsize = ifp->size();
343
39.9k
  while (entries--)
344
37.3k
  {
345
37.3k
    tiff_get(base, &tag, &type, &len, &save);
346
37.3k
    if (len > 1024)
347
27.3k
    {
348
27.3k
      fseek(ifp, save, SEEK_SET); // Recover tiff-read position!!
349
27.3k
      continue;                   // no GPS tags are 1k or larger
350
27.3k
    }
351
9.97k
    INT64 savepos = ftell(ifp);
352
9.97k
    if (len > 8 && savepos + len > fsize * 2)
353
122
    {
354
122
        fseek(ifp, save, SEEK_SET); // Recover tiff-read position!!
355
122
        continue;
356
122
    }
357
358
9.85k
    if (callbacks.exif_cb)
359
0
    {
360
0
        callbacks.exif_cb(callbacks.exifparser_data, tag | 0x50000, type, len, order, ifp, base);
361
0
        fseek(ifp, savepos, SEEK_SET);
362
0
    }
363
364
9.85k
    switch (tag)
365
9.85k
    {
366
1.32k
    case 0x0001:
367
1.32k
      imgdata.other.parsed_gps.latref = getc(ifp);
368
1.32k
      break;
369
174
    case 0x0003:
370
174
      imgdata.other.parsed_gps.longref = getc(ifp);
371
174
      break;
372
84
    case 0x0005:
373
84
      imgdata.other.parsed_gps.altref = getc(ifp);
374
84
      break;
375
702
    case 0x0002:
376
702
      if (len == 3)
377
1.63k
        FORC(3) imgdata.other.parsed_gps.latitude[c] = getrealf(type);
378
702
      break;
379
186
    case 0x0004:
380
186
      if (len == 3)
381
294
        FORC(3) imgdata.other.parsed_gps.longitude[c] = getrealf(type);
382
186
      break;
383
506
    case 0x0007:
384
506
      if (len == 3)
385
618
        FORC(3) imgdata.other.parsed_gps.gpstimestamp[c] = getrealf(type);
386
506
      break;
387
216
    case 0x0006:
388
216
      imgdata.other.parsed_gps.altitude = getrealf(type);
389
216
      break;
390
100
    case 0x0009:
391
100
      imgdata.other.parsed_gps.gpsstatus = getc(ifp);
392
100
      break;
393
9.85k
    }
394
9.83k
    fseek(ifp, save, SEEK_SET);
395
9.83k
  }
396
2.68k
}
397
398
void LibRaw::parse_gps(INT64 base)
399
3.56k
{
400
3.56k
  unsigned entries, tag, type, len, c;
401
3.56k
  INT64 save;
402
403
3.56k
  entries = get2();
404
3.56k
  if (entries > 40)
405
1.24k
    return;
406
33.8k
  while (entries--)
407
31.5k
  {
408
31.5k
    tiff_get(base, &tag, &type, &len, &save);
409
31.5k
    if (len > 1024)
410
23.1k
    {
411
23.1k
      fseek(ifp, save, SEEK_SET); // Recover tiff-read position!!
412
23.1k
      continue;                   // no GPS tags are 1k or larger
413
23.1k
    }
414
8.44k
    switch (tag)
415
8.44k
    {
416
1.27k
    case 0x0001:
417
1.47k
    case 0x0003:
418
1.55k
    case 0x0005:
419
1.55k
      gpsdata[29 + tag / 2] = getc(ifp);
420
1.55k
      break;
421
682
    case 0x0002:
422
764
    case 0x0004:
423
1.12k
    case 0x0007:
424
6.75k
      FORC(6) gpsdata[tag / 3 * 6 + c] = get4();
425
1.12k
      break;
426
84
    case 0x0006:
427
168
      FORC(2) gpsdata[18 + c] = get4();
428
84
      break;
429
102
    case 0x0012: // 18
430
236
    case 0x001d: // 29
431
236
      fgets((char *)(gpsdata + 14 + tag / 3), MIN(len, 12), ifp);
432
8.44k
    }
433
8.41k
    fseek(ifp, save, SEEK_SET);
434
8.41k
  }
435
2.32k
}