1 /* -*- C++ -*-
2  * Copyright 2019-2020 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 
selectCRXTrack(short maxTrack)18 void LibRaw::selectCRXTrack(short maxTrack)
19 {
20   if (maxTrack < 0)
21     return;
22   INT64 bitcounts[LIBRAW_CRXTRACKS_MAXCOUNT], maxbitcount = 0;
23   uint32_t maxjpegbytes = 0;
24   memset(bitcounts, 0, sizeof(bitcounts));
25   for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
26   {
27     crx_data_header_t *d = &libraw_internal_data.unpacker_data.crx_header[i];
28     if (d->MediaType == 1) // RAW
29     {
30       bitcounts[i] = INT64(d->nBits) * INT64(d->f_width) * INT64(d->f_height);
31       if (bitcounts[i] > maxbitcount)
32         maxbitcount = bitcounts[i];
33     }
34     else if (d->MediaType == 2) // JPEG
35     {
36       if (d->MediaSize > maxjpegbytes)
37       {
38         maxjpegbytes = d->MediaSize;
39         thumb_offset = d->MediaOffset;
40         thumb_length = d->MediaSize;
41       }
42     }
43   }
44   if (maxbitcount < 8)
45     return;
46   int framei = -1, framecnt = 0;
47   for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
48   {
49     if (bitcounts[i] == maxbitcount)
50     {
51       if (framecnt <= (int)shot_select)
52         framei = i;
53       framecnt++;
54     }
55   }
56   is_raw = framecnt;
57   if (framei >= 0 && framei < LIBRAW_CRXTRACKS_MAXCOUNT)
58   {
59     crx_data_header_t *d =
60         &libraw_internal_data.unpacker_data.crx_header[framei];
61     data_offset = d->MediaOffset;
62     data_size = d->MediaSize;
63     raw_width = d->f_width;
64     raw_height = d->f_height;
65     load_raw = &LibRaw::crxLoadRaw;
66     switch (d->cfaLayout)
67     {
68     case 0:
69       filters = 0x94949494;
70       break;
71     case 1:
72       filters = 0x61616161;
73       break;
74     case 2:
75       filters = 0x49494949;
76       break;
77     case 3:
78       filters = 0x16161616;
79       break;
80     }
81 
82     libraw_internal_data.unpacker_data.crx_track_selected = framei;
83 
84     int tiff_idx = -1;
85     INT64 tpixels = 0;
86     for (unsigned i = 0; i < tiff_nifds && i < LIBRAW_IFD_MAXCOUNT; i++)
87       if (INT64(tiff_ifd[i].t_height) * INT64(tiff_ifd[i].t_height) > tpixels)
88       {
89         tpixels = INT64(tiff_ifd[i].t_height) * INT64(tiff_ifd[i].t_height);
90         tiff_idx = i;
91       }
92     if (tiff_idx >= 0)
93       flip = tiff_ifd[tiff_idx].t_flip;
94   }
95 }
96 
97 #define bad_hdr                                                                \
98   (((order != 0x4d4d) && (order != 0x4949)) || (get2() != 0x002a) ||           \
99    (get4() != 0x00000008))
parseCR3(unsigned long long oAtomList,unsigned long long szAtomList,short & nesting,char * AtomNameStack,short & nTrack,short & TrackType)100 int LibRaw::parseCR3(unsigned long long oAtomList,
101                      unsigned long long szAtomList, short &nesting,
102                      char *AtomNameStack, short &nTrack, short &TrackType)
103 {
104   /*
105   Atom starts with 4 bytes for Atom size and 4 bytes containing Atom name
106   Atom size includes the length of the header and the size of all "contained"
107   Atoms if Atom size == 1, Atom has the extended size stored in 8 bytes located
108   after the Atom name if Atom size == 0, it is the last top-level Atom extending
109   to the end of the file Atom name is often a 4 symbol mnemonic, but can be a
110   4-byte integer
111   */
112   const char UIID_Canon[17] =
113       "\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48";
114 
115   /*
116   AtomType = 0 - unknown: "unk."
117   AtomType = 1 - container atom: "cont"
118   AtomType = 2 - leaf atom: "leaf"
119   AtomType = 3 - can be container, can be leaf: "both"
120   */
121   short AtomType;
122   static const struct
123   {
124     char AtomName[5];
125     short AtomType;
126   } AtomNamesList[] = {
127       {"dinf", 1},
128       {"edts", 1},
129       {"fiin", 1},
130       {"ipro", 1},
131       {"iprp", 1},
132       {"mdia", 1},
133       {"meco", 1},
134       {"mere", 1},
135       {"mfra", 1},
136       {"minf", 1},
137       {"moof", 1},
138       {"moov", 1},
139       {"mvex", 1},
140       {"paen", 1},
141       {"schi", 1},
142       {"sinf", 1},
143       {"skip", 1},
144       {"stbl", 1},
145       {"stsd", 1},
146       {"strk", 1},
147       {"tapt", 1},
148       {"traf", 1},
149       {"trak", 1},
150 
151       {"cdsc", 2},
152       {"colr", 2},
153       {"dimg", 2},
154       // {"dref", 2},
155       {"free", 2},
156       {"frma", 2},
157       {"ftyp", 2},
158       {"hdlr", 2},
159       {"hvcC", 2},
160       {"iinf", 2},
161       {"iloc", 2},
162       {"infe", 2},
163       {"ipco", 2},
164       {"ipma", 2},
165       {"iref", 2},
166       {"irot", 2},
167       {"ispe", 2},
168       {"meta", 2},
169       {"mvhd", 2},
170       {"pitm", 2},
171       {"pixi", 2},
172       {"schm", 2},
173       {"thmb", 2},
174       {"tkhd", 2},
175       {"url ", 2},
176       {"urn ", 2},
177 
178       {"CCTP", 1},
179       {"CRAW", 1},
180 
181       {"JPEG", 2},
182       {"CDI1", 2},
183       {"CMP1", 2},
184 
185       {"CNCV", 2},
186       {"CCDT", 2},
187       {"CTBO", 2},
188       {"CMT1", 2},
189       {"CMT2", 2},
190       {"CMT3", 2},
191       {"CMT4", 2},
192       {"THMB", 2},
193       {"co64", 2},
194       {"mdat", 2},
195       {"mdhd", 2},
196       {"nmhd", 2},
197       {"stsc", 2},
198       {"stsz", 2},
199       {"stts", 2},
200       {"vmhd", 2},
201 
202       {"dref", 3},
203       {"uuid", 3},
204   };
205 
206   const char sHandlerType[5][5] = {"unk.", "soun", "vide", "hint", "meta"};
207 
208   int c, err;
209 
210   ushort tL;                        // Atom length represented in 4 or 8 bytes
211   char nmAtom[5];                   // Atom name
212   unsigned long long oAtom, szAtom; // Atom offset and Atom size
213   unsigned long long oAtomContent,
214       szAtomContent; // offset and size of Atom content
215   unsigned long long lHdr;
216 
217   char UIID[16];
218   uchar CMP1[36];
219   char HandlerType[5], MediaFormatID[5];
220   uint32_t relpos_inDir, relpos_inBox;
221   unsigned szItem, Tag, lTag;
222   ushort tItem;
223 
224   nmAtom[0] = MediaFormatID[0] = nmAtom[4] = MediaFormatID[4] = '\0';
225   strcpy(HandlerType, sHandlerType[0]);
226   oAtom = oAtomList;
227   nesting++;
228   if (nesting > 31)
229     return -14; // too deep nesting
230   short s_order = order;
231 
232   while ((oAtom + 8ULL) <= (oAtomList + szAtomList))
233   {
234     lHdr = 0ULL;
235     err = 0;
236     order = 0x4d4d;
237     fseek(ifp, oAtom, SEEK_SET);
238     szAtom = get4();
239     FORC4 nmAtom[c] = AtomNameStack[nesting * 4 + c] = fgetc(ifp);
240     AtomNameStack[(nesting + 1) * 4] = '\0';
241     tL = 4;
242     AtomType = 0;
243 
244     for (c = 0; c < int(sizeof AtomNamesList / sizeof *AtomNamesList); c++)
245       if (!strcmp(nmAtom, AtomNamesList[c].AtomName))
246       {
247         AtomType = AtomNamesList[c].AtomType;
248         break;
249       }
250 
251     if (!AtomType)
252     {
253       err = 1;
254     }
255 
256     if (szAtom == 0ULL)
257     {
258       if (nesting != 0)
259       {
260         err = -2;
261         goto fin;
262       }
263       szAtom = szAtomList - oAtom;
264       oAtomContent = oAtom + 8ULL;
265       szAtomContent = szAtom - 8ULL;
266     }
267     else if (szAtom == 1ULL)
268     {
269       if ((oAtom + 16ULL) > (oAtomList + szAtomList))
270       {
271         err = -3;
272         goto fin;
273       }
274       tL = 8;
275       szAtom = (((unsigned long long)get4()) << 32) | get4();
276       oAtomContent = oAtom + 16ULL;
277       szAtomContent = szAtom - 16ULL;
278     }
279     else
280     {
281       oAtomContent = oAtom + 8ULL;
282       szAtomContent = szAtom - 8ULL;
283     }
284 
285     if (!strcmp(nmAtom, "trak"))
286     {
287       nTrack++;
288       TrackType = 0;
289       if (nTrack >= LIBRAW_CRXTRACKS_MAXCOUNT)
290         break;
291     }
292     if (!strcmp(AtomNameStack, "moovuuid"))
293     {
294       lHdr = 16ULL;
295       fread(UIID, 1, lHdr, ifp);
296       if (!strncmp(UIID, UIID_Canon, lHdr))
297       {
298         AtomType = 1;
299       }
300       else
301         fseek(ifp, -lHdr, SEEK_CUR);
302     }
303     else if (!strcmp(AtomNameStack, "moovuuidCCTP"))
304     {
305       lHdr = 12ULL;
306     }
307     else if (!strcmp(AtomNameStack, "moovuuidCMT1"))
308     {
309       short q_order = order;
310       order = get2();
311       if ((tL != 4) || bad_hdr)
312       {
313         err = -4;
314         goto fin;
315       }
316       parse_tiff_ifd(oAtomContent);
317       order = q_order;
318     }
319     else if (!strcmp(AtomNameStack, "moovuuidCMT2"))
320     {
321       short q_order = order;
322       order = get2();
323       if ((tL != 4) || bad_hdr)
324       {
325         err = -5;
326         goto fin;
327       }
328       parse_exif(oAtomContent);
329       order = q_order;
330     }
331     else if (!strcmp(AtomNameStack, "moovuuidCMT3"))
332     {
333       short q_order = order;
334       order = get2();
335       if ((tL != 4) || bad_hdr)
336       {
337         err = -6;
338         goto fin;
339       }
340       fseek(ifp, -12L, SEEK_CUR);
341       parse_makernote(oAtomContent, 0);
342       order = q_order;
343     }
344     else if (!strcmp(AtomNameStack, "moovuuidCMT4"))
345     {
346       short q_order = order;
347       order = get2();
348       if ((tL != 4) || bad_hdr)
349       {
350         err = -6;
351         goto fin;
352       }
353       INT64 off = ftell(ifp);
354       parse_gps(oAtomContent);
355       fseek(ifp, off, SEEK_SET);
356       parse_gps_libraw(oAtomContent);
357       order = q_order;
358     }
359     else if (!strcmp(AtomNameStack, "moovtrakmdiahdlr"))
360     {
361       fseek(ifp, 8L, SEEK_CUR);
362       FORC4 HandlerType[c] = fgetc(ifp);
363       for (c = 1; c < int(sizeof sHandlerType / sizeof *sHandlerType); c++)
364         if (!strcmp(HandlerType, sHandlerType[c]))
365         {
366           TrackType = c;
367           break;
368         }
369     }
370     else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsd"))
371     {
372       if (szAtomContent >= 16)
373       {
374         fseek(ifp, 12L, SEEK_CUR);
375         lHdr = 8;
376       }
377       else
378       {
379         err = -7;
380         goto fin;
381       }
382       FORC4 MediaFormatID[c] = fgetc(ifp);
383       if ((TrackType == 2) && (!strcmp(MediaFormatID, "CRAW")))
384       {
385         if (szAtomContent >= 44)
386           fseek(ifp, 24L, SEEK_CUR);
387         else
388         {
389           err = -8;
390           goto fin;
391         }
392       }
393       else
394       {
395         AtomType = 2; // only continue for CRAW
396         lHdr = 0;
397       }
398 #define current_track libraw_internal_data.unpacker_data.crx_header[nTrack]
399 
400       /*ImageWidth =*/ get2();
401       /*ImageHeight =*/ get2();
402     }
403     else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAW"))
404     {
405       lHdr = 82;
406     }
407     else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWCMP1"))
408     {
409       if (szAtomContent >= 40)
410         fread(CMP1, 1, 36, ifp);
411       else
412       {
413         err = -7;
414         goto fin;
415       }
416       if (!crxParseImageHeader(CMP1, nTrack))
417         current_track.MediaType = 1;
418     }
419     else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWJPEG"))
420     {
421       current_track.MediaType = 2;
422     }
423     else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsz"))
424     {
425       if (szAtomContent == 12)
426         fseek(ifp, 4L, SEEK_CUR);
427       else if (szAtomContent == 16)
428         fseek(ifp, 12L, SEEK_CUR);
429       else
430       {
431         err = -9;
432         goto fin;
433       }
434       current_track.MediaSize = get4();
435     }
436     else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblco64"))
437     {
438       if (szAtomContent == 16)
439         fseek(ifp, 8L, SEEK_CUR);
440       else
441       {
442         err = -10;
443         goto fin;
444       }
445       current_track.MediaOffset = (((unsigned long long)get4()) << 32) | get4();
446     }
447 
448     if (nTrack >= 0 && nTrack < LIBRAW_CRXTRACKS_MAXCOUNT &&
449         current_track.MediaSize && current_track.MediaOffset &&
450         ((oAtom + szAtom) >= (oAtomList + szAtomList)) &&
451         !strncmp(AtomNameStack, "moovtrakmdiaminfstbl", 20))
452     {
453       if ((TrackType == 4) && (!strcmp(MediaFormatID, "CTMD")))
454       {
455         order = 0x4949;
456         relpos_inDir = 0L;
457         while (relpos_inDir + 6 < current_track.MediaSize)
458         {
459           if (current_track.MediaOffset + relpos_inDir > ifp->size() - 6) // need at least 6 bytes
460           {
461               err = -11;
462               goto fin;
463           }
464           fseek(ifp, current_track.MediaOffset + relpos_inDir, SEEK_SET);
465           szItem = get4();
466           tItem = get2();
467           if (szItem < 1 || (  (relpos_inDir + szItem) > current_track.MediaSize))
468           {
469             err = -11;
470             goto fin;
471           }
472           if ((tItem == 7) || (tItem == 8) || (tItem == 9))
473           {
474             relpos_inBox = relpos_inDir + 12L;
475             while (relpos_inBox + 8 < relpos_inDir + szItem)
476             {
477               if (current_track.MediaOffset + relpos_inBox > ifp->size() - 8) // need at least 8 bytes
478               {
479                   err = -11;
480                   goto fin;
481               }
482               fseek(ifp, current_track.MediaOffset + relpos_inBox, SEEK_SET);
483               lTag = get4();
484               Tag = get4();
485               if (lTag < 8)
486               {
487                 err = -12;
488                 goto fin;
489               }
490               else if ((relpos_inBox + lTag) > (relpos_inDir + szItem))
491               {
492                 err = -11;
493                 goto fin;
494               }
495               if ((Tag == 0x927c) && ((tItem == 7) || (tItem == 8)))
496               {
497                 fseek(ifp, current_track.MediaOffset + relpos_inBox + 8L,
498                       SEEK_SET);
499                 short q_order = order;
500                 order = get2();
501                 if (bad_hdr)
502                 {
503                   err = -13;
504                   goto fin;
505                 }
506                 fseek(ifp, -8L, SEEK_CUR);
507                 libraw_internal_data.unpacker_data.CR3_CTMDtag = 1;
508                 parse_makernote(current_track.MediaOffset + relpos_inBox + 8,
509                                 0);
510                 libraw_internal_data.unpacker_data.CR3_CTMDtag = 0;
511                 order = q_order;
512               }
513               relpos_inBox += lTag;
514             }
515           }
516           relpos_inDir += szItem;
517         }
518         order = 0x4d4d;
519       }
520     }
521 #undef current_track
522     if (AtomType == 1)
523     {
524       err = parseCR3(oAtomContent + lHdr, szAtomContent - lHdr, nesting,
525                      AtomNameStack, nTrack, TrackType);
526       if (err)
527         goto fin;
528     }
529     oAtom += szAtom;
530   }
531 
532 fin:
533   nesting--;
534   if (nesting >= 0)
535     AtomNameStack[nesting * 4] = '\0';
536   order = s_order;
537   return err;
538 }
539 #undef bad_hdr
540