Coverage Report

Created: 2025-09-08 07:52

/src/LibRaw/src/metadata/cr3_parser.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- C++ -*-
2
 * Copyright 2019-2024 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
6
{
66
6
  short maxTrack = libraw_internal_data.unpacker_data.crx_track_count;
67
6
  if (maxTrack < 0)
68
0
    return;
69
70
6
  INT64 bitcounts[LIBRAW_CRXTRACKS_MAXCOUNT], maxbitcount = 0;
71
6
  int framecounts[LIBRAW_CRXTRACKS_MAXCOUNT];
72
6
  uint32_t maxjpegbytes = 0;
73
6
  int framecnt = 0;
74
6
  int media_tracks = 0;
75
6
  int track_select = 0;
76
6
  int frame_select = 0;
77
6
  memset(bitcounts, 0, sizeof(bitcounts));
78
6
  memset(framecounts, 0, sizeof(framecounts));
79
80
  // Calc max frame bitcount for max-sized RAW track(s) selection
81
42
  for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
82
36
  {
83
36
    crx_data_header_t *d = &libraw_internal_data.unpacker_data.crx_header[i];
84
36
    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
36
  }
92
93
6
  if (maxbitcount < 8) // no raw tracks
94
6
    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(INT64 oAtomList,
341
                     INT64 szAtomList, short &nesting,
342
                     char *AtomNameStack, short &nTrack, short &TrackType)
343
1.40k
{
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
1.40k
  const char UIID_Canon[17] =
353
1.40k
      "\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48";
354
1.40k
  const unsigned char UIID_CanonPreview[17] = "\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16";
355
1.40k
  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
1.40k
  short AtomType;
364
1.40k
  static const struct
365
1.40k
  {
366
1.40k
    char AtomName[5];
367
1.40k
    short AtomType;
368
1.40k
  } AtomNamesList[] = {
369
1.40k
      {"dinf", 1},
370
1.40k
      {"edts", 1},
371
1.40k
      {"fiin", 1},
372
1.40k
      {"ipro", 1},
373
1.40k
      {"iprp", 1},
374
1.40k
      {"mdia", 1},
375
1.40k
      {"meco", 1},
376
1.40k
      {"mere", 1},
377
1.40k
      {"mfra", 1},
378
1.40k
      {"minf", 1},
379
1.40k
      {"moof", 1},
380
1.40k
      {"moov", 1},
381
1.40k
      {"mvex", 1},
382
1.40k
      {"paen", 1},
383
1.40k
      {"schi", 1},
384
1.40k
      {"sinf", 1},
385
1.40k
      {"skip", 1},
386
1.40k
      {"stbl", 1},
387
1.40k
      {"stsd", 1},
388
1.40k
      {"strk", 1},
389
1.40k
      {"tapt", 1},
390
1.40k
      {"traf", 1},
391
1.40k
      {"trak", 1},
392
393
1.40k
      {"cdsc", 2},
394
1.40k
      {"colr", 2},
395
1.40k
      {"dimg", 2},
396
      // {"dref", 2},
397
1.40k
      {"free", 2},
398
1.40k
      {"frma", 2},
399
1.40k
      {"ftyp", 2},
400
1.40k
      {"hdlr", 2},
401
1.40k
      {"hvcC", 2},
402
1.40k
      {"iinf", 2},
403
1.40k
      {"iloc", 2},
404
1.40k
      {"infe", 2},
405
1.40k
      {"ipco", 2},
406
1.40k
      {"ipma", 2},
407
1.40k
      {"iref", 2},
408
1.40k
      {"irot", 2},
409
1.40k
      {"ispe", 2},
410
1.40k
      {"meta", 2},
411
1.40k
      {"mvhd", 2},
412
1.40k
      {"pitm", 2},
413
1.40k
      {"pixi", 2},
414
1.40k
      {"schm", 2},
415
1.40k
      {"thmb", 2},
416
1.40k
      {"tkhd", 2},
417
1.40k
      {"url ", 2},
418
1.40k
      {"urn ", 2},
419
420
1.40k
      {"CCTP", 1},
421
1.40k
      {"CRAW", 1},
422
423
1.40k
      {"JPEG", 2},
424
1.40k
      {"CDI1", 2},
425
1.40k
      {"CMP1", 2},
426
427
1.40k
      {"CNCV", 2},
428
1.40k
      {"CCDT", 2},
429
1.40k
      {"CTBO", 2},
430
1.40k
      {"CMT1", 2},
431
1.40k
      {"CMT2", 2},
432
1.40k
      {"CMT3", 2},
433
1.40k
      {"CMT4", 2},
434
1.40k
      {"CNOP", 2},
435
1.40k
      {"THMB", 2},
436
1.40k
      {"co64", 2},
437
1.40k
      {"mdat", 2},
438
1.40k
      {"mdhd", 2},
439
1.40k
      {"nmhd", 2},
440
1.40k
      {"stsc", 2},
441
1.40k
      {"stsz", 2},
442
1.40k
      {"stts", 2},
443
1.40k
      {"vmhd", 2},
444
445
1.40k
      {"dref", 3},
446
1.40k
      {"uuid", 3},
447
1.40k
  };
448
449
1.40k
  const char sHandlerType[5][5] = {"unk.", "soun", "vide", "hint", "meta"};
450
451
1.40k
  int c, err=0;
452
453
1.40k
  ushort tL;                        // Atom length represented in 4 or 8 bytes
454
1.40k
  char nmAtom[5];                   // Atom name
455
1.40k
  INT64 oAtom, szAtom; // Atom offset and Atom size
456
1.40k
  INT64 oAtomContent,
457
1.40k
      szAtomContent; // offset and size of Atom content
458
1.40k
  INT64 lHdr;
459
460
1.40k
  char UIID[16];
461
1.40k
  uchar CMP1[85];
462
1.40k
  uchar thdr[4];
463
1.40k
  uchar CDI1[60];
464
1.40k
  char HandlerType[5], MediaFormatID[5];
465
466
1.40k
  nmAtom[0] = MediaFormatID[0] = nmAtom[4] = MediaFormatID[4] = '\0';
467
1.40k
  strcpy(HandlerType, sHandlerType[0]);
468
1.40k
  oAtom = oAtomList;
469
1.40k
  nesting++;
470
1.40k
  if (nesting > 31)
471
0
    return -14; // too deep nesting
472
1.40k
  short s_order = order;
473
474
8.55k
  while ((oAtom + 8LL) <= (oAtomList + szAtomList))
475
7.69k
  {
476
7.69k
    lHdr = 0ULL;
477
7.69k
    err = 0;
478
7.69k
    order = 0x4d4d;
479
7.69k
    fseek(ifp, oAtom, SEEK_SET);
480
7.69k
  if (nesting == 0)
481
2.37k
  {
482
2.37k
      fread(thdr, 1, 4, ifp);
483
2.37k
      fseek(ifp, oAtom, SEEK_SET);
484
2.37k
  }
485
7.69k
    szAtom = get4();
486
30.4k
    FORC4 nmAtom[c] = AtomNameStack[nesting * 4 + c] = fgetc(ifp);
487
7.69k
    AtomNameStack[(nesting + 1) * 4] = '\0';
488
7.69k
    tL = 4;
489
7.69k
    AtomType = 0;
490
491
472k
    for (c = 0; c < int(sizeof AtomNamesList / sizeof *AtomNamesList); c++)
492
466k
      if (!strcmp(nmAtom, AtomNamesList[c].AtomName))
493
1.57k
      {
494
1.57k
        AtomType = AtomNamesList[c].AtomType;
495
1.57k
        break;
496
1.57k
      }
497
498
7.69k
    if (!AtomType)
499
5.94k
    {
500
5.94k
    if (nesting == 0)
501
1.34k
    {
502
1.34k
      if(!memcmp(thdr,"II*\0",4) || !memcmp(thdr,"MM*\0",4))
503
4
      {
504
4
        err = 0;
505
4
        goto fin;
506
4
      }
507
1.34k
      }
508
5.93k
      err = 1;
509
5.93k
    }
510
511
7.69k
    if (szAtom == 0ULL)
512
58
    {
513
58
      if (nesting != 0)
514
36
      {
515
36
        err = -2;
516
36
        goto fin;
517
36
      }
518
22
      szAtom = szAtomList - oAtom;
519
22
      oAtomContent = oAtom + 8ULL;
520
22
      szAtomContent = szAtom - 8ULL;
521
22
    }
522
7.63k
    else if (szAtom == 1LL)
523
478
    {
524
478
      if ((oAtom + 16LL) > (oAtomList + szAtomList))
525
2
      {
526
2
        err = -3;
527
2
        goto fin;
528
2
      }
529
476
      tL = 8;
530
476
      szAtom = (((unsigned long long)get4()) << 32) | get4();
531
476
      oAtomContent = oAtom + 16ULL;
532
476
      szAtomContent = szAtom - 16ULL;
533
476
    }
534
7.15k
    else
535
7.15k
    {
536
7.15k
      oAtomContent = oAtom + 8ULL;
537
7.15k
      szAtomContent = szAtom - 8ULL;
538
7.15k
    }
539
540
7.65k
  if (!strcmp(AtomNameStack, "uuid")) // Top level uuid
541
26
  {
542
26
    INT64 tt = ftell(ifp);
543
26
    lHdr = 16ULL;
544
26
    fread(UIID, 1, lHdr, ifp);
545
26
    if (!memcmp(UIID, UUID_XMP, 16) && szAtom > 24LL && szAtom < 1024000LL)
546
0
    {
547
0
      xmpdata = (char *)calloc(xmplen = unsigned(szAtom - 23),1);
548
0
      unsigned br = fread(xmpdata,1, szAtom - 24, ifp);
549
0
      xmpdata[br] = 0;
550
0
    }
551
26
    else if (!memcmp(UIID, UIID_CanonPreview, 16) && szAtom > 48LL && szAtom < 100LL * 1024000LL)
552
0
    {
553
      // read next 48 bytes, check for 'PRVW'
554
0
      unsigned char xdata[32];
555
0
      fread(xdata, 32, 1, ifp);  
556
0
      if (!memcmp(xdata + 12, "PRVW", 4))
557
0
      {
558
0
        thumb_length = unsigned(szAtom - 56);
559
0
        thumb_offset = ftell(ifp);
560
0
        if (imgdata.thumbs_list.thumbcount < LIBRAW_THUMBNAIL_MAXCOUNT)
561
0
        {
562
0
          bool do_add = true;
563
0
          for(int idx = 0; idx < imgdata.thumbs_list.thumbcount; idx++)
564
0
            if (imgdata.thumbs_list.thumblist[idx].toffset == thumb_offset)
565
0
            {
566
0
              do_add = false;
567
0
              break;
568
0
            }
569
0
          if (do_add)
570
0
          {
571
0
            int idx = imgdata.thumbs_list.thumbcount;
572
0
            imgdata.thumbs_list.thumblist[idx].tformat = LIBRAW_INTERNAL_THUMBNAIL_JPEG;
573
0
            imgdata.thumbs_list.thumblist[idx].toffset = thumb_offset;
574
0
            imgdata.thumbs_list.thumblist[idx].tlength = thumb_length;
575
0
            imgdata.thumbs_list.thumblist[idx].tflip = 0xffff;
576
0
            imgdata.thumbs_list.thumblist[idx].tmisc = (3 << 5) | 8; // 3 samples/8 bps
577
0
            imgdata.thumbs_list.thumblist[idx].twidth = (xdata[22] << 8) + xdata[23];
578
0
                        imgdata.thumbs_list.thumblist[idx].theight = (xdata[24] << 8) + xdata[25];
579
0
            imgdata.thumbs_list.thumbcount++;
580
0
          }
581
0
        }
582
583
0
      }
584
0
    }
585
26
    fseek(ifp, tt, SEEK_SET);
586
26
  }
587
588
7.65k
    if (!strcmp(nmAtom, "trak"))
589
208
    {
590
208
      nTrack++;
591
208
      TrackType = 0;
592
208
      if (nTrack >= LIBRAW_CRXTRACKS_MAXCOUNT)
593
2
        break;
594
208
    }
595
7.65k
    if (!strcmp(AtomNameStack, "moovuuid"))
596
30
    {
597
30
      lHdr = 16ULL;
598
30
      fread(UIID, 1, lHdr, ifp);
599
30
      if (!strncmp(UIID, UIID_Canon, lHdr))
600
0
      {
601
0
        AtomType = 1;
602
0
      }
603
30
      else
604
30
        fseek(ifp, -lHdr, SEEK_CUR);
605
30
    }
606
7.62k
    else if (!strcmp(AtomNameStack, "moovuuidCCTP"))
607
0
    {
608
0
      lHdr = 12ULL;
609
0
    }
610
7.62k
    else if (!strcmp(AtomNameStack, "moovuuidCMT1"))
611
0
    {
612
0
      short q_order = order;
613
0
      order = get2();
614
0
      if ((tL != 4) || bad_hdr())
615
0
      {
616
0
        err = -4;
617
0
        goto fin;
618
0
      }
619
0
      if (!libraw_internal_data.unpacker_data.cr3_ifd0_length)
620
0
        libraw_internal_data.unpacker_data.cr3_ifd0_length = unsigned(szAtomContent);
621
0
      parse_tiff_ifd(oAtomContent);
622
0
      order = q_order;
623
0
    }
624
7.62k
  else if (!strcmp(AtomNameStack, "moovuuidTHMB") && szAtom > 24)
625
0
  {
626
0
    unsigned char xdata[16];
627
0
    fread(xdata, 16, 1, ifp);
628
0
    INT64 xoffset = ftell(ifp);
629
0
    if (imgdata.thumbs_list.thumbcount < LIBRAW_THUMBNAIL_MAXCOUNT)
630
0
    {
631
0
      bool do_add = true;
632
0
      for (int idx = 0; idx < imgdata.thumbs_list.thumbcount; idx++)
633
0
        if (imgdata.thumbs_list.thumblist[idx].toffset == xoffset)
634
0
        {
635
0
          do_add = false;
636
0
          break;
637
0
        }
638
0
            if (do_add)
639
0
            {
640
0
              int idx = imgdata.thumbs_list.thumbcount;
641
0
              imgdata.thumbs_list.thumblist[idx].tformat = LIBRAW_INTERNAL_THUMBNAIL_JPEG;
642
0
        imgdata.thumbs_list.thumblist[idx].toffset = xoffset;
643
0
              imgdata.thumbs_list.thumblist[idx].tlength = unsigned(szAtom-24LL);
644
0
        imgdata.thumbs_list.thumblist[idx].tflip = 0xffff;
645
0
              imgdata.thumbs_list.thumblist[idx].tmisc = (3 << 5) | 8; // 3 samples/8 bps
646
0
              imgdata.thumbs_list.thumblist[idx].twidth = (xdata[4] << 8) + xdata[5];
647
0
              imgdata.thumbs_list.thumblist[idx].theight = (xdata[6] << 8) + xdata[7];
648
0
              imgdata.thumbs_list.thumbcount++;
649
0
            }
650
0
    }
651
0
  }
652
7.62k
  else if (!strcmp(AtomNameStack, "moovuuidCMT2"))
653
0
  {
654
0
    short q_order = order;
655
0
    order = get2();
656
0
    if ((tL != 4) || bad_hdr())
657
0
    {
658
0
      err = -5;
659
0
      goto fin;
660
0
    }
661
0
    if (!libraw_internal_data.unpacker_data.cr3_exif_length)
662
0
      libraw_internal_data.unpacker_data.cr3_exif_length = unsigned(szAtomContent); 
663
0
      parse_exif(oAtomContent);
664
0
      order = q_order;
665
0
    }
666
7.62k
    else if (!strcmp(AtomNameStack, "moovuuidCMT3"))
667
0
    {
668
0
      short q_order = order;
669
0
      order = get2();
670
0
      if ((tL != 4) || bad_hdr())
671
0
      {
672
0
        err = -6;
673
0
        goto fin;
674
0
      }
675
0
    if (callbacks.exif_cb)
676
0
    {
677
0
        INT64 savepos = ifp->tell();
678
0
        callbacks.exif_cb(callbacks.exifparser_data, 0x70000 | 0x927c, 7, szAtomContent, order, ifp, oAtomContent);
679
0
        fseek(ifp, savepos, SEEK_SET);
680
0
    }
681
0
      fseek(ifp, -12L, SEEK_CUR);
682
0
      parse_makernote(oAtomContent, 0);
683
0
      order = q_order;
684
0
    }
685
7.62k
    else if (!strcmp(AtomNameStack, "moovuuidCMT4"))
686
0
    {
687
0
      short q_order = order;
688
0
      order = get2();
689
0
      if ((tL != 4) || bad_hdr())
690
0
      {
691
0
        err = -6;
692
0
        goto fin;
693
0
      }
694
0
      INT64 off = ftell(ifp);
695
0
      parse_gps(oAtomContent);
696
0
      fseek(ifp, off, SEEK_SET);
697
0
      parse_gps_libraw(oAtomContent);
698
0
      order = q_order;
699
0
    }
700
7.62k
    else if (!strcmp(AtomNameStack, "moovtrakmdiahdlr"))
701
0
    {
702
0
      fseek(ifp, 8L, SEEK_CUR);
703
0
      FORC4 HandlerType[c] = fgetc(ifp);
704
0
      for (c = 1; c < int(sizeof sHandlerType / sizeof *sHandlerType); c++)
705
0
        if (!strcmp(HandlerType, sHandlerType[c]))
706
0
        {
707
0
          TrackType = c;
708
0
          break;
709
0
        }
710
0
    }
711
7.62k
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsd"))
712
4
    {
713
4
      if (szAtomContent >= 16)
714
2
      {
715
2
        fseek(ifp, 12L, SEEK_CUR);
716
2
        lHdr = 8;
717
2
      }
718
2
      else
719
2
      {
720
2
        err = -7;
721
2
        goto fin;
722
2
      }
723
8
      FORC4 MediaFormatID[c] = fgetc(ifp);
724
2
      if ((TrackType == 2) && (!strcmp(MediaFormatID, "CRAW")))
725
0
      {
726
0
        if (szAtomContent >= 44)
727
0
          fseek(ifp, 24L, SEEK_CUR);
728
0
        else
729
0
        {
730
0
          err = -8;
731
0
          goto fin;
732
0
        }
733
0
      }
734
2
      else
735
2
      {
736
2
        AtomType = 2; // only continue for CRAW
737
2
        lHdr = 0;
738
2
      }
739
5.68k
#define current_track libraw_internal_data.unpacker_data.crx_header[nTrack]
740
741
2
      /*ImageWidth =*/ get2();
742
2
      /*ImageHeight =*/ get2();
743
2
    }
744
7.62k
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAW"))
745
0
    {
746
0
      lHdr = 82;
747
0
    }
748
7.62k
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWCMP1"))
749
0
    {
750
0
      INT64 read_size = szAtomContent > 85LL ? 85 : INT64(szAtomContent);
751
0
      if (szAtomContent >= 40)
752
0
        fread(CMP1, 1, size_t(read_size), ifp);
753
0
      else
754
0
      {
755
0
        err = -7;
756
0
        goto fin;
757
0
      }
758
0
      if (!crxParseImageHeader(CMP1, nTrack, read_size))
759
0
        current_track.MediaType = 1;
760
0
    }
761
762
7.62k
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWCDI1")) {
763
0
      if (szAtomContent >= 60) {
764
0
        fread(CDI1, 1, 60, ifp);
765
0
        if (!strncmp((char *)CDI1+8, "IAD1", 4) && (sgetn(8, CDI1) == 0x38)) {
766
          // sensor area at CDI1+12, 4 16-bit values
767
          // Bayer pattern? - next 4 16-bit values
768
0
          imCanon.RecommendedImageArea = sget_CanonArea(CDI1+12 + 2*4*2);
769
0
          imCanon.LeftOpticalBlack     = sget_CanonArea(CDI1+12 + 3*4*2);
770
0
          imCanon.UpperOpticalBlack    = sget_CanonArea(CDI1+12 + 4*4*2);
771
0
          imCanon.ActiveArea           = sget_CanonArea(CDI1+12 + 5*4*2);
772
0
        }
773
0
      }
774
0
    }
775
776
7.62k
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWJPEG"))
777
0
    {
778
0
      current_track.MediaType = 2;
779
0
    }
780
7.62k
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsc"))
781
20
    {
782
20
      if (szAtomContent >= 12) {
783
18
        fseek(ifp, 4L, SEEK_CUR);
784
18
        int entries = get4();
785
18
        if (entries < 1 || entries > 1000000)
786
6
        {
787
6
          err =  -9;
788
6
          goto fin;
789
6
        }
790
791
12
        current_track.stsc_data = (crx_sample_to_chunk_t*) calloc(entries * sizeof(crx_sample_to_chunk_t),1);
792
12
        if(!current_track.stsc_data)
793
0
        {
794
0
          err =  -9;
795
0
          goto fin;
796
0
        }
797
12
        current_track.stsc_count = entries;
798
572
        for(int i = 0; i < entries; i++)
799
560
        {
800
560
          current_track.stsc_data[i].first = get4();
801
560
          current_track.stsc_data[i].count = get4();
802
560
          current_track.stsc_data[i].id = get4();
803
560
        }
804
12
      }
805
20
    }
806
7.60k
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsz"))
807
50
    {
808
50
      if (szAtomContent >= 12)
809
24
      {
810
24
        fseek(ifp, 4L, SEEK_CUR);
811
24
        int sample_size = get4();
812
24
        int entries = get4();
813
24
        current_track.sample_count = entries;
814
815
        // if sample size is zero sample size is fixed
816
24
        if (sample_size)
817
4
        {
818
4
           current_track.MediaSize = sample_size;
819
4
           current_track.sample_size = sample_size;
820
4
        }
821
20
        else
822
20
        {
823
20
          current_track.sample_size = 0;
824
20
          if (entries < 1 || entries > 1000000) {
825
4
            err = -10;
826
4
            goto fin;
827
4
          }
828
16
          current_track.sample_sizes = (int32_t*)calloc(entries * sizeof(int32_t),1);
829
16
          if (!current_track.sample_sizes)
830
0
          {
831
0
            err = -10;
832
0
            goto fin;
833
0
          }
834
1.81k
          for (int i = 0; i < entries; i++)
835
1.80k
            current_track.sample_sizes[i] = get4();
836
837
16
          current_track.MediaSize = current_track.sample_sizes[0];
838
16
        }
839
24
      }
840
50
    }
841
7.55k
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblco64"))
842
18
    {
843
18
      if (szAtomContent >= 16) {
844
18
        fseek(ifp, 4L, SEEK_CUR);
845
18
        uint32_t entries = get4();
846
18
    uint32_t i;
847
18
        if (entries < 1 || entries > 1000000)
848
4
        {
849
4
          err = -11;
850
4
          goto fin;
851
4
        }
852
14
        current_track.chunk_offsets = (INT64*)calloc(entries * sizeof(int64_t),1);
853
14
        if(!current_track.chunk_offsets)
854
0
        {
855
0
          err = -11;
856
0
          goto fin;
857
0
        }
858
859
14
        current_track.chunk_count = entries;
860
900
        for (i = 0; i < entries; i++)
861
886
          current_track.chunk_offsets[i] = (((int64_t)get4()) << 32) | get4();
862
863
14
        current_track.chunk_count = i;
864
14
        current_track.MediaOffset =  current_track.chunk_offsets[0];
865
14
      }
866
18
    }
867
868
7.63k
    if (nTrack >= 0 && nTrack < LIBRAW_CRXTRACKS_MAXCOUNT &&
869
7.63k
        current_track.MediaSize && current_track.MediaOffset &&
870
7.63k
        ((oAtom + szAtom) >= (oAtomList + szAtomList)) &&
871
7.63k
        !strncmp(AtomNameStack, "moovtrakmdiaminfstbl", 20))
872
0
    {
873
0
      if ((TrackType == 4) && (!strcmp(MediaFormatID, "CTMD")))
874
0
      {
875
0
        current_track.MediaType = 3;
876
0
      }
877
0
    }
878
7.63k
#undef current_track
879
7.63k
    if (AtomType == 1)
880
896
    {
881
896
      err = parseCR3(oAtomContent + lHdr, szAtomContent - lHdr, nesting,
882
896
                     AtomNameStack, nTrack, TrackType);
883
896
      if (err)
884
482
        goto fin;
885
896
    }
886
7.15k
    oAtom += szAtom;
887
7.15k
  }
888
889
908
fin:
890
908
  nesting--;
891
908
  if (nesting >= 0)
892
612
    AtomNameStack[nesting * 4] = '\0';
893
908
  order = s_order;
894
908
  return err;
895
1.40k
}
896
#undef bad_hdr
897
898
void LibRaw::parseCR3_Free()
899
119k
{
900
119k
  short maxTrack = libraw_internal_data.unpacker_data.crx_track_count;
901
119k
  if (maxTrack < 0)
902
47.7k
    return;
903
904
143k
  for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
905
71.5k
  {
906
71.5k
    crx_data_header_t *d = &libraw_internal_data.unpacker_data.crx_header[i];
907
71.5k
    if (d->stsc_data)
908
0
    {
909
0
      free(d->stsc_data);
910
0
      d->stsc_data = NULL;
911
0
    }
912
71.5k
    if (d->chunk_offsets)
913
2
    {
914
2
      free(d->chunk_offsets);
915
2
      d->chunk_offsets = NULL;
916
2
    }
917
918
71.5k
    if (d->sample_sizes)
919
6
    {
920
6
      free(d->sample_sizes);
921
6
      d->sample_sizes = NULL;
922
6
    }
923
71.5k
    d->stsc_count   = 0;
924
71.5k
    d->sample_count = 0;
925
71.5k
    d->sample_size  = 0;
926
71.5k
    d->chunk_count  = 0;
927
71.5k
  }
928
71.5k
  libraw_internal_data.unpacker_data.crx_track_count = -1;
929
71.5k
}