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