Coverage Report

Created: 2026-02-26 07:48

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
0
{
66
0
  short maxTrack = libraw_internal_data.unpacker_data.crx_track_count;
67
0
  if (maxTrack < 0)
68
0
    return;
69
70
0
  INT64 bitcounts[LIBRAW_CRXTRACKS_MAXCOUNT], maxbitcount = 0;
71
0
  int framecounts[LIBRAW_CRXTRACKS_MAXCOUNT];
72
0
  uint32_t maxjpegbytes = 0;
73
0
  int framecnt = 0;
74
0
  int media_tracks = 0;
75
0
  int track_select = 0;
76
0
  int frame_select = 0;
77
0
  memset(bitcounts, 0, sizeof(bitcounts));
78
0
  memset(framecounts, 0, sizeof(framecounts));
79
80
  // Calc max frame bitcount for max-sized RAW track(s) selection
81
0
  for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
82
0
  {
83
0
    crx_data_header_t *d = &libraw_internal_data.unpacker_data.crx_header[i];
84
0
    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
0
  }
92
93
0
  if (maxbitcount < 8) // no raw tracks
94
0
    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
0
{
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
0
  const char UIID_Canon[17] =
353
0
      "\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48";
354
0
  const unsigned char UIID_CanonPreview[17] = "\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16";
355
0
  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
0
  short AtomType;
364
0
  static const struct
365
0
  {
366
0
    char AtomName[5];
367
0
    short AtomType;
368
0
  } AtomNamesList[] = {
369
0
      {"dinf", 1},
370
0
      {"edts", 1},
371
0
      {"fiin", 1},
372
0
      {"ipro", 1},
373
0
      {"iprp", 1},
374
0
      {"mdia", 1},
375
0
      {"meco", 1},
376
0
      {"mere", 1},
377
0
      {"mfra", 1},
378
0
      {"minf", 1},
379
0
      {"moof", 1},
380
0
      {"moov", 1},
381
0
      {"mvex", 1},
382
0
      {"paen", 1},
383
0
      {"schi", 1},
384
0
      {"sinf", 1},
385
0
      {"skip", 1},
386
0
      {"stbl", 1},
387
0
      {"stsd", 1},
388
0
      {"strk", 1},
389
0
      {"tapt", 1},
390
0
      {"traf", 1},
391
0
      {"trak", 1},
392
393
0
      {"cdsc", 2},
394
0
      {"colr", 2},
395
0
      {"dimg", 2},
396
      // {"dref", 2},
397
0
      {"free", 2},
398
0
      {"frma", 2},
399
0
      {"ftyp", 2},
400
0
      {"hdlr", 2},
401
0
      {"hvcC", 2},
402
0
      {"iinf", 2},
403
0
      {"iloc", 2},
404
0
      {"infe", 2},
405
0
      {"ipco", 2},
406
0
      {"ipma", 2},
407
0
      {"iref", 2},
408
0
      {"irot", 2},
409
0
      {"ispe", 2},
410
0
      {"meta", 2},
411
0
      {"mvhd", 2},
412
0
      {"pitm", 2},
413
0
      {"pixi", 2},
414
0
      {"schm", 2},
415
0
      {"thmb", 2},
416
0
      {"tkhd", 2},
417
0
      {"url ", 2},
418
0
      {"urn ", 2},
419
420
0
      {"CCTP", 1},
421
0
      {"CRAW", 1},
422
423
0
      {"JPEG", 2},
424
0
      {"CDI1", 2},
425
0
      {"CMP1", 2},
426
427
0
      {"CNCV", 2},
428
0
      {"CCDT", 2},
429
0
      {"CTBO", 2},
430
0
      {"CMT1", 2},
431
0
      {"CMT2", 2},
432
0
      {"CMT3", 2},
433
0
      {"CMT4", 2},
434
0
      {"CNOP", 2},
435
0
      {"THMB", 2},
436
0
      {"co64", 2},
437
0
      {"mdat", 2},
438
0
      {"mdhd", 2},
439
0
      {"nmhd", 2},
440
0
      {"stsc", 2},
441
0
      {"stsz", 2},
442
0
      {"stts", 2},
443
0
      {"vmhd", 2},
444
445
0
      {"dref", 3},
446
0
      {"uuid", 3},
447
0
  };
448
449
0
  const char sHandlerType[5][5] = {"unk.", "soun", "vide", "hint", "meta"};
450
451
0
  int c, err=0;
452
453
0
  ushort tL;                        // Atom length represented in 4 or 8 bytes
454
0
  char nmAtom[5];                   // Atom name
455
0
  UINT64 oAtom, szAtom; // Atom offset and Atom size
456
0
  UINT64 oAtomContent,
457
0
      szAtomContent; // offset and size of Atom content
458
0
  UINT64 lHdr;
459
460
0
  char UIID[16];
461
0
  uchar CMP1[85];
462
0
  uchar thdr[4];
463
0
  uchar CDI1[60];
464
0
  char HandlerType[5], MediaFormatID[5];
465
466
0
  nmAtom[0] = MediaFormatID[0] = nmAtom[4] = MediaFormatID[4] = '\0';
467
0
  strcpy(HandlerType, sHandlerType[0]);
468
0
  oAtom = oAtomList;
469
0
  nesting++;
470
0
  if (nesting > 31)
471
0
    return -14; // too deep nesting
472
0
  short s_order = order;
473
474
0
  while (((oAtom + 8ULL) <= (oAtomList + szAtomList)) && ((oAtom+8ULL) < filesz))
475
0
  {
476
0
    lHdr = 0ULL;
477
0
    err = 0;
478
0
    order = 0x4d4d;
479
0
    fseek(ifp, oAtom, SEEK_SET);
480
0
  if (nesting == 0)
481
0
  {
482
0
      fread(thdr, 1, 4, ifp);
483
0
      fseek(ifp, oAtom, SEEK_SET);
484
0
  }
485
0
  uint32_t sz = get4();
486
0
    szAtom = sz;
487
0
    FORC4 nmAtom[c] = AtomNameStack[nesting * 4 + c] = fgetc(ifp);
488
0
    AtomNameStack[(nesting + 1) * 4] = '\0';
489
0
    tL = 4;
490
0
    AtomType = 0;
491
492
0
    for (c = 0; c < int(sizeof AtomNamesList / sizeof *AtomNamesList); c++)
493
0
      if (!strcmp(nmAtom, AtomNamesList[c].AtomName))
494
0
      {
495
0
        AtomType = AtomNamesList[c].AtomType;
496
0
        break;
497
0
      }
498
499
0
    if (!AtomType)
500
0
    {
501
0
    if (nesting == 0)
502
0
    {
503
0
      if(!memcmp(thdr,"II*\0",4) || !memcmp(thdr,"MM*\0",4) ||
504
0
        ( !memcmp(HandlerType, "unk.", 4) && nTrack >=0))
505
0
      {
506
0
        err = 0;
507
0
        goto fin;
508
0
      }
509
0
      }
510
0
      err = 1;
511
0
    }
512
513
0
    if (szAtom == 0ULL)
514
0
    {
515
0
      if (nesting != 0)
516
0
      {
517
0
        err = -2;
518
0
        goto fin;
519
0
      }
520
0
      szAtom = szAtomList - oAtom;
521
0
      oAtomContent = oAtom + 8ULL;
522
0
      szAtomContent = szAtom - 8ULL;
523
0
    }
524
0
    else if (szAtom == 1LL)
525
0
    {
526
0
      if ((oAtom + 16LL) > (oAtomList + szAtomList))
527
0
      {
528
0
        err = -3;
529
0
        goto fin;
530
0
      }
531
0
      tL = 8;
532
0
    uint64_t upper = get4();
533
0
    uint64_t lower = get4();
534
0
      szAtom = ((upper & 0x7fffffff) << 32) | lower; // This will limit atom size to 2^63-1. In practice, you can live with this
535
0
      if (szAtom < 16ULL)
536
0
      {
537
0
        err = -3;
538
0
        goto fin;
539
0
      }
540
541
0
    oAtomContent = oAtom + 16ULL;
542
0
      szAtomContent = szAtom - 16ULL;
543
0
    }
544
0
    else
545
0
    {
546
0
      oAtomContent = oAtom + 8ULL;
547
0
      szAtomContent = szAtom - 8ULL;
548
0
    }
549
0
  if (szAtom < 8ULL)
550
0
  {
551
0
      err = -3;
552
0
      goto fin;
553
0
  }
554
555
0
  if (!strcmp(AtomNameStack, "uuid")) // Top level uuid
556
0
  {
557
0
    INT64 tt = ftell(ifp);
558
0
    lHdr = 16ULL;
559
0
    fread(UIID, 1, lHdr, ifp);
560
0
    if (!memcmp(UIID, UUID_XMP, 16) && szAtom > 24LL && szAtom < 1024000LL)
561
0
    {
562
0
      xmpdata = (char *)calloc(xmplen = unsigned(szAtom - 23),1);
563
0
      unsigned br = fread(xmpdata,1, szAtom - 24, ifp);
564
0
      xmpdata[br] = 0;
565
0
    }
566
0
    else if (!memcmp(UIID, UIID_CanonPreview, 16) && szAtom > 48LL && szAtom < 100LL * 1024000LL)
567
0
    {
568
      // read next 48 bytes, check for 'PRVW'
569
0
      unsigned char xdata[32];
570
0
      fread(xdata, 32, 1, ifp);  
571
0
      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
0
    }
600
0
    fseek(ifp, tt, SEEK_SET);
601
0
  }
602
603
0
    if (!strcmp(nmAtom, "trak"))
604
0
    {
605
0
      nTrack++;
606
0
      TrackType = 0;
607
0
      if (nTrack >= LIBRAW_CRXTRACKS_MAXCOUNT)
608
0
        break;
609
0
    }
610
0
    if (!strcmp(AtomNameStack, "moovuuid"))
611
0
    {
612
0
      lHdr = 16ULL;
613
0
      fread(UIID, 1, lHdr, ifp);
614
0
      if (!strncmp(UIID, UIID_Canon, lHdr))
615
0
      {
616
0
        AtomType = 1;
617
0
      }
618
0
      else
619
0
        fseek(ifp, -lHdr, SEEK_CUR);
620
0
    }
621
0
    else if (!strcmp(AtomNameStack, "moovuuidCCTP"))
622
0
    {
623
0
      lHdr = 12ULL;
624
0
    }
625
0
    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
0
  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
0
  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
0
    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
0
    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
0
    else if (!strcmp(AtomNameStack, "moovtrakmdiahdlr"))
716
0
    {
717
0
      fseek(ifp, 8L, SEEK_CUR);
718
0
      FORC4 HandlerType[c] = fgetc(ifp);
719
0
      for (c = 1; c < int(sizeof sHandlerType / sizeof *sHandlerType); c++)
720
0
        if (!strcmp(HandlerType, sHandlerType[c]))
721
0
        {
722
0
          TrackType = c;
723
0
          break;
724
0
        }
725
0
    }
726
0
    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
0
#define current_track libraw_internal_data.unpacker_data.crx_header[nTrack]
755
756
0
      /*ImageWidth =*/ get2();
757
0
      /*ImageHeight =*/ get2();
758
0
    }
759
0
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAW"))
760
0
    {
761
0
      lHdr = 82;
762
0
    }
763
0
    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
0
    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
0
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWJPEG"))
792
0
    {
793
0
      current_track.MediaType = 2;
794
0
    }
795
0
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsc"))
796
0
    {
797
0
      if (szAtomContent >= 12) {
798
0
        fseek(ifp, 4L, SEEK_CUR);
799
0
        int entries = get4();
800
0
        if (entries < 1 || entries > 1000000)
801
0
        {
802
0
          err =  -9;
803
0
          goto fin;
804
0
        }
805
806
0
        current_track.stsc_data = (crx_sample_to_chunk_t*) calloc(entries * sizeof(crx_sample_to_chunk_t),1);
807
0
        if(!current_track.stsc_data)
808
0
        {
809
0
          err =  -9;
810
0
          goto fin;
811
0
        }
812
0
        current_track.stsc_count = entries;
813
0
        for(int i = 0; i < entries; i++)
814
0
        {
815
0
          current_track.stsc_data[i].first = get4();
816
0
          current_track.stsc_data[i].count = get4();
817
0
          current_track.stsc_data[i].id = get4();
818
0
        }
819
0
      }
820
0
    }
821
0
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsz"))
822
0
    {
823
0
      if (szAtomContent >= 12)
824
0
      {
825
0
        fseek(ifp, 4L, SEEK_CUR);
826
0
        int sample_size = get4();
827
0
        int entries = get4();
828
0
        current_track.sample_count = entries;
829
830
        // if sample size is zero sample size is fixed
831
0
        if (sample_size)
832
0
        {
833
0
           current_track.MediaSize = sample_size;
834
0
           current_track.sample_size = sample_size;
835
0
        }
836
0
        else
837
0
        {
838
0
          current_track.sample_size = 0;
839
0
          if (entries < 1 || entries > 1000000) {
840
0
            err = -10;
841
0
            goto fin;
842
0
          }
843
0
          current_track.sample_sizes = (int32_t*)calloc(entries * sizeof(int32_t),1);
844
0
          if (!current_track.sample_sizes)
845
0
          {
846
0
            err = -10;
847
0
            goto fin;
848
0
          }
849
0
          for (int i = 0; i < entries; i++)
850
0
            current_track.sample_sizes[i] = get4();
851
852
0
          current_track.MediaSize = current_track.sample_sizes[0];
853
0
        }
854
0
      }
855
0
    }
856
0
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblco64"))
857
0
    {
858
0
      if (szAtomContent >= 16) {
859
0
        fseek(ifp, 4L, SEEK_CUR);
860
0
        uint32_t entries = get4();
861
0
    uint32_t i;
862
0
        if (entries < 1 || entries > 1000000)
863
0
        {
864
0
          err = -11;
865
0
          goto fin;
866
0
        }
867
0
        current_track.chunk_offsets = (INT64*)calloc(entries * sizeof(int64_t),1);
868
0
        if(!current_track.chunk_offsets)
869
0
        {
870
0
          err = -11;
871
0
          goto fin;
872
0
        }
873
874
0
        current_track.chunk_count = entries;
875
0
        for (i = 0; i < entries; i++)
876
0
          current_track.chunk_offsets[i] = (((int64_t)get4()) << 32) | get4();
877
878
0
        current_track.chunk_count = i;
879
0
        current_track.MediaOffset =  current_track.chunk_offsets[0];
880
0
      }
881
0
    }
882
883
0
    if (nTrack >= 0 && nTrack < LIBRAW_CRXTRACKS_MAXCOUNT &&
884
0
        current_track.MediaSize && current_track.MediaOffset &&
885
0
        ((oAtom + szAtom) >= (oAtomList + szAtomList)) &&
886
0
        !strncmp(AtomNameStack, "moovtrakmdiaminfstbl", 20))
887
0
    {
888
0
      if ((TrackType == 4) && (!strcmp(MediaFormatID, "CTMD")))
889
0
      {
890
0
        current_track.MediaType = 3;
891
0
      }
892
0
    }
893
0
#undef current_track
894
0
    if (AtomType == 1)
895
0
    {
896
0
      err = parseCR3(oAtomContent + lHdr, szAtomContent - lHdr, nesting,
897
0
                     AtomNameStack, nTrack, TrackType,filesz);
898
0
      if (err)
899
0
        goto fin;
900
0
    }
901
0
    oAtom += szAtom;
902
0
  }
903
904
0
fin:
905
0
  nesting--;
906
0
  if (nesting >= 0)
907
0
    AtomNameStack[nesting * 4] = '\0';
908
0
  order = s_order;
909
0
  return err;
910
0
}
911
#undef bad_hdr
912
913
void LibRaw::parseCR3_Free()
914
0
{
915
0
  short maxTrack = libraw_internal_data.unpacker_data.crx_track_count;
916
0
  if (maxTrack < 0)
917
0
    return;
918
919
0
  for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
920
0
  {
921
0
    crx_data_header_t *d = &libraw_internal_data.unpacker_data.crx_header[i];
922
0
    if (d->stsc_data)
923
0
    {
924
0
      free(d->stsc_data);
925
0
      d->stsc_data = NULL;
926
0
    }
927
0
    if (d->chunk_offsets)
928
0
    {
929
0
      free(d->chunk_offsets);
930
0
      d->chunk_offsets = NULL;
931
0
    }
932
933
0
    if (d->sample_sizes)
934
0
    {
935
0
      free(d->sample_sizes);
936
      d->sample_sizes = NULL;
937
0
    }
938
0
    d->stsc_count   = 0;
939
0
    d->sample_count = 0;
940
0
    d->sample_size  = 0;
941
0
    d->chunk_count  = 0;
942
0
  }
943
0
  libraw_internal_data.unpacker_data.crx_track_count = -1;
944
0
}