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