File indexing completed on 2025-01-05 03:56:58

0001 /* -*- C++ -*-
0002  * Copyright 2019-2021 LibRaw LLC (info@libraw.org)
0003  *
0004 
0005  LibRaw is free software; you can redistribute it and/or modify
0006  it under the terms of the one of two licenses as you choose:
0007 
0008 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
0009    (See file LICENSE.LGPL provided in LibRaw distribution archive for details).
0010 
0011 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
0012    (See file LICENSE.CDDL provided in LibRaw distribution archive for details).
0013 
0014  */
0015 
0016 #include "../../internal/dcraw_defs.h"
0017 
0018 
0019 static libraw_area_t sget_CanonArea(uchar *s) {
0020   libraw_area_t la = {};
0021   la.l = s[0] << 8 | s[1];
0022   la.t = s[2] << 8 | s[3];
0023   la.r = s[4] << 8 | s[5];
0024   la.b = s[6] << 8 | s[7];
0025   return la;
0026 }
0027 
0028 int LibRaw::selectCRXFrame(short trackNum, unsigned frameIndex)
0029 {
0030   uint32_t sample_size;
0031   uint32_t stsc_index = 0;
0032   uint32_t current_sample = 0;
0033   crx_data_header_t *hdr = &libraw_internal_data.unpacker_data.crx_header[trackNum];
0034 
0035   if (frameIndex >= hdr->sample_count)
0036     return -1;
0037 
0038   for (int i = 0; i < hdr->chunk_count; i++)
0039   {
0040     int64_t current_offset = hdr->chunk_offsets[i];
0041 
0042     while((stsc_index < hdr->stsc_count) && (i+1 == hdr->stsc_data[stsc_index+1].first))
0043       stsc_index++;
0044 
0045     for (int j = 0; j < hdr->stsc_data[stsc_index].count; j++)
0046     {
0047       if (current_sample > hdr->sample_count)
0048         return -1;
0049 
0050       sample_size = hdr->sample_size > 0 ? hdr->sample_size : hdr->sample_sizes[current_sample];
0051       if(current_sample == frameIndex)
0052       {
0053         hdr->MediaOffset = current_offset;
0054         hdr->MediaSize = sample_size;
0055         return 0;
0056       }
0057       current_offset += sample_size;
0058       current_sample++;
0059     }
0060   }
0061   return -1;
0062 }
0063 
0064 void LibRaw::selectCRXTrack()
0065 {
0066   short maxTrack = libraw_internal_data.unpacker_data.crx_track_count;
0067   if (maxTrack < 0)
0068     return;
0069 
0070   INT64 bitcounts[LIBRAW_CRXTRACKS_MAXCOUNT], maxbitcount = 0;
0071   int framecounts[LIBRAW_CRXTRACKS_MAXCOUNT], maxframecount = 0;
0072   uint32_t maxjpegbytes = 0;
0073   int framecnt = 0;
0074   int media_tracks = 0;
0075   int track_select = 0;
0076   int frame_select = 0;
0077   int err;
0078   memset(bitcounts, 0, sizeof(bitcounts));
0079   memset(framecounts, 0, sizeof(framecounts));
0080 
0081   // Calc max frame bitcount for max-sized RAW track(s) selection
0082   for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
0083   {
0084     crx_data_header_t *d = &libraw_internal_data.unpacker_data.crx_header[i];
0085     if (d->MediaType == 1) // RAW
0086     {
0087       bitcounts[i] = INT64(d->nBits) * INT64(d->f_width) * INT64(d->f_height);
0088       maxbitcount = MAX(bitcounts[i], maxbitcount);
0089       if (d->sample_count > 1)
0090           framecounts[i] = d->sample_count;
0091     }
0092   }
0093 
0094   if (maxbitcount < 8) // no raw tracks
0095       return;
0096 
0097   // Calc  RAW tracks and frames
0098   for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
0099   {
0100       if (bitcounts[i] == maxbitcount)
0101       {
0102           media_tracks++;
0103           if (framecounts[i] > 1)
0104               framecnt = MAX(framecnt, framecounts[i]);
0105       }
0106   }
0107   
0108   // If the file has only 1 media track shot_select represents frames select.
0109   // If the file has multiple media tracks shot_select represents track select.
0110   // If the file has multiple media tracks and multiple frames it is currently unsupported.
0111 
0112   if (framecnt && media_tracks > 1)
0113     return;
0114   else if (framecnt)
0115     frame_select = shot_select;
0116   else
0117     track_select = shot_select;
0118 
0119   int tracki = -1;
0120   for (int i = 0, trackcnt = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
0121   {
0122     if (bitcounts[i] == maxbitcount)
0123     {
0124       if (trackcnt <= (int)track_select)
0125         tracki = i;
0126       trackcnt++;
0127     }
0128   }
0129 
0130   if (tracki >= 0 && tracki < LIBRAW_CRXTRACKS_MAXCOUNT /* && frame_select > 0 */)
0131   {
0132       framecnt = framecounts[tracki]; // Update to selected track
0133       frame_select = LIM(frame_select, 0, framecnt);
0134       if(frame_select > 0)
0135         if (selectCRXFrame(tracki, frame_select))
0136               return;
0137   }
0138   else
0139       return; // No RAW track index
0140 
0141   // Frame selected: parse CTMD metadata
0142   for (int i = 0, trackcnt = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
0143   {
0144       crx_data_header_t *d = &libraw_internal_data.unpacker_data.crx_header[i];
0145       int fsel = LIM(frame_select, 0, d->sample_count);
0146       if (d->MediaType == 3) // CTMD metadata
0147       {
0148           /* ignore errors !*/
0149           if (fsel)
0150               selectCRXFrame(i, fsel);
0151           parseCR3_CTMD(i);
0152       }
0153       else if (d->MediaType == 2) // JPEG
0154       {
0155           if (fsel)
0156               selectCRXFrame(i, fsel);
0157           if (d->MediaSize > maxjpegbytes)
0158           {
0159               maxjpegbytes = d->MediaSize;
0160               thumb_offset = d->MediaOffset;
0161               thumb_length = d->MediaSize;
0162               if (imgdata.thumbs_list.thumbcount < LIBRAW_THUMBNAIL_MAXCOUNT)
0163               {
0164                 bool do_add = true;
0165                 for (int idx = 0; idx < imgdata.thumbs_list.thumbcount; idx++)
0166                   if (imgdata.thumbs_list.thumblist[idx].toffset == thumb_offset)
0167                   {
0168                     do_add = false;
0169                     break;
0170                   }
0171                 if (do_add)
0172                 {
0173                   int idx = imgdata.thumbs_list.thumbcount;
0174                   imgdata.thumbs_list.thumblist[idx].tformat = LIBRAW_INTERNAL_THUMBNAIL_JPEG;
0175                   imgdata.thumbs_list.thumblist[idx].toffset = thumb_offset;
0176                   imgdata.thumbs_list.thumblist[idx].tlength = thumb_length;
0177                   imgdata.thumbs_list.thumblist[idx].tflip = 0xffff;
0178                   imgdata.thumbs_list.thumblist[idx].tmisc = (3 << 5) | 8; // 3 samples/8 bps
0179                   imgdata.thumbs_list.thumblist[idx].twidth = 0;
0180                   imgdata.thumbs_list.thumblist[idx].theight = 0;
0181                   imgdata.thumbs_list.thumbcount++;
0182                 }
0183               }
0184           }
0185       }
0186   }
0187 
0188   if (framecnt)
0189     is_raw = framecnt;
0190   else
0191     is_raw = media_tracks;
0192 
0193   if (tracki >= 0 && tracki < LIBRAW_CRXTRACKS_MAXCOUNT)
0194   {
0195     crx_data_header_t *d =
0196         &libraw_internal_data.unpacker_data.crx_header[tracki];
0197     data_offset = d->MediaOffset;
0198     data_size = d->MediaSize;
0199     raw_width = d->f_width;
0200     raw_height = d->f_height;
0201     load_raw = &LibRaw::crxLoadRaw;
0202     tiff_bps = d->encType == 3? d->medianBits : d->nBits;
0203     switch (d->cfaLayout)
0204     {
0205     case 0:
0206       filters = 0x94949494;
0207       break;
0208     case 1:
0209       filters = 0x61616161;
0210       break;
0211     case 2:
0212       filters = 0x49494949;
0213       break;
0214     case 3:
0215       filters = 0x16161616;
0216       break;
0217     }
0218 
0219     libraw_internal_data.unpacker_data.crx_track_selected = tracki;
0220 
0221     int tiff_idx = -1;
0222     INT64 tpixels = 0;
0223     for (unsigned i = 0; i < tiff_nifds && i < LIBRAW_IFD_MAXCOUNT; i++)
0224       if (INT64(tiff_ifd[i].t_height) * INT64(tiff_ifd[i].t_height) > tpixels)
0225       {
0226         tpixels = INT64(tiff_ifd[i].t_height) * INT64(tiff_ifd[i].t_height);
0227         tiff_idx = i;
0228       }
0229     if (tiff_idx >= 0)
0230       flip = tiff_ifd[tiff_idx].t_flip;
0231   }
0232 }
0233 
0234 #define bad_hdr()                                                              \
0235   (((order != 0x4d4d) && (order != 0x4949)) || (get2() != 0x002a) ||           \
0236    (get4() != 0x00000008))
0237 
0238 int LibRaw::parseCR3_CTMD(short trackNum)
0239 {
0240   int err = 0;
0241   short s_order = order;
0242   order = 0x4949;
0243   uint32_t relpos_inDir = 0;
0244   uint32_t relpos_inBox = 0;
0245   unsigned szItem, Tag, lTag;
0246   ushort tItem;
0247 
0248 #define track libraw_internal_data.unpacker_data.crx_header[trackNum]
0249 
0250   if (track.MediaType != 3)
0251   {
0252     err = -10;
0253     goto ctmd_fin;
0254   }
0255 
0256   while (relpos_inDir + 6 < track.MediaSize)
0257   {
0258     if (track.MediaOffset + relpos_inDir > ifp->size() - 6) // need at least 6 bytes
0259     {
0260         err = -11;
0261         goto ctmd_fin;
0262     }
0263     fseek(ifp, track.MediaOffset + relpos_inDir, SEEK_SET);
0264     szItem = get4();
0265     tItem = get2();
0266     if (szItem < 1 || (  (relpos_inDir + szItem) > track.MediaSize))
0267     {
0268       err = -11;
0269       goto ctmd_fin;
0270     }
0271     if ((tItem == 7) || (tItem == 8) || (tItem == 9))
0272     {
0273       relpos_inBox = relpos_inDir + 12L;
0274       while (relpos_inBox + 8 < relpos_inDir + szItem)
0275       {
0276         if (track.MediaOffset + relpos_inBox > ifp->size() - 8) // need at least 8 bytes
0277         {
0278             err = -11;
0279             goto ctmd_fin;
0280         }
0281         fseek(ifp, track.MediaOffset + relpos_inBox, SEEK_SET);
0282         lTag = get4();
0283         Tag = get4();
0284         if (lTag < 8)
0285         {
0286           err = -12;
0287           goto ctmd_fin;
0288         }
0289         else if ((relpos_inBox + lTag) > (relpos_inDir + szItem))
0290         {
0291           err = -11;
0292           goto ctmd_fin;
0293         }
0294         if ((Tag == 0x927c) && ((tItem == 7) || (tItem == 8)))
0295         {
0296           fseek(ifp, track.MediaOffset + relpos_inBox + 8L,
0297                 SEEK_SET);
0298           short q_order = order;
0299           order = get2();
0300           if (bad_hdr())
0301           {
0302             err = -13;
0303             goto ctmd_fin;
0304           }
0305           fseek(ifp, -8L, SEEK_CUR);
0306           libraw_internal_data.unpacker_data.CR3_CTMDtag = 1;
0307           parse_makernote(track.MediaOffset + relpos_inBox + 8,
0308                           0);
0309           libraw_internal_data.unpacker_data.CR3_CTMDtag = 0;
0310           order = q_order;
0311         }
0312         relpos_inBox += lTag;
0313       }
0314     }
0315     relpos_inDir += szItem;
0316   }
0317 
0318 ctmd_fin:
0319   order = s_order;
0320   return err;
0321 }
0322 #undef track
0323 
0324 int LibRaw::parseCR3(INT64 oAtomList,
0325                      INT64 szAtomList, short &nesting,
0326                      char *AtomNameStack, short &nTrack, short &TrackType)
0327 {
0328   /*
0329   Atom starts with 4 bytes for Atom size and 4 bytes containing Atom name
0330   Atom size includes the length of the header and the size of all "contained"
0331   Atoms if Atom size == 1, Atom has the extended size stored in 8 bytes located
0332   after the Atom name if Atom size == 0, it is the last top-level Atom extending
0333   to the end of the file Atom name is often a 4 symbol mnemonic, but can be a
0334   4-byte integer
0335   */
0336   const char UIID_Canon[17] =
0337       "\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48";
0338   const unsigned char UIID_CanonPreview[17] = "\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16";
0339   const unsigned char UUID_XMP[17] = "\xbe\x7a\xcf\xcb\x97\xa9\x42\xe8\x9c\x71\x99\x94\x91\xe3\xaf\xac";
0340   
0341   /*
0342   AtomType = 0 - unknown: "unk."
0343   AtomType = 1 - container atom: "cont"
0344   AtomType = 2 - leaf atom: "leaf"
0345   AtomType = 3 - can be container, can be leaf: "both"
0346   */
0347   short AtomType;
0348   static const struct
0349   {
0350     char AtomName[5];
0351     short AtomType;
0352   } AtomNamesList[] = {
0353       {"dinf", 1},
0354       {"edts", 1},
0355       {"fiin", 1},
0356       {"ipro", 1},
0357       {"iprp", 1},
0358       {"mdia", 1},
0359       {"meco", 1},
0360       {"mere", 1},
0361       {"mfra", 1},
0362       {"minf", 1},
0363       {"moof", 1},
0364       {"moov", 1},
0365       {"mvex", 1},
0366       {"paen", 1},
0367       {"schi", 1},
0368       {"sinf", 1},
0369       {"skip", 1},
0370       {"stbl", 1},
0371       {"stsd", 1},
0372       {"strk", 1},
0373       {"tapt", 1},
0374       {"traf", 1},
0375       {"trak", 1},
0376 
0377       {"cdsc", 2},
0378       {"colr", 2},
0379       {"dimg", 2},
0380       // {"dref", 2},
0381       {"free", 2},
0382       {"frma", 2},
0383       {"ftyp", 2},
0384       {"hdlr", 2},
0385       {"hvcC", 2},
0386       {"iinf", 2},
0387       {"iloc", 2},
0388       {"infe", 2},
0389       {"ipco", 2},
0390       {"ipma", 2},
0391       {"iref", 2},
0392       {"irot", 2},
0393       {"ispe", 2},
0394       {"meta", 2},
0395       {"mvhd", 2},
0396       {"pitm", 2},
0397       {"pixi", 2},
0398       {"schm", 2},
0399       {"thmb", 2},
0400       {"tkhd", 2},
0401       {"url ", 2},
0402       {"urn ", 2},
0403 
0404       {"CCTP", 1},
0405       {"CRAW", 1},
0406 
0407       {"JPEG", 2},
0408       {"CDI1", 2},
0409       {"CMP1", 2},
0410 
0411       {"CNCV", 2},
0412       {"CCDT", 2},
0413       {"CTBO", 2},
0414       {"CMT1", 2},
0415       {"CMT2", 2},
0416       {"CMT3", 2},
0417       {"CMT4", 2},
0418       {"CNOP", 2},
0419       {"THMB", 2},
0420       {"co64", 2},
0421       {"mdat", 2},
0422       {"mdhd", 2},
0423       {"nmhd", 2},
0424       {"stsc", 2},
0425       {"stsz", 2},
0426       {"stts", 2},
0427       {"vmhd", 2},
0428 
0429       {"dref", 3},
0430       {"uuid", 3},
0431   };
0432 
0433   const char sHandlerType[5][5] = {"unk.", "soun", "vide", "hint", "meta"};
0434 
0435   int c, err=0;
0436 
0437   ushort tL;                        // Atom length represented in 4 or 8 bytes
0438   char nmAtom[5];                   // Atom name
0439   INT64 oAtom, szAtom; // Atom offset and Atom size
0440   INT64 oAtomContent,
0441       szAtomContent; // offset and size of Atom content
0442   INT64 lHdr;
0443 
0444   char UIID[16];
0445   uchar CMP1[85];
0446   uchar CDI1[60];
0447   char HandlerType[5], MediaFormatID[5];
0448   uint32_t relpos_inDir, relpos_inBox;
0449   unsigned szItem, Tag, lTag;
0450   ushort tItem;
0451 
0452   nmAtom[0] = MediaFormatID[0] = nmAtom[4] = MediaFormatID[4] = '\0';
0453   strcpy(HandlerType, sHandlerType[0]);
0454   oAtom = oAtomList;
0455   nesting++;
0456   if (nesting > 31)
0457     return -14; // too deep nesting
0458   short s_order = order;
0459 
0460   while ((oAtom + 8LL) <= (oAtomList + szAtomList))
0461   {
0462     lHdr = 0ULL;
0463     err = 0;
0464     order = 0x4d4d;
0465     fseek(ifp, oAtom, SEEK_SET);
0466     szAtom = get4();
0467     FORC4 nmAtom[c] = AtomNameStack[nesting * 4 + c] = fgetc(ifp);
0468     AtomNameStack[(nesting + 1) * 4] = '\0';
0469     tL = 4;
0470     AtomType = 0;
0471 
0472     for (c = 0; c < int(sizeof AtomNamesList / sizeof *AtomNamesList); c++)
0473       if (!strcmp(nmAtom, AtomNamesList[c].AtomName))
0474       {
0475         AtomType = AtomNamesList[c].AtomType;
0476         break;
0477       }
0478 
0479     if (!AtomType)
0480     {
0481       err = 1;
0482     }
0483 
0484     if (szAtom == 0ULL)
0485     {
0486       if (nesting != 0)
0487       {
0488         err = -2;
0489         goto fin;
0490       }
0491       szAtom = szAtomList - oAtom;
0492       oAtomContent = oAtom + 8ULL;
0493       szAtomContent = szAtom - 8ULL;
0494     }
0495     else if (szAtom == 1LL)
0496     {
0497       if ((oAtom + 16LL) > (oAtomList + szAtomList))
0498       {
0499         err = -3;
0500         goto fin;
0501       }
0502       tL = 8;
0503       szAtom = (((unsigned long long)get4()) << 32) | get4();
0504       oAtomContent = oAtom + 16ULL;
0505       szAtomContent = szAtom - 16ULL;
0506     }
0507     else
0508     {
0509       oAtomContent = oAtom + 8ULL;
0510       szAtomContent = szAtom - 8ULL;
0511     }
0512 
0513     if (!strcmp(AtomNameStack, "uuid")) // Top level uuid
0514     {
0515         INT64 tt = ftell(ifp);
0516         lHdr = 16ULL;
0517         fread(UIID, 1, lHdr, ifp);
0518         if (!memcmp(UIID, UUID_XMP, 16) && szAtom > 24LL && szAtom < 1024000LL)
0519         {
0520             xmpdata = (char *)malloc(xmplen = unsigned(szAtom - 23));
0521             fread(xmpdata, szAtom - 24, 1, ifp);
0522             xmpdata[szAtom - 24] = 0;
0523         }
0524         else if (!memcmp(UIID, UIID_CanonPreview, 16) && szAtom > 48LL && szAtom < 100LL * 1024000LL)
0525         {
0526             // read next 48 bytes, check for 'PRVW'
0527             unsigned char xdata[32];
0528             fread(xdata, 32, 1, ifp);   
0529             if (!memcmp(xdata + 12, "PRVW", 4))
0530             {
0531                 thumb_length = unsigned(szAtom - 56);
0532                 thumb_offset = ftell(ifp);
0533                 if (imgdata.thumbs_list.thumbcount < LIBRAW_THUMBNAIL_MAXCOUNT)
0534                 {
0535                     bool do_add = true;
0536                     for(int idx = 0; idx < imgdata.thumbs_list.thumbcount; idx++)
0537                         if (imgdata.thumbs_list.thumblist[idx].toffset == thumb_offset)
0538                         {
0539                             do_add = false;
0540                             break;
0541                         }
0542                     if (do_add)
0543                     {
0544                         int idx = imgdata.thumbs_list.thumbcount;
0545                         imgdata.thumbs_list.thumblist[idx].tformat = LIBRAW_INTERNAL_THUMBNAIL_JPEG;
0546                         imgdata.thumbs_list.thumblist[idx].toffset = thumb_offset;
0547                         imgdata.thumbs_list.thumblist[idx].tlength = thumb_length;
0548                         imgdata.thumbs_list.thumblist[idx].tflip = 0xffff;
0549                         imgdata.thumbs_list.thumblist[idx].tmisc = (3 << 5) | 8; // 3 samples/8 bps
0550                         imgdata.thumbs_list.thumblist[idx].twidth = (xdata[22] << 8) + xdata[23];
0551                         imgdata.thumbs_list.thumblist[idx].theight = (xdata[24] << 8) + xdata[25];
0552                         imgdata.thumbs_list.thumbcount++;
0553                     }
0554                 }
0555 
0556             }
0557         }
0558         fseek(ifp, tt, SEEK_SET);
0559     }
0560 
0561     if (!strcmp(nmAtom, "trak"))
0562     {
0563       nTrack++;
0564       TrackType = 0;
0565       if (nTrack >= LIBRAW_CRXTRACKS_MAXCOUNT)
0566         break;
0567     }
0568     if (!strcmp(AtomNameStack, "moovuuid"))
0569     {
0570       lHdr = 16ULL;
0571       fread(UIID, 1, lHdr, ifp);
0572       if (!strncmp(UIID, UIID_Canon, lHdr))
0573       {
0574         AtomType = 1;
0575       }
0576       else
0577         fseek(ifp, -lHdr, SEEK_CUR);
0578     }
0579     else if (!strcmp(AtomNameStack, "moovuuidCCTP"))
0580     {
0581       lHdr = 12ULL;
0582     }
0583     else if (!strcmp(AtomNameStack, "moovuuidCMT1"))
0584     {
0585       short q_order = order;
0586       order = get2();
0587       if ((tL != 4) || bad_hdr())
0588       {
0589         err = -4;
0590         goto fin;
0591       }
0592       if (!libraw_internal_data.unpacker_data.cr3_ifd0_length)
0593         libraw_internal_data.unpacker_data.cr3_ifd0_length = unsigned(szAtomContent);
0594       parse_tiff_ifd(oAtomContent);
0595       order = q_order;
0596     }
0597     else if (!strcmp(AtomNameStack, "moovuuidTHMB") && szAtom > 24)
0598     {
0599         unsigned char xdata[16];
0600         fread(xdata, 16, 1, ifp);
0601         INT64 xoffset = ftell(ifp);
0602         if (imgdata.thumbs_list.thumbcount < LIBRAW_THUMBNAIL_MAXCOUNT)
0603         {
0604             bool do_add = true;
0605             for (int idx = 0; idx < imgdata.thumbs_list.thumbcount; idx++)
0606                 if (imgdata.thumbs_list.thumblist[idx].toffset == xoffset)
0607                 {
0608                     do_add = false;
0609                     break;
0610                 }
0611             if (do_add)
0612             {
0613               int idx = imgdata.thumbs_list.thumbcount;
0614               imgdata.thumbs_list.thumblist[idx].tformat = LIBRAW_INTERNAL_THUMBNAIL_JPEG;
0615               imgdata.thumbs_list.thumblist[idx].toffset = xoffset;
0616               imgdata.thumbs_list.thumblist[idx].tlength = szAtom-24;
0617               imgdata.thumbs_list.thumblist[idx].tflip = 0xffff;
0618               imgdata.thumbs_list.thumblist[idx].tmisc = (3 << 5) | 8; // 3 samples/8 bps
0619               imgdata.thumbs_list.thumblist[idx].twidth = (xdata[4] << 8) + xdata[5];
0620               imgdata.thumbs_list.thumblist[idx].theight = (xdata[6] << 8) + xdata[7];
0621               imgdata.thumbs_list.thumbcount++;
0622             }
0623         }
0624     }
0625     else if (!strcmp(AtomNameStack, "moovuuidCMT2"))
0626     {
0627         short q_order = order;
0628         order = get2();
0629         if ((tL != 4) || bad_hdr())
0630         {
0631             err = -5;
0632             goto fin;
0633         }
0634         if (!libraw_internal_data.unpacker_data.cr3_exif_length)
0635             libraw_internal_data.unpacker_data.cr3_exif_length = unsigned(szAtomContent); 
0636       parse_exif(oAtomContent);
0637       order = q_order;
0638     }
0639     else if (!strcmp(AtomNameStack, "moovuuidCMT3"))
0640     {
0641       short q_order = order;
0642       order = get2();
0643       if ((tL != 4) || bad_hdr())
0644       {
0645         err = -6;
0646         goto fin;
0647       }
0648       fseek(ifp, -12L, SEEK_CUR);
0649       parse_makernote(oAtomContent, 0);
0650       order = q_order;
0651     }
0652     else if (!strcmp(AtomNameStack, "moovuuidCMT4"))
0653     {
0654       short q_order = order;
0655       order = get2();
0656       if ((tL != 4) || bad_hdr())
0657       {
0658         err = -6;
0659         goto fin;
0660       }
0661       INT64 off = ftell(ifp);
0662       parse_gps(oAtomContent);
0663       fseek(ifp, off, SEEK_SET);
0664       parse_gps_libraw(oAtomContent);
0665       order = q_order;
0666     }
0667     else if (!strcmp(AtomNameStack, "moovtrakmdiahdlr"))
0668     {
0669       fseek(ifp, 8L, SEEK_CUR);
0670       FORC4 HandlerType[c] = fgetc(ifp);
0671       for (c = 1; c < int(sizeof sHandlerType / sizeof *sHandlerType); c++)
0672         if (!strcmp(HandlerType, sHandlerType[c]))
0673         {
0674           TrackType = c;
0675           break;
0676         }
0677     }
0678     else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsd"))
0679     {
0680       if (szAtomContent >= 16)
0681       {
0682         fseek(ifp, 12L, SEEK_CUR);
0683         lHdr = 8;
0684       }
0685       else
0686       {
0687         err = -7;
0688         goto fin;
0689       }
0690       FORC4 MediaFormatID[c] = fgetc(ifp);
0691       if ((TrackType == 2) && (!strcmp(MediaFormatID, "CRAW")))
0692       {
0693         if (szAtomContent >= 44)
0694           fseek(ifp, 24L, SEEK_CUR);
0695         else
0696         {
0697           err = -8;
0698           goto fin;
0699         }
0700       }
0701       else
0702       {
0703         AtomType = 2; // only continue for CRAW
0704         lHdr = 0;
0705       }
0706 #define current_track libraw_internal_data.unpacker_data.crx_header[nTrack]
0707 
0708       /*ImageWidth =*/ get2();
0709       /*ImageHeight =*/ get2();
0710     }
0711     else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAW"))
0712     {
0713       lHdr = 82;
0714     }
0715     else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWCMP1"))
0716     {
0717       int read_size = szAtomContent > 85 ? 85 : szAtomContent;
0718       if (szAtomContent >= 40)
0719         fread(CMP1, 1, read_size, ifp);
0720       else
0721       {
0722         err = -7;
0723         goto fin;
0724       }
0725       if (!crxParseImageHeader(CMP1, nTrack, read_size))
0726         current_track.MediaType = 1;
0727     }
0728 
0729     else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWCDI1")) {
0730       if (szAtomContent >= 60) {
0731         fread(CDI1, 1, 60, ifp);
0732         if (!strncmp((char *)CDI1+8, "IAD1", 4) && (sgetn(8, CDI1) == 0x38)) {
0733           // sensor area at CDI1+12, 4 16-bit values
0734           // Bayer pattern? - next 4 16-bit values
0735           imCanon.RecommendedImageArea = sget_CanonArea(CDI1+12 + 2*4*2);
0736           imCanon.LeftOpticalBlack     = sget_CanonArea(CDI1+12 + 3*4*2);
0737           imCanon.UpperOpticalBlack    = sget_CanonArea(CDI1+12 + 4*4*2);
0738           imCanon.ActiveArea           = sget_CanonArea(CDI1+12 + 5*4*2);
0739         }
0740       }
0741     }
0742 
0743     else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWJPEG"))
0744     {
0745       current_track.MediaType = 2;
0746     }
0747     else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsc"))
0748     {
0749       if (szAtomContent >= 12) {
0750         fseek(ifp, 4L, SEEK_CUR);
0751         int entries = get4();
0752         if (entries < 1 || entries > 1000000)
0753         {
0754           err =  -9;
0755           goto fin;
0756         }
0757 
0758         current_track.stsc_data = (crx_sample_to_chunk_t*) malloc(entries * sizeof(crx_sample_to_chunk_t));
0759         if(!current_track.stsc_data)
0760         {
0761           err =  -9;
0762           goto fin;
0763         }
0764         current_track.stsc_count = entries;
0765         for(int i = 0; i < entries; i++)
0766         {
0767           current_track.stsc_data[i].first = get4();
0768           current_track.stsc_data[i].count = get4();
0769           current_track.stsc_data[i].id = get4();
0770         }
0771       }
0772     }
0773     else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsz"))
0774     {
0775       if (szAtomContent >= 12)
0776       {
0777         fseek(ifp, 4L, SEEK_CUR);
0778         int sample_size = get4();
0779         int entries = get4();
0780         current_track.sample_count = entries;
0781 
0782         // if sample size is zero sample size is fixed
0783         if (sample_size)
0784         {
0785            current_track.MediaSize = sample_size;
0786            current_track.sample_size = sample_size;
0787         }
0788         else
0789         {
0790           current_track.sample_size = 0;
0791           if (entries < 1 || entries > 1000000) {
0792             err = -10;
0793             goto fin;
0794           }
0795           current_track.sample_sizes = (int32_t*)malloc(entries * sizeof(int32_t));
0796           if (!current_track.sample_sizes)
0797           {
0798             err = -10;
0799             goto fin;
0800           }
0801           for (int i = 0; i < entries; i++)
0802             current_track.sample_sizes[i] = get4();
0803 
0804           current_track.MediaSize = current_track.sample_sizes[0];
0805         }
0806       }
0807     }
0808     else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblco64"))
0809     {
0810       if (szAtomContent >= 16) {
0811         fseek(ifp, 4L, SEEK_CUR);
0812         uint32_t entries = get4();
0813         int i;
0814         if (entries < 1 || entries > 1000000)
0815         {
0816           err = -11;
0817           goto fin;
0818         }
0819         current_track.chunk_offsets = (INT64*)malloc(entries * sizeof(int64_t));
0820         if(!current_track.chunk_offsets)
0821         {
0822           err = -11;
0823           goto fin;
0824         }
0825 
0826         current_track.chunk_count = entries;
0827         for (i = 0; i < entries; i++)
0828           current_track.chunk_offsets[i] = (((int64_t)get4()) << 32) | get4();
0829 
0830         current_track.chunk_count = i;
0831         current_track.MediaOffset =  current_track.chunk_offsets[0];
0832       }
0833     }
0834 
0835     if (nTrack >= 0 && nTrack < LIBRAW_CRXTRACKS_MAXCOUNT &&
0836         current_track.MediaSize && current_track.MediaOffset &&
0837         ((oAtom + szAtom) >= (oAtomList + szAtomList)) &&
0838         !strncmp(AtomNameStack, "moovtrakmdiaminfstbl", 20))
0839     {
0840       if ((TrackType == 4) && (!strcmp(MediaFormatID, "CTMD")))
0841       {
0842         current_track.MediaType = 3;
0843       }
0844     }
0845 #undef current_track
0846     if (AtomType == 1)
0847     {
0848       err = parseCR3(oAtomContent + lHdr, szAtomContent - lHdr, nesting,
0849                      AtomNameStack, nTrack, TrackType);
0850       if (err)
0851         goto fin;
0852     }
0853     oAtom += szAtom;
0854   }
0855 
0856 fin:
0857   nesting--;
0858   if (nesting >= 0)
0859     AtomNameStack[nesting * 4] = '\0';
0860   order = s_order;
0861   return err;
0862 }
0863 #undef bad_hdr
0864 
0865 void LibRaw::parseCR3_Free()
0866 {
0867   short maxTrack = libraw_internal_data.unpacker_data.crx_track_count;
0868   if (maxTrack < 0)
0869     return;
0870 
0871   for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
0872   {
0873     crx_data_header_t *d = &libraw_internal_data.unpacker_data.crx_header[i];
0874     if (d->stsc_data)
0875     {
0876       free(d->stsc_data);
0877       d->stsc_data = NULL;
0878     }
0879     if (d->chunk_offsets)
0880     {
0881       free(d->chunk_offsets);
0882       d->chunk_offsets = NULL;
0883     }
0884 
0885     if (d->sample_sizes)
0886     {
0887       free(d->sample_sizes);
0888       d->sample_sizes = NULL;
0889     }
0890     d->stsc_count   = 0;
0891     d->sample_count = 0;
0892     d->sample_size  = 0;
0893     d->chunk_count  = 0;
0894   }
0895   libraw_internal_data.unpacker_data.crx_track_count = -1;
0896 }