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