Coverage Report

Created: 2026-02-14 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libraw/src/metadata/cr3_parser.cpp
Line
Count
Source
1
/* -*- C++ -*-
2
 * Copyright 2019-2025 LibRaw LLC (info@libraw.org)
3
 *
4
5
 LibRaw is free software; you can redistribute it and/or modify
6
 it under the terms of the one of two licenses as you choose:
7
8
1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
9
   (See file LICENSE.LGPL provided in LibRaw distribution archive for details).
10
11
2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
12
   (See file LICENSE.CDDL provided in LibRaw distribution archive for details).
13
14
 */
15
16
#include "../../internal/dcraw_defs.h"
17
18
19
0
static libraw_area_t sget_CanonArea(uchar *s) {
20
0
  libraw_area_t la = {};
21
0
  la.l = s[0] << 8 | s[1];
22
0
  la.t = s[2] << 8 | s[3];
23
0
  la.r = s[4] << 8 | s[5];
24
0
  la.b = s[6] << 8 | s[7];
25
0
  return la;
26
0
}
27
28
int LibRaw::selectCRXFrame(short trackNum, unsigned frameIndex)
29
0
{
30
0
  uint32_t sample_size;
31
0
  uint32_t stsc_index = 0;
32
0
  uint32_t current_sample = 0;
33
0
  crx_data_header_t *hdr = &libraw_internal_data.unpacker_data.crx_header[trackNum];
34
35
0
  if (frameIndex >= hdr->sample_count)
36
0
    return -1;
37
38
0
  for (unsigned i = 0; i < hdr->chunk_count; i++)
39
0
  {
40
0
    int64_t current_offset = hdr->chunk_offsets[i];
41
42
0
    while((stsc_index < hdr->stsc_count) && (i+1 == hdr->stsc_data[stsc_index+1].first))
43
0
      stsc_index++;
44
45
0
    for (unsigned j = 0; j < hdr->stsc_data[stsc_index].count; j++)
46
0
    {
47
0
      if (current_sample > hdr->sample_count)
48
0
        return -1;
49
50
0
      sample_size = hdr->sample_size > 0 ? hdr->sample_size : hdr->sample_sizes[current_sample];
51
0
      if(current_sample == frameIndex)
52
0
      {
53
0
        hdr->MediaOffset = current_offset;
54
0
        hdr->MediaSize = sample_size;
55
0
        return 0;
56
0
      }
57
0
      current_offset += sample_size;
58
0
      current_sample++;
59
0
    }
60
0
  }
61
0
  return -1;
62
0
}
63
64
void LibRaw::selectCRXTrack()
65
28
{
66
28
  short maxTrack = libraw_internal_data.unpacker_data.crx_track_count;
67
28
  if (maxTrack < 0)
68
0
    return;
69
70
28
  INT64 bitcounts[LIBRAW_CRXTRACKS_MAXCOUNT], maxbitcount = 0;
71
28
  int framecounts[LIBRAW_CRXTRACKS_MAXCOUNT];
72
28
  uint32_t maxjpegbytes = 0;
73
28
  int framecnt = 0;
74
28
  int media_tracks = 0;
75
28
  int track_select = 0;
76
28
  int frame_select = 0;
77
28
  memset(bitcounts, 0, sizeof(bitcounts));
78
28
  memset(framecounts, 0, sizeof(framecounts));
79
80
  // Calc max frame bitcount for max-sized RAW track(s) selection
81
107
  for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
82
79
  {
83
79
    crx_data_header_t *d = &libraw_internal_data.unpacker_data.crx_header[i];
84
79
    if (d->MediaType == 1) // RAW
85
0
    {
86
0
      bitcounts[i] = INT64(d->nBits) * INT64(d->f_width) * INT64(d->f_height);
87
0
      maxbitcount = MAX(bitcounts[i], maxbitcount);
88
0
    if (d->sample_count > 1)
89
0
      framecounts[i] = d->sample_count;
90
0
    }
91
79
  }
92
93
28
  if (maxbitcount < 8) // no raw tracks
94
28
    return;
95
96
  // Calc  RAW tracks and frames
97
0
  for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
98
0
  {
99
0
    if (bitcounts[i] == maxbitcount)
100
0
    {
101
0
      media_tracks++;
102
0
      if (framecounts[i] > 1)
103
0
        framecnt = MAX(framecnt, framecounts[i]);
104
0
    }
105
0
  }
106
  
107
  // If the file has only 1 media track shot_select represents frames select.
108
  // If the file has multiple media tracks shot_select represents track select.
109
  // If the file has multiple media tracks and multiple frames it is currently unsupported.
110
111
0
  if (framecnt && media_tracks > 1)
112
0
    return;
113
0
  else if (framecnt)
114
0
    frame_select = shot_select;
115
0
  else
116
0
    track_select = shot_select;
117
118
0
  int tracki = -1;
119
0
  for (int i = 0, trackcnt = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
120
0
  {
121
0
    if (bitcounts[i] == maxbitcount)
122
0
    {
123
0
      if (trackcnt <= (int)track_select)
124
0
        tracki = i;
125
0
    trackcnt++;
126
0
    }
127
0
  }
128
129
0
  if (tracki >= 0 && tracki < LIBRAW_CRXTRACKS_MAXCOUNT /* && frame_select > 0 */)
130
0
  {
131
0
    framecnt = framecounts[tracki]; // Update to selected track
132
0
    frame_select = LIM(frame_select, 0, framecnt);
133
0
    if(frame_select > 0)
134
0
    if (selectCRXFrame(tracki, frame_select))
135
0
        return;
136
0
  }
137
0
  else
138
0
    return; // No RAW track index
139
140
0
  int ctmdcount = 0;
141
  // Frame selected: parse CTMD metadata
142
0
  for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
143
0
  {
144
0
    crx_data_header_t *d = &libraw_internal_data.unpacker_data.crx_header[i];
145
0
    int fsel = LIM(frame_select, 0, int(d->sample_count));
146
0
    if (d->MediaType == 3) // CTMD metadata
147
0
    {
148
      /* ignore errors !*/
149
0
      if (fsel)
150
0
        selectCRXFrame(i, fsel);
151
0
      parseCR3_CTMD(i);
152
0
      ctmdcount++;
153
0
    }
154
0
    else if (d->MediaType == 2) // JPEG
155
0
    {
156
0
      if (fsel)
157
0
        selectCRXFrame(i, fsel);
158
0
      if (d->MediaSize > maxjpegbytes)
159
0
      {
160
0
        maxjpegbytes = d->MediaSize;
161
0
        thumb_offset = d->MediaOffset;
162
0
        thumb_length = d->MediaSize;
163
0
              if (imgdata.thumbs_list.thumbcount < LIBRAW_THUMBNAIL_MAXCOUNT)
164
0
              {
165
0
                bool do_add = true;
166
0
                for (int idx = 0; idx < imgdata.thumbs_list.thumbcount; idx++)
167
0
                  if (imgdata.thumbs_list.thumblist[idx].toffset == thumb_offset)
168
0
                  {
169
0
                    do_add = false;
170
0
                    break;
171
0
                  }
172
0
                if (do_add)
173
0
                {
174
0
                  int idx = imgdata.thumbs_list.thumbcount;
175
0
                  imgdata.thumbs_list.thumblist[idx].tformat = LIBRAW_INTERNAL_THUMBNAIL_JPEG;
176
0
                  imgdata.thumbs_list.thumblist[idx].toffset = thumb_offset;
177
0
                  imgdata.thumbs_list.thumblist[idx].tlength = thumb_length;
178
0
                  imgdata.thumbs_list.thumblist[idx].tflip = 0xffff;
179
0
                  imgdata.thumbs_list.thumblist[idx].tmisc = (3 << 5) | 8; // 3 samples/8 bps
180
0
                  imgdata.thumbs_list.thumblist[idx].twidth = 0;
181
0
                  imgdata.thumbs_list.thumblist[idx].theight = 0;
182
0
                  imgdata.thumbs_list.thumbcount++;
183
0
                }
184
0
              }
185
0
      }
186
0
    }
187
0
  }
188
189
0
  if (framecnt)
190
0
    is_raw = framecnt;
191
0
  else
192
0
    is_raw = media_tracks;
193
194
0
  if (tracki >= 0 && tracki < LIBRAW_CRXTRACKS_MAXCOUNT)
195
0
  {
196
0
    crx_data_header_t *d =
197
0
        &libraw_internal_data.unpacker_data.crx_header[tracki];
198
0
    data_offset = d->MediaOffset;
199
0
    data_size = d->MediaSize;
200
0
    raw_width = d->f_width;
201
0
    raw_height = d->f_height;
202
0
    load_raw = &LibRaw::crxLoadRaw;
203
0
    tiff_bps = d->encType == 3? d->medianBits : d->nBits;
204
0
    switch (d->cfaLayout)
205
0
    {
206
0
    case 0:
207
0
      filters = 0x94949494;
208
0
      break;
209
0
    case 1:
210
0
      filters = 0x61616161;
211
0
      break;
212
0
    case 2:
213
0
      filters = 0x49494949;
214
0
      break;
215
0
    case 3:
216
0
      filters = 0x16161616;
217
0
      break;
218
0
    }
219
220
0
    libraw_internal_data.unpacker_data.crx_track_selected = tracki;
221
222
0
    int tiff_idx = -1;
223
0
    INT64 tpixels = 0;
224
0
    for (unsigned i = 0; i < tiff_nifds && i < LIBRAW_IFD_MAXCOUNT; i++)
225
0
      if (INT64(tiff_ifd[i].t_height) * INT64(tiff_ifd[i].t_height) > tpixels)
226
0
      {
227
0
        tpixels = INT64(tiff_ifd[i].t_height) * INT64(tiff_ifd[i].t_height);
228
0
        tiff_idx = i;
229
0
      }
230
0
    if (tiff_idx >= 0)
231
0
      flip = tiff_ifd[tiff_idx].t_flip;
232
233
0
  if (ctmdcount == 1 && imgdata.makernotes.canon.multishot[0] && imgdata.makernotes.canon.multishot[1])
234
0
    for (int c = 0; c < 4; c++)
235
0
      cam_mul[c] = 1024;
236
0
  }
237
0
}
238
239
#define bad_hdr()                                                              \
240
0
  (((order != 0x4d4d) && (order != 0x4949)) || (get2() != 0x002a) ||           \
241
0
   (get4() != 0x00000008))
242
243
int LibRaw::parseCR3_CTMD(short trackNum)
244
0
{
245
0
  int err = 0;
246
0
  short s_order = order;
247
0
  order = 0x4949;
248
0
  uint32_t relpos_inDir = 0;
249
0
  uint32_t relpos_inBox = 0;
250
0
  unsigned szItem, Tag, lTag;
251
0
  ushort tItem;
252
253
0
#define track libraw_internal_data.unpacker_data.crx_header[trackNum]
254
255
0
  if (track.MediaType != 3)
256
0
  {
257
0
    err = -10;
258
0
    goto ctmd_fin;
259
0
  }
260
261
0
  while (relpos_inDir + 6 < track.MediaSize)
262
0
  {
263
0
    if (track.MediaOffset + relpos_inDir > ifp->size() - 6) // need at least 6 bytes
264
0
    {
265
0
        err = -11;
266
0
        goto ctmd_fin;
267
0
    }
268
0
    fseek(ifp, track.MediaOffset + relpos_inDir, SEEK_SET);
269
0
    szItem = get4();
270
0
    tItem = get2();
271
0
    if (szItem < 1 || (  (relpos_inDir + szItem) > track.MediaSize))
272
0
    {
273
0
      err = -11;
274
0
      goto ctmd_fin;
275
0
    }
276
0
    if ((tItem == 7) || (tItem == 8) || (tItem == 9))
277
0
    {
278
0
      relpos_inBox = relpos_inDir + 12L;
279
0
      while (relpos_inBox + 8 < relpos_inDir + szItem)
280
0
      {
281
0
        if (track.MediaOffset + relpos_inBox > ifp->size() - 8) // need at least 8 bytes
282
0
        {
283
0
            err = -11;
284
0
            goto ctmd_fin;
285
0
        }
286
0
        fseek(ifp, track.MediaOffset + relpos_inBox, SEEK_SET);
287
0
        lTag = get4();
288
0
        Tag = get4();
289
0
        if (lTag < 8)
290
0
        {
291
0
          err = -12;
292
0
          goto ctmd_fin;
293
0
        }
294
0
        else if ((relpos_inBox + lTag) > (relpos_inDir + szItem))
295
0
        {
296
0
          err = -11;
297
0
          goto ctmd_fin;
298
0
        }
299
0
        if (Tag == 0x927c)
300
0
        {
301
0
          fseek(ifp, track.MediaOffset + relpos_inBox + 8L,
302
0
                SEEK_SET);
303
0
          short q_order = order;
304
0
          order = get2();
305
0
          if (bad_hdr())
306
0
          {
307
0
            err = -13;
308
0
            goto ctmd_fin;
309
0
          }
310
0
          if (callbacks.exif_cb)
311
0
          {
312
0
            INT64 savepos = ifp->tell();
313
0
            callbacks.exif_cb(callbacks.exifparser_data, (tItem << 20) | 0x80000 | 0x927c, 7, lTag-8, order, ifp, 
314
0
        track.MediaOffset + relpos_inBox + 8);
315
0
            fseek(ifp, savepos, SEEK_SET);
316
0
          }
317
318
0
      if ((tItem == 7) || (tItem == 8))
319
0
      {
320
0
        fseek(ifp, -8L, SEEK_CUR);
321
0
        libraw_internal_data.unpacker_data.CR3_CTMDtag = 1;
322
0
        parse_makernote(track.MediaOffset + relpos_inBox + 8,
323
0
          0);
324
0
        libraw_internal_data.unpacker_data.CR3_CTMDtag = 0;
325
0
      }
326
0
          order = q_order;
327
0
        }
328
0
        relpos_inBox += lTag;
329
0
      }
330
0
    }
331
0
    relpos_inDir += szItem;
332
0
  }
333
334
0
ctmd_fin:
335
0
  order = s_order;
336
0
  return err;
337
0
}
338
#undef track
339
340
int LibRaw::parseCR3(UINT64 oAtomList,
341
                     UINT64 szAtomList, short &nesting,
342
                     char *AtomNameStack, short &nTrack, short &TrackType, UINT64 filesz)
343
743
{
344
  /*
345
  Atom starts with 4 bytes for Atom size and 4 bytes containing Atom name
346
  Atom size includes the length of the header and the size of all "contained"
347
  Atoms if Atom size == 1, Atom has the extended size stored in 8 bytes located
348
  after the Atom name if Atom size == 0, it is the last top-level Atom extending
349
  to the end of the file Atom name is often a 4 symbol mnemonic, but can be a
350
  4-byte integer
351
  */
352
743
  const char UIID_Canon[17] =
353
743
      "\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48";
354
743
  const unsigned char UIID_CanonPreview[17] = "\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16";
355
743
  const unsigned char UUID_XMP[17] = "\xbe\x7a\xcf\xcb\x97\xa9\x42\xe8\x9c\x71\x99\x94\x91\xe3\xaf\xac";
356
  
357
  /*
358
  AtomType = 0 - unknown: "unk."
359
  AtomType = 1 - container atom: "cont"
360
  AtomType = 2 - leaf atom: "leaf"
361
  AtomType = 3 - can be container, can be leaf: "both"
362
  */
363
743
  short AtomType;
364
743
  static const struct
365
743
  {
366
743
    char AtomName[5];
367
743
    short AtomType;
368
743
  } AtomNamesList[] = {
369
743
      {"dinf", 1},
370
743
      {"edts", 1},
371
743
      {"fiin", 1},
372
743
      {"ipro", 1},
373
743
      {"iprp", 1},
374
743
      {"mdia", 1},
375
743
      {"meco", 1},
376
743
      {"mere", 1},
377
743
      {"mfra", 1},
378
743
      {"minf", 1},
379
743
      {"moof", 1},
380
743
      {"moov", 1},
381
743
      {"mvex", 1},
382
743
      {"paen", 1},
383
743
      {"schi", 1},
384
743
      {"sinf", 1},
385
743
      {"skip", 1},
386
743
      {"stbl", 1},
387
743
      {"stsd", 1},
388
743
      {"strk", 1},
389
743
      {"tapt", 1},
390
743
      {"traf", 1},
391
743
      {"trak", 1},
392
393
743
      {"cdsc", 2},
394
743
      {"colr", 2},
395
743
      {"dimg", 2},
396
      // {"dref", 2},
397
743
      {"free", 2},
398
743
      {"frma", 2},
399
743
      {"ftyp", 2},
400
743
      {"hdlr", 2},
401
743
      {"hvcC", 2},
402
743
      {"iinf", 2},
403
743
      {"iloc", 2},
404
743
      {"infe", 2},
405
743
      {"ipco", 2},
406
743
      {"ipma", 2},
407
743
      {"iref", 2},
408
743
      {"irot", 2},
409
743
      {"ispe", 2},
410
743
      {"meta", 2},
411
743
      {"mvhd", 2},
412
743
      {"pitm", 2},
413
743
      {"pixi", 2},
414
743
      {"schm", 2},
415
743
      {"thmb", 2},
416
743
      {"tkhd", 2},
417
743
      {"url ", 2},
418
743
      {"urn ", 2},
419
420
743
      {"CCTP", 1},
421
743
      {"CRAW", 1},
422
423
743
      {"JPEG", 2},
424
743
      {"CDI1", 2},
425
743
      {"CMP1", 2},
426
427
743
      {"CNCV", 2},
428
743
      {"CCDT", 2},
429
743
      {"CTBO", 2},
430
743
      {"CMT1", 2},
431
743
      {"CMT2", 2},
432
743
      {"CMT3", 2},
433
743
      {"CMT4", 2},
434
743
      {"CNOP", 2},
435
743
      {"THMB", 2},
436
743
      {"co64", 2},
437
743
      {"mdat", 2},
438
743
      {"mdhd", 2},
439
743
      {"nmhd", 2},
440
743
      {"stsc", 2},
441
743
      {"stsz", 2},
442
743
      {"stts", 2},
443
743
      {"vmhd", 2},
444
445
743
      {"dref", 3},
446
743
      {"uuid", 3},
447
743
  };
448
449
743
  const char sHandlerType[5][5] = {"unk.", "soun", "vide", "hint", "meta"};
450
451
743
  int c, err=0;
452
453
743
  ushort tL;                        // Atom length represented in 4 or 8 bytes
454
743
  char nmAtom[5];                   // Atom name
455
743
  UINT64 oAtom, szAtom; // Atom offset and Atom size
456
743
  UINT64 oAtomContent,
457
743
      szAtomContent; // offset and size of Atom content
458
743
  UINT64 lHdr;
459
460
743
  char UIID[16];
461
743
  uchar CMP1[85];
462
743
  uchar thdr[4];
463
743
  uchar CDI1[60];
464
743
  char HandlerType[5], MediaFormatID[5];
465
466
743
  nmAtom[0] = MediaFormatID[0] = nmAtom[4] = MediaFormatID[4] = '\0';
467
743
  strcpy(HandlerType, sHandlerType[0]);
468
743
  oAtom = oAtomList;
469
743
  nesting++;
470
743
  if (nesting > 31)
471
0
    return -14; // too deep nesting
472
743
  short s_order = order;
473
474
1.45k
  while (((oAtom + 8ULL) <= (oAtomList + szAtomList)) && ((oAtom+8ULL) < filesz))
475
1.03k
  {
476
1.03k
    lHdr = 0ULL;
477
1.03k
    err = 0;
478
1.03k
    order = 0x4d4d;
479
1.03k
    fseek(ifp, oAtom, SEEK_SET);
480
1.03k
  if (nesting == 0)
481
478
  {
482
478
      fread(thdr, 1, 4, ifp);
483
478
      fseek(ifp, oAtom, SEEK_SET);
484
478
  }
485
1.03k
  uint32_t sz = get4();
486
1.03k
    szAtom = sz;
487
4.12k
    FORC4 nmAtom[c] = AtomNameStack[nesting * 4 + c] = fgetc(ifp);
488
1.03k
    AtomNameStack[(nesting + 1) * 4] = '\0';
489
1.03k
    tL = 4;
490
1.03k
    AtomType = 0;
491
492
35.1k
    for (c = 0; c < int(sizeof AtomNamesList / sizeof *AtomNamesList); c++)
493
34.9k
      if (!strcmp(nmAtom, AtomNamesList[c].AtomName))
494
843
      {
495
843
        AtomType = AtomNamesList[c].AtomType;
496
843
        break;
497
843
      }
498
499
1.03k
    if (!AtomType)
500
188
    {
501
188
    if (nesting == 0)
502
61
    {
503
61
      if(!memcmp(thdr,"II*\0",4) || !memcmp(thdr,"MM*\0",4) ||
504
59
        ( !memcmp(HandlerType, "unk.", 4) && nTrack >=0))
505
4
      {
506
4
        err = 0;
507
4
        goto fin;
508
4
      }
509
61
      }
510
184
      err = 1;
511
184
    }
512
513
1.02k
    if (szAtom == 0ULL)
514
7
    {
515
7
      if (nesting != 0)
516
3
      {
517
3
        err = -2;
518
3
        goto fin;
519
3
      }
520
4
      szAtom = szAtomList - oAtom;
521
4
      oAtomContent = oAtom + 8ULL;
522
4
      szAtomContent = szAtom - 8ULL;
523
4
    }
524
1.02k
    else if (szAtom == 1LL)
525
72
    {
526
72
      if ((oAtom + 16LL) > (oAtomList + szAtomList))
527
0
      {
528
0
        err = -3;
529
0
        goto fin;
530
0
      }
531
72
      tL = 8;
532
72
    uint64_t upper = get4();
533
72
    uint64_t lower = get4();
534
72
      szAtom = ((upper & 0x7fffffff) << 32) | lower; // This will limit atom size to 2^63-1. In practice, you can live with this
535
72
      if (szAtom < 16ULL)
536
4
      {
537
4
        err = -3;
538
4
        goto fin;
539
4
      }
540
541
68
    oAtomContent = oAtom + 16ULL;
542
68
      szAtomContent = szAtom - 16ULL;
543
68
    }
544
948
    else
545
948
    {
546
948
      oAtomContent = oAtom + 8ULL;
547
948
      szAtomContent = szAtom - 8ULL;
548
948
    }
549
1.02k
  if (szAtom < 8ULL)
550
1
  {
551
1
      err = -3;
552
1
      goto fin;
553
1
  }
554
555
1.01k
  if (!strcmp(AtomNameStack, "uuid")) // Top level uuid
556
36
  {
557
36
    INT64 tt = ftell(ifp);
558
36
    lHdr = 16ULL;
559
36
    fread(UIID, 1, lHdr, ifp);
560
36
    if (!memcmp(UIID, UUID_XMP, 16) && szAtom > 24LL && szAtom < 1024000LL)
561
2
    {
562
2
      xmpdata = (char *)calloc(xmplen = unsigned(szAtom - 23),1);
563
2
      unsigned br = fread(xmpdata,1, szAtom - 24, ifp);
564
2
      xmpdata[br] = 0;
565
2
    }
566
34
    else if (!memcmp(UIID, UIID_CanonPreview, 16) && szAtom > 48LL && szAtom < 100LL * 1024000LL)
567
2
    {
568
      // read next 48 bytes, check for 'PRVW'
569
2
      unsigned char xdata[32];
570
2
      fread(xdata, 32, 1, ifp);  
571
2
      if (!memcmp(xdata + 12, "PRVW", 4))
572
0
      {
573
0
        thumb_length = unsigned(szAtom - 56);
574
0
        thumb_offset = ftell(ifp);
575
0
        if (imgdata.thumbs_list.thumbcount < LIBRAW_THUMBNAIL_MAXCOUNT)
576
0
        {
577
0
          bool do_add = true;
578
0
          for(int idx = 0; idx < imgdata.thumbs_list.thumbcount; idx++)
579
0
            if (imgdata.thumbs_list.thumblist[idx].toffset == thumb_offset)
580
0
            {
581
0
              do_add = false;
582
0
              break;
583
0
            }
584
0
          if (do_add)
585
0
          {
586
0
            int idx = imgdata.thumbs_list.thumbcount;
587
0
            imgdata.thumbs_list.thumblist[idx].tformat = LIBRAW_INTERNAL_THUMBNAIL_JPEG;
588
0
            imgdata.thumbs_list.thumblist[idx].toffset = thumb_offset;
589
0
            imgdata.thumbs_list.thumblist[idx].tlength = thumb_length;
590
0
            imgdata.thumbs_list.thumblist[idx].tflip = 0xffff;
591
0
            imgdata.thumbs_list.thumblist[idx].tmisc = (3 << 5) | 8; // 3 samples/8 bps
592
0
            imgdata.thumbs_list.thumblist[idx].twidth = (xdata[22] << 8) + xdata[23];
593
0
                        imgdata.thumbs_list.thumblist[idx].theight = (xdata[24] << 8) + xdata[25];
594
0
            imgdata.thumbs_list.thumbcount++;
595
0
          }
596
0
        }
597
598
0
      }
599
2
    }
600
36
    fseek(ifp, tt, SEEK_SET);
601
36
  }
602
603
1.01k
    if (!strcmp(nmAtom, "trak"))
604
158
    {
605
158
      nTrack++;
606
158
      TrackType = 0;
607
158
      if (nTrack >= LIBRAW_CRXTRACKS_MAXCOUNT)
608
1
        break;
609
158
    }
610
1.01k
    if (!strcmp(AtomNameStack, "moovuuid"))
611
1
    {
612
1
      lHdr = 16ULL;
613
1
      fread(UIID, 1, lHdr, ifp);
614
1
      if (!strncmp(UIID, UIID_Canon, lHdr))
615
0
      {
616
0
        AtomType = 1;
617
0
      }
618
1
      else
619
1
        fseek(ifp, -lHdr, SEEK_CUR);
620
1
    }
621
1.01k
    else if (!strcmp(AtomNameStack, "moovuuidCCTP"))
622
0
    {
623
0
      lHdr = 12ULL;
624
0
    }
625
1.01k
    else if (!strcmp(AtomNameStack, "moovuuidCMT1"))
626
0
    {
627
0
      short q_order = order;
628
0
      order = get2();
629
0
      if ((tL != 4) || bad_hdr())
630
0
      {
631
0
        err = -4;
632
0
        goto fin;
633
0
      }
634
0
      if (!libraw_internal_data.unpacker_data.cr3_ifd0_length)
635
0
        libraw_internal_data.unpacker_data.cr3_ifd0_length = unsigned(szAtomContent);
636
0
      parse_tiff_ifd(oAtomContent);
637
0
      order = q_order;
638
0
    }
639
1.01k
  else if (!strcmp(AtomNameStack, "moovuuidTHMB") && szAtom > 24)
640
0
  {
641
0
    unsigned char xdata[16];
642
0
    fread(xdata, 16, 1, ifp);
643
0
    INT64 xoffset = ftell(ifp);
644
0
    if (imgdata.thumbs_list.thumbcount < LIBRAW_THUMBNAIL_MAXCOUNT)
645
0
    {
646
0
      bool do_add = true;
647
0
      for (int idx = 0; idx < imgdata.thumbs_list.thumbcount; idx++)
648
0
        if (imgdata.thumbs_list.thumblist[idx].toffset == xoffset)
649
0
        {
650
0
          do_add = false;
651
0
          break;
652
0
        }
653
0
            if (do_add)
654
0
            {
655
0
              int idx = imgdata.thumbs_list.thumbcount;
656
0
              imgdata.thumbs_list.thumblist[idx].tformat = LIBRAW_INTERNAL_THUMBNAIL_JPEG;
657
0
        imgdata.thumbs_list.thumblist[idx].toffset = xoffset;
658
0
              imgdata.thumbs_list.thumblist[idx].tlength = unsigned(szAtom-24LL);
659
0
        imgdata.thumbs_list.thumblist[idx].tflip = 0xffff;
660
0
              imgdata.thumbs_list.thumblist[idx].tmisc = (3 << 5) | 8; // 3 samples/8 bps
661
0
              imgdata.thumbs_list.thumblist[idx].twidth = (xdata[4] << 8) + xdata[5];
662
0
              imgdata.thumbs_list.thumblist[idx].theight = (xdata[6] << 8) + xdata[7];
663
0
              imgdata.thumbs_list.thumbcount++;
664
0
            }
665
0
    }
666
0
  }
667
1.01k
  else if (!strcmp(AtomNameStack, "moovuuidCMT2"))
668
0
  {
669
0
    short q_order = order;
670
0
    order = get2();
671
0
    if ((tL != 4) || bad_hdr())
672
0
    {
673
0
      err = -5;
674
0
      goto fin;
675
0
    }
676
0
    if (!libraw_internal_data.unpacker_data.cr3_exif_length)
677
0
      libraw_internal_data.unpacker_data.cr3_exif_length = unsigned(szAtomContent); 
678
0
      parse_exif(oAtomContent);
679
0
      order = q_order;
680
0
    }
681
1.01k
    else if (!strcmp(AtomNameStack, "moovuuidCMT3"))
682
0
    {
683
0
      short q_order = order;
684
0
      order = get2();
685
0
      if ((tL != 4) || bad_hdr())
686
0
      {
687
0
        err = -6;
688
0
        goto fin;
689
0
      }
690
0
    if (callbacks.exif_cb)
691
0
    {
692
0
        INT64 savepos = ifp->tell();
693
0
        callbacks.exif_cb(callbacks.exifparser_data, 0x70000 | 0x927c, 7, szAtomContent, order, ifp, oAtomContent);
694
0
        fseek(ifp, savepos, SEEK_SET);
695
0
    }
696
0
      fseek(ifp, -12L, SEEK_CUR);
697
0
      parse_makernote(oAtomContent, 0);
698
0
      order = q_order;
699
0
    }
700
1.01k
    else if (!strcmp(AtomNameStack, "moovuuidCMT4"))
701
0
    {
702
0
      short q_order = order;
703
0
      order = get2();
704
0
      if ((tL != 4) || bad_hdr())
705
0
      {
706
0
        err = -6;
707
0
        goto fin;
708
0
      }
709
0
      INT64 off = ftell(ifp);
710
0
      parse_gps(oAtomContent);
711
0
      fseek(ifp, off, SEEK_SET);
712
0
      parse_gps_libraw(oAtomContent);
713
0
      order = q_order;
714
0
    }
715
1.01k
    else if (!strcmp(AtomNameStack, "moovtrakmdiahdlr"))
716
1
    {
717
1
      fseek(ifp, 8L, SEEK_CUR);
718
4
      FORC4 HandlerType[c] = fgetc(ifp);
719
5
      for (c = 1; c < int(sizeof sHandlerType / sizeof *sHandlerType); c++)
720
4
        if (!strcmp(HandlerType, sHandlerType[c]))
721
0
        {
722
0
          TrackType = c;
723
0
          break;
724
0
        }
725
1
    }
726
1.01k
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsd"))
727
0
    {
728
0
      if (szAtomContent >= 16)
729
0
      {
730
0
        fseek(ifp, 12L, SEEK_CUR);
731
0
        lHdr = 8;
732
0
      }
733
0
      else
734
0
      {
735
0
        err = -7;
736
0
        goto fin;
737
0
      }
738
0
      FORC4 MediaFormatID[c] = fgetc(ifp);
739
0
      if ((TrackType == 2) && (!strcmp(MediaFormatID, "CRAW")))
740
0
      {
741
0
        if (szAtomContent >= 44)
742
0
          fseek(ifp, 24L, SEEK_CUR);
743
0
        else
744
0
        {
745
0
          err = -8;
746
0
          goto fin;
747
0
        }
748
0
      }
749
0
      else
750
0
      {
751
0
        AtomType = 2; // only continue for CRAW
752
0
        lHdr = 0;
753
0
      }
754
667k
#define current_track libraw_internal_data.unpacker_data.crx_header[nTrack]
755
756
0
      /*ImageWidth =*/ get2();
757
0
      /*ImageHeight =*/ get2();
758
0
    }
759
1.01k
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAW"))
760
0
    {
761
0
      lHdr = 82;
762
0
    }
763
1.01k
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWCMP1"))
764
0
    {
765
0
      INT64 read_size = szAtomContent > 85LL ? 85 : INT64(szAtomContent);
766
0
      if (szAtomContent >= 40)
767
0
        fread(CMP1, 1, size_t(read_size), ifp);
768
0
      else
769
0
      {
770
0
        err = -7;
771
0
        goto fin;
772
0
      }
773
0
      if (!crxParseImageHeader(CMP1, nTrack, read_size))
774
0
        current_track.MediaType = 1;
775
0
    }
776
777
1.01k
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWCDI1")) {
778
0
      if (szAtomContent >= 60) {
779
0
        fread(CDI1, 1, 60, ifp);
780
0
        if (!strncmp((char *)CDI1+8, "IAD1", 4) && (sgetn(8, CDI1) == 0x38)) {
781
          // sensor area at CDI1+12, 4 16-bit values
782
          // Bayer pattern? - next 4 16-bit values
783
0
          imCanon.RecommendedImageArea = sget_CanonArea(CDI1+12 + 2*4*2);
784
0
          imCanon.LeftOpticalBlack     = sget_CanonArea(CDI1+12 + 3*4*2);
785
0
          imCanon.UpperOpticalBlack    = sget_CanonArea(CDI1+12 + 4*4*2);
786
0
          imCanon.ActiveArea           = sget_CanonArea(CDI1+12 + 5*4*2);
787
0
        }
788
0
      }
789
0
    }
790
791
1.01k
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWJPEG"))
792
0
    {
793
0
      current_track.MediaType = 2;
794
0
    }
795
1.01k
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsc"))
796
12
    {
797
12
      if (szAtomContent >= 12) {
798
11
        fseek(ifp, 4L, SEEK_CUR);
799
11
        int entries = get4();
800
11
        if (entries < 1 || entries > 1000000)
801
2
        {
802
2
          err =  -9;
803
2
          goto fin;
804
2
        }
805
806
9
        current_track.stsc_data = (crx_sample_to_chunk_t*) calloc(entries * sizeof(crx_sample_to_chunk_t),1);
807
9
        if(!current_track.stsc_data)
808
0
        {
809
0
          err =  -9;
810
0
          goto fin;
811
0
        }
812
9
        current_track.stsc_count = entries;
813
1.26k
        for(int i = 0; i < entries; i++)
814
1.25k
        {
815
1.25k
          current_track.stsc_data[i].first = get4();
816
1.25k
          current_track.stsc_data[i].count = get4();
817
1.25k
          current_track.stsc_data[i].id = get4();
818
1.25k
        }
819
9
      }
820
12
    }
821
1.00k
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsz"))
822
33
    {
823
33
      if (szAtomContent >= 12)
824
27
      {
825
27
        fseek(ifp, 4L, SEEK_CUR);
826
27
        int sample_size = get4();
827
27
        int entries = get4();
828
27
        current_track.sample_count = entries;
829
830
        // if sample size is zero sample size is fixed
831
27
        if (sample_size)
832
14
        {
833
14
           current_track.MediaSize = sample_size;
834
14
           current_track.sample_size = sample_size;
835
14
        }
836
13
        else
837
13
        {
838
13
          current_track.sample_size = 0;
839
13
          if (entries < 1 || entries > 1000000) {
840
1
            err = -10;
841
1
            goto fin;
842
1
          }
843
12
          current_track.sample_sizes = (int32_t*)calloc(entries * sizeof(int32_t),1);
844
12
          if (!current_track.sample_sizes)
845
0
          {
846
0
            err = -10;
847
0
            goto fin;
848
0
          }
849
4.63k
          for (int i = 0; i < entries; i++)
850
4.62k
            current_track.sample_sizes[i] = get4();
851
852
12
          current_track.MediaSize = current_track.sample_sizes[0];
853
12
        }
854
27
      }
855
33
    }
856
971
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblco64"))
857
11
    {
858
11
      if (szAtomContent >= 16) {
859
11
        fseek(ifp, 4L, SEEK_CUR);
860
11
        uint32_t entries = get4();
861
11
    uint32_t i;
862
11
        if (entries < 1 || entries > 1000000)
863
3
        {
864
3
          err = -11;
865
3
          goto fin;
866
3
        }
867
8
        current_track.chunk_offsets = (INT64*)calloc(entries * sizeof(int64_t),1);
868
8
        if(!current_track.chunk_offsets)
869
0
        {
870
0
          err = -11;
871
0
          goto fin;
872
0
        }
873
874
8
        current_track.chunk_count = entries;
875
658k
        for (i = 0; i < entries; i++)
876
658k
          current_track.chunk_offsets[i] = (((int64_t)get4()) << 32) | get4();
877
878
8
        current_track.chunk_count = i;
879
8
        current_track.MediaOffset =  current_track.chunk_offsets[0];
880
8
      }
881
11
    }
882
883
1.01k
    if (nTrack >= 0 && nTrack < LIBRAW_CRXTRACKS_MAXCOUNT &&
884
451
        current_track.MediaSize && current_track.MediaOffset &&
885
6
        ((oAtom + szAtom) >= (oAtomList + szAtomList)) &&
886
3
        !strncmp(AtomNameStack, "moovtrakmdiaminfstbl", 20))
887
3
    {
888
3
      if ((TrackType == 4) && (!strcmp(MediaFormatID, "CTMD")))
889
0
      {
890
0
        current_track.MediaType = 3;
891
0
      }
892
3
    }
893
1.01k
#undef current_track
894
1.01k
    if (AtomType == 1)
895
513
    {
896
513
      err = parseCR3(oAtomContent + lHdr, szAtomContent - lHdr, nesting,
897
513
                     AtomNameStack, nTrack, TrackType,filesz);
898
513
      if (err)
899
300
        goto fin;
900
513
    }
901
712
    oAtom += szAtom;
902
712
  }
903
904
743
fin:
905
743
  nesting--;
906
743
  if (nesting >= 0)
907
513
    AtomNameStack[nesting * 4] = '\0';
908
743
  order = s_order;
909
743
  return err;
910
743
}
911
#undef bad_hdr
912
913
void LibRaw::parseCR3_Free()
914
63.2k
{
915
63.2k
  short maxTrack = libraw_internal_data.unpacker_data.crx_track_count;
916
63.2k
  if (maxTrack < 0)
917
25.2k
    return;
918
919
76.0k
  for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
920
38.0k
  {
921
38.0k
    crx_data_header_t *d = &libraw_internal_data.unpacker_data.crx_header[i];
922
38.0k
    if (d->stsc_data)
923
5
    {
924
5
      free(d->stsc_data);
925
5
      d->stsc_data = NULL;
926
5
    }
927
38.0k
    if (d->chunk_offsets)
928
7
    {
929
7
      free(d->chunk_offsets);
930
7
      d->chunk_offsets = NULL;
931
7
    }
932
933
38.0k
    if (d->sample_sizes)
934
8
    {
935
8
      free(d->sample_sizes);
936
      d->sample_sizes = NULL;
937
8
    }
938
38.0k
    d->stsc_count   = 0;
939
38.0k
    d->sample_count = 0;
940
38.0k
    d->sample_size  = 0;
941
38.0k
    d->chunk_count  = 0;
942
38.0k
  }
943
37.9k
  libraw_internal_data.unpacker_data.crx_track_count = -1;
944
37.9k
}