Coverage Report

Created: 2025-10-12 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-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
4
{
66
4
  short maxTrack = libraw_internal_data.unpacker_data.crx_track_count;
67
4
  if (maxTrack < 0)
68
0
    return;
69
70
4
  INT64 bitcounts[LIBRAW_CRXTRACKS_MAXCOUNT], maxbitcount = 0;
71
4
  int framecounts[LIBRAW_CRXTRACKS_MAXCOUNT];
72
4
  uint32_t maxjpegbytes = 0;
73
4
  int framecnt = 0;
74
4
  int media_tracks = 0;
75
4
  int track_select = 0;
76
4
  int frame_select = 0;
77
4
  memset(bitcounts, 0, sizeof(bitcounts));
78
4
  memset(framecounts, 0, sizeof(framecounts));
79
80
  // Calc max frame bitcount for max-sized RAW track(s) selection
81
23
  for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
82
19
  {
83
19
    crx_data_header_t *d = &libraw_internal_data.unpacker_data.crx_header[i];
84
19
    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
19
  }
92
93
4
  if (maxbitcount < 8) // no raw tracks
94
4
    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.31k
{
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.31k
  const char UIID_Canon[17] =
353
1.31k
      "\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48";
354
1.31k
  const unsigned char UIID_CanonPreview[17] = "\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16";
355
1.31k
  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.31k
  short AtomType;
364
1.31k
  static const struct
365
1.31k
  {
366
1.31k
    char AtomName[5];
367
1.31k
    short AtomType;
368
1.31k
  } AtomNamesList[] = {
369
1.31k
      {"dinf", 1},
370
1.31k
      {"edts", 1},
371
1.31k
      {"fiin", 1},
372
1.31k
      {"ipro", 1},
373
1.31k
      {"iprp", 1},
374
1.31k
      {"mdia", 1},
375
1.31k
      {"meco", 1},
376
1.31k
      {"mere", 1},
377
1.31k
      {"mfra", 1},
378
1.31k
      {"minf", 1},
379
1.31k
      {"moof", 1},
380
1.31k
      {"moov", 1},
381
1.31k
      {"mvex", 1},
382
1.31k
      {"paen", 1},
383
1.31k
      {"schi", 1},
384
1.31k
      {"sinf", 1},
385
1.31k
      {"skip", 1},
386
1.31k
      {"stbl", 1},
387
1.31k
      {"stsd", 1},
388
1.31k
      {"strk", 1},
389
1.31k
      {"tapt", 1},
390
1.31k
      {"traf", 1},
391
1.31k
      {"trak", 1},
392
393
1.31k
      {"cdsc", 2},
394
1.31k
      {"colr", 2},
395
1.31k
      {"dimg", 2},
396
      // {"dref", 2},
397
1.31k
      {"free", 2},
398
1.31k
      {"frma", 2},
399
1.31k
      {"ftyp", 2},
400
1.31k
      {"hdlr", 2},
401
1.31k
      {"hvcC", 2},
402
1.31k
      {"iinf", 2},
403
1.31k
      {"iloc", 2},
404
1.31k
      {"infe", 2},
405
1.31k
      {"ipco", 2},
406
1.31k
      {"ipma", 2},
407
1.31k
      {"iref", 2},
408
1.31k
      {"irot", 2},
409
1.31k
      {"ispe", 2},
410
1.31k
      {"meta", 2},
411
1.31k
      {"mvhd", 2},
412
1.31k
      {"pitm", 2},
413
1.31k
      {"pixi", 2},
414
1.31k
      {"schm", 2},
415
1.31k
      {"thmb", 2},
416
1.31k
      {"tkhd", 2},
417
1.31k
      {"url ", 2},
418
1.31k
      {"urn ", 2},
419
420
1.31k
      {"CCTP", 1},
421
1.31k
      {"CRAW", 1},
422
423
1.31k
      {"JPEG", 2},
424
1.31k
      {"CDI1", 2},
425
1.31k
      {"CMP1", 2},
426
427
1.31k
      {"CNCV", 2},
428
1.31k
      {"CCDT", 2},
429
1.31k
      {"CTBO", 2},
430
1.31k
      {"CMT1", 2},
431
1.31k
      {"CMT2", 2},
432
1.31k
      {"CMT3", 2},
433
1.31k
      {"CMT4", 2},
434
1.31k
      {"CNOP", 2},
435
1.31k
      {"THMB", 2},
436
1.31k
      {"co64", 2},
437
1.31k
      {"mdat", 2},
438
1.31k
      {"mdhd", 2},
439
1.31k
      {"nmhd", 2},
440
1.31k
      {"stsc", 2},
441
1.31k
      {"stsz", 2},
442
1.31k
      {"stts", 2},
443
1.31k
      {"vmhd", 2},
444
445
1.31k
      {"dref", 3},
446
1.31k
      {"uuid", 3},
447
1.31k
  };
448
449
1.31k
  const char sHandlerType[5][5] = {"unk.", "soun", "vide", "hint", "meta"};
450
451
1.31k
  int c, err=0;
452
453
1.31k
  ushort tL;                        // Atom length represented in 4 or 8 bytes
454
1.31k
  char nmAtom[5];                   // Atom name
455
1.31k
  INT64 oAtom, szAtom; // Atom offset and Atom size
456
1.31k
  INT64 oAtomContent,
457
1.31k
      szAtomContent; // offset and size of Atom content
458
1.31k
  INT64 lHdr;
459
460
1.31k
  char UIID[16];
461
1.31k
  uchar CMP1[85];
462
1.31k
  uchar thdr[4];
463
1.31k
  uchar CDI1[60];
464
1.31k
  char HandlerType[5], MediaFormatID[5];
465
466
1.31k
  nmAtom[0] = MediaFormatID[0] = nmAtom[4] = MediaFormatID[4] = '\0';
467
1.31k
  strcpy(HandlerType, sHandlerType[0]);
468
1.31k
  oAtom = oAtomList;
469
1.31k
  nesting++;
470
1.31k
  if (nesting > 31)
471
0
    return -14; // too deep nesting
472
1.31k
  short s_order = order;
473
474
1.23M
  while ((oAtom + 8LL) <= (oAtomList + szAtomList))
475
1.23M
  {
476
1.23M
    lHdr = 0ULL;
477
1.23M
    err = 0;
478
1.23M
    order = 0x4d4d;
479
1.23M
    fseek(ifp, oAtom, SEEK_SET);
480
1.23M
  if (nesting == 0)
481
811k
  {
482
811k
      fread(thdr, 1, 4, ifp);
483
811k
      fseek(ifp, oAtom, SEEK_SET);
484
811k
  }
485
1.23M
    szAtom = get4();
486
4.95M
    FORC4 nmAtom[c] = AtomNameStack[nesting * 4 + c] = fgetc(ifp);
487
1.23M
    AtomNameStack[(nesting + 1) * 4] = '\0';
488
1.23M
    tL = 4;
489
1.23M
    AtomType = 0;
490
491
90.3M
    for (c = 0; c < int(sizeof AtomNamesList / sizeof *AtomNamesList); c++)
492
89.0M
      if (!strcmp(nmAtom, AtomNamesList[c].AtomName))
493
1.49k
      {
494
1.49k
        AtomType = AtomNamesList[c].AtomType;
495
1.49k
        break;
496
1.49k
      }
497
498
1.23M
    if (!AtomType)
499
1.23M
    {
500
1.23M
    if (nesting == 0)
501
811k
    {
502
811k
      if(!memcmp(thdr,"II*\0",4) || !memcmp(thdr,"MM*\0",4))
503
4
      {
504
4
        err = 0;
505
4
        goto fin;
506
4
      }
507
811k
      }
508
1.23M
      err = 1;
509
1.23M
    }
510
511
1.23M
    if (szAtom == 0ULL)
512
41
    {
513
41
      if (nesting != 0)
514
14
      {
515
14
        err = -2;
516
14
        goto fin;
517
14
      }
518
27
      szAtom = szAtomList - oAtom;
519
27
      oAtomContent = oAtom + 8ULL;
520
27
      szAtomContent = szAtom - 8ULL;
521
27
    }
522
1.23M
    else if (szAtom == 1LL)
523
161
    {
524
161
      if ((oAtom + 16LL) > (oAtomList + szAtomList))
525
1
      {
526
1
        err = -3;
527
1
        goto fin;
528
1
      }
529
160
      tL = 8;
530
160
      szAtom = (((unsigned long long)get4()) << 32) | get4();
531
160
      oAtomContent = oAtom + 16ULL;
532
160
      szAtomContent = szAtom - 16ULL;
533
160
    }
534
1.23M
    else
535
1.23M
    {
536
1.23M
      oAtomContent = oAtom + 8ULL;
537
1.23M
      szAtomContent = szAtom - 8ULL;
538
1.23M
    }
539
540
1.23M
  if (!strcmp(AtomNameStack, "uuid")) // Top level uuid
541
57
  {
542
57
    INT64 tt = ftell(ifp);
543
57
    lHdr = 16ULL;
544
57
    fread(UIID, 1, lHdr, ifp);
545
57
    if (!memcmp(UIID, UUID_XMP, 16) && szAtom > 24LL && szAtom < 1024000LL)
546
2
    {
547
2
      xmpdata = (char *)calloc(xmplen = unsigned(szAtom - 23),1);
548
2
      unsigned br = fread(xmpdata,1, szAtom - 24, ifp);
549
2
      xmpdata[br] = 0;
550
2
    }
551
55
    else if (!memcmp(UIID, UIID_CanonPreview, 16) && szAtom > 48LL && szAtom < 100LL * 1024000LL)
552
1
    {
553
      // read next 48 bytes, check for 'PRVW'
554
1
      unsigned char xdata[32];
555
1
      fread(xdata, 32, 1, ifp);  
556
1
      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
1
    }
585
57
    fseek(ifp, tt, SEEK_SET);
586
57
  }
587
588
1.23M
    if (!strcmp(nmAtom, "trak"))
589
388
    {
590
388
      nTrack++;
591
388
      TrackType = 0;
592
388
      if (nTrack >= LIBRAW_CRXTRACKS_MAXCOUNT)
593
4
        break;
594
388
    }
595
1.23M
    if (!strcmp(AtomNameStack, "moovuuid"))
596
3
    {
597
3
      lHdr = 16ULL;
598
3
      fread(UIID, 1, lHdr, ifp);
599
3
      if (!strncmp(UIID, UIID_Canon, lHdr))
600
0
      {
601
0
        AtomType = 1;
602
0
      }
603
3
      else
604
3
        fseek(ifp, -lHdr, SEEK_CUR);
605
3
    }
606
1.23M
    else if (!strcmp(AtomNameStack, "moovuuidCCTP"))
607
0
    {
608
0
      lHdr = 12ULL;
609
0
    }
610
1.23M
    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
1.23M
  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
1.23M
  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
1.23M
    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
1.23M
    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
1.23M
    else if (!strcmp(AtomNameStack, "moovtrakmdiahdlr"))
701
1
    {
702
1
      fseek(ifp, 8L, SEEK_CUR);
703
4
      FORC4 HandlerType[c] = fgetc(ifp);
704
5
      for (c = 1; c < int(sizeof sHandlerType / sizeof *sHandlerType); c++)
705
4
        if (!strcmp(HandlerType, sHandlerType[c]))
706
0
        {
707
0
          TrackType = c;
708
0
          break;
709
0
        }
710
1
    }
711
1.23M
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsd"))
712
15
    {
713
15
      if (szAtomContent >= 16)
714
12
      {
715
12
        fseek(ifp, 12L, SEEK_CUR);
716
12
        lHdr = 8;
717
12
      }
718
3
      else
719
3
      {
720
3
        err = -7;
721
3
        goto fin;
722
3
      }
723
48
      FORC4 MediaFormatID[c] = fgetc(ifp);
724
12
      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
12
      else
735
12
      {
736
12
        AtomType = 2; // only continue for CRAW
737
12
        lHdr = 0;
738
12
      }
739
4.26M
#define current_track libraw_internal_data.unpacker_data.crx_header[nTrack]
740
741
12
      /*ImageWidth =*/ get2();
742
12
      /*ImageHeight =*/ get2();
743
12
    }
744
1.23M
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAW"))
745
0
    {
746
0
      lHdr = 82;
747
0
    }
748
1.23M
    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
1.23M
    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
1.23M
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWJPEG"))
777
0
    {
778
0
      current_track.MediaType = 2;
779
0
    }
780
1.23M
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsc"))
781
26
    {
782
26
      if (szAtomContent >= 12) {
783
19
        fseek(ifp, 4L, SEEK_CUR);
784
19
        int entries = get4();
785
19
        if (entries < 1 || entries > 1000000)
786
5
        {
787
5
          err =  -9;
788
5
          goto fin;
789
5
        }
790
791
14
        current_track.stsc_data = (crx_sample_to_chunk_t*) calloc(entries * sizeof(crx_sample_to_chunk_t),1);
792
14
        if(!current_track.stsc_data)
793
0
        {
794
0
          err =  -9;
795
0
          goto fin;
796
0
        }
797
14
        current_track.stsc_count = entries;
798
1.04M
        for(int i = 0; i < entries; i++)
799
1.04M
        {
800
1.04M
          current_track.stsc_data[i].first = get4();
801
1.04M
          current_track.stsc_data[i].count = get4();
802
1.04M
          current_track.stsc_data[i].id = get4();
803
1.04M
        }
804
14
      }
805
26
    }
806
1.23M
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsz"))
807
45
    {
808
45
      if (szAtomContent >= 12)
809
32
      {
810
32
        fseek(ifp, 4L, SEEK_CUR);
811
32
        int sample_size = get4();
812
32
        int entries = get4();
813
32
        current_track.sample_count = entries;
814
815
        // if sample size is zero sample size is fixed
816
32
        if (sample_size)
817
11
        {
818
11
           current_track.MediaSize = sample_size;
819
11
           current_track.sample_size = sample_size;
820
11
        }
821
21
        else
822
21
        {
823
21
          current_track.sample_size = 0;
824
21
          if (entries < 1 || entries > 1000000) {
825
3
            err = -10;
826
3
            goto fin;
827
3
          }
828
18
          current_track.sample_sizes = (int32_t*)calloc(entries * sizeof(int32_t),1);
829
18
          if (!current_track.sample_sizes)
830
0
          {
831
0
            err = -10;
832
0
            goto fin;
833
0
          }
834
241k
          for (int i = 0; i < entries; i++)
835
241k
            current_track.sample_sizes[i] = get4();
836
837
18
          current_track.MediaSize = current_track.sample_sizes[0];
838
18
        }
839
32
      }
840
45
    }
841
1.23M
    else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblco64"))
842
17
    {
843
17
      if (szAtomContent >= 16) {
844
17
        fseek(ifp, 4L, SEEK_CUR);
845
17
        uint32_t entries = get4();
846
17
    uint32_t i;
847
17
        if (entries < 1 || entries > 1000000)
848
3
        {
849
3
          err = -11;
850
3
          goto fin;
851
3
        }
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
475k
        for (i = 0; i < entries; i++)
861
475k
          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
17
    }
867
868
1.23M
    if (nTrack >= 0 && nTrack < LIBRAW_CRXTRACKS_MAXCOUNT &&
869
422k
        current_track.MediaSize && current_track.MediaOffset &&
870
0
        ((oAtom + szAtom) >= (oAtomList + szAtomList)) &&
871
0
        !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
1.23M
#undef current_track
879
1.23M
    if (AtomType == 1)
880
966
    {
881
966
      err = parseCR3(oAtomContent + lHdr, szAtomContent - lHdr, nesting,
882
966
                     AtomNameStack, nTrack, TrackType);
883
966
      if (err)
884
778
        goto fin;
885
966
    }
886
1.23M
    oAtom += szAtom;
887
1.23M
  }
888
889
1.31k
fin:
890
1.31k
  nesting--;
891
1.31k
  if (nesting >= 0)
892
966
    AtomNameStack[nesting * 4] = '\0';
893
1.31k
  order = s_order;
894
1.31k
  return err;
895
1.31k
}
896
#undef bad_hdr
897
898
void LibRaw::parseCR3_Free()
899
78.6k
{
900
78.6k
  short maxTrack = libraw_internal_data.unpacker_data.crx_track_count;
901
78.6k
  if (maxTrack < 0)
902
31.0k
    return;
903
904
95.4k
  for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
905
47.8k
  {
906
47.8k
    crx_data_header_t *d = &libraw_internal_data.unpacker_data.crx_header[i];
907
47.8k
    if (d->stsc_data)
908
11
    {
909
11
      free(d->stsc_data);
910
11
      d->stsc_data = NULL;
911
11
    }
912
47.8k
    if (d->chunk_offsets)
913
12
    {
914
12
      free(d->chunk_offsets);
915
12
      d->chunk_offsets = NULL;
916
12
    }
917
918
47.8k
    if (d->sample_sizes)
919
16
    {
920
16
      free(d->sample_sizes);
921
      d->sample_sizes = NULL;
922
16
    }
923
47.8k
    d->stsc_count   = 0;
924
47.8k
    d->sample_count = 0;
925
47.8k
    d->sample_size  = 0;
926
47.8k
    d->chunk_count  = 0;
927
47.8k
  }
928
47.6k
  libraw_internal_data.unpacker_data.crx_track_count = -1;
929
47.6k
}