1/*****************************************************************************/
2// Copyright 2006-2007 Adobe Systems Incorporated
3// All Rights Reserved.
4//
5// NOTICE: Adobe permits you to use, modify, and distribute this file in
6// accordance with the terms of the Adobe license agreement accompanying it.
7/*****************************************************************************/
8
9/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_info.cpp#1 $ */
10/* $DateTime: 2012/05/30 13:28:51 $ */
11/* $Change: 832332 $ */
12/* $Author: tknoll $ */
13
14/*****************************************************************************/
15
16#include "dng_info.h"
17
18#include "dng_camera_profile.h"
19#include "dng_exceptions.h"
20#include "dng_globals.h"
21#include "dng_host.h"
22#include "dng_tag_codes.h"
23#include "dng_parse_utils.h"
24#include "dng_safe_arithmetic.h"
25#include "dng_tag_types.h"
26#include "dng_tag_values.h"
27#include "dng_utils.h"
28
29/*****************************************************************************/
30
31dng_info::dng_info ()
32
33 : fTIFFBlockOffset (0)
34 , fTIFFBlockOriginalOffset (kDNGStreamInvalidOffset)
35 , fBigEndian (false)
36 , fMagic (0)
37 , fExif ()
38 , fShared ()
39 , fMainIndex (-1)
40 , fMaskIndex (-1)
41 , fIFDCount (0)
42 , fChainedIFDCount (0)
43 , fMakerNoteNextIFD (0)
44
45 {
46
47 }
48
49/*****************************************************************************/
50
51dng_info::~dng_info ()
52 {
53
54 }
55
56/*****************************************************************************/
57
58void dng_info::ValidateMagic ()
59 {
60
61 switch (fMagic)
62 {
63
64 case magicTIFF:
65 case magicExtendedProfile:
66 case magicRawCache:
67 case magicPanasonic:
68 case magicOlympusA:
69 case magicOlympusB:
70 {
71
72 return;
73
74 }
75
76 default:
77 {
78
79 #if qDNGValidate
80
81 ReportError ("Invalid TIFF magic number");
82
83 #endif
84
85 ThrowBadFormat ();
86
87 }
88
89 }
90
91 }
92
93/*****************************************************************************/
94
95void dng_info::ParseTag (dng_host &host,
96 dng_stream &stream,
97 dng_exif *exif,
98 dng_shared *shared,
99 dng_ifd *ifd,
100 uint32 parentCode,
101 uint32 tagCode,
102 uint32 tagType,
103 uint32 tagCount,
104 uint64 tagOffset,
105 int64 offsetDelta)
106 {
107
108 bool isSubIFD = parentCode >= tcFirstSubIFD &&
109 parentCode <= tcLastSubIFD;
110
111 bool isMainIFD = (parentCode == 0 || isSubIFD) &&
112 ifd &&
113 ifd->fUsesNewSubFileType &&
114 ifd->fNewSubFileType == sfMainImage;
115
116 // Panasonic RAW format stores private tags using tag codes < 254 in
117 // IFD 0. Redirect the parsing of these tags into a logical
118 // "PanasonicRAW" IFD.
119
120 // Panasonic is starting to use some higher numbers also (280..283).
121
122 if (fMagic == 85 && parentCode == 0 && (tagCode < tcNewSubFileType ||
123 (tagCode >= 280 && tagCode <= 283)))
124 {
125
126 parentCode = tcPanasonicRAW;
127
128 ifd = NULL;
129
130 }
131
132 stream.SetReadPosition (tagOffset);
133
134 if (ifd && ifd->ParseTag (stream,
135 parentCode,
136 tagCode,
137 tagType,
138 tagCount,
139 tagOffset))
140 {
141
142 return;
143
144 }
145
146 stream.SetReadPosition (tagOffset);
147
148 if (exif && shared && exif->ParseTag (stream,
149 *shared,
150 parentCode,
151 isMainIFD,
152 tagCode,
153 tagType,
154 tagCount,
155 tagOffset))
156 {
157
158 return;
159
160 }
161
162 stream.SetReadPosition (tagOffset);
163
164 if (shared && exif && shared->ParseTag (stream,
165 *exif,
166 parentCode,
167 isMainIFD,
168 tagCode,
169 tagType,
170 tagCount,
171 tagOffset,
172 offsetDelta))
173 {
174
175 return;
176
177 }
178
179 if (parentCode == tcLeicaMakerNote &&
180 tagType == ttUndefined &&
181 tagCount >= 14)
182 {
183
184 if (ParseMakerNoteIFD (host,
185 stream,
186 tagCount,
187 tagOffset,
188 offsetDelta,
189 tagOffset,
190 stream.Length (),
191 tcLeicaMakerNote))
192 {
193
194 return;
195
196 }
197
198 }
199
200 if (parentCode == tcOlympusMakerNote &&
201 tagType == ttUndefined &&
202 tagCount >= 14)
203 {
204
205 uint32 olympusMakerParent = 0;
206
207 switch (tagCode)
208 {
209
210 case 8208:
211 olympusMakerParent = tcOlympusMakerNote8208;
212 break;
213
214 case 8224:
215 olympusMakerParent = tcOlympusMakerNote8224;
216 break;
217
218 case 8240:
219 olympusMakerParent = tcOlympusMakerNote8240;
220 break;
221
222 case 8256:
223 olympusMakerParent = tcOlympusMakerNote8256;
224 break;
225
226 case 8272:
227 olympusMakerParent = tcOlympusMakerNote8272;
228 break;
229
230 case 12288:
231 olympusMakerParent = tcOlympusMakerNote12288;
232 break;
233
234 default:
235 break;
236
237 }
238
239 if (olympusMakerParent)
240 {
241
242 // Olympus made a mistake in some camera models in computing
243 // the size of these sub-tags, so we fudge the count.
244
245 if (ParseMakerNoteIFD (host,
246 stream,
247 stream.Length () - tagOffset,
248 tagOffset,
249 offsetDelta,
250 tagOffset,
251 stream.Length (),
252 olympusMakerParent))
253 {
254
255 return;
256
257 }
258
259 }
260
261 }
262
263 if (parentCode == tcRicohMakerNote &&
264 tagCode == 0x2001 &&
265 tagType == ttUndefined &&
266 tagCount > 22)
267 {
268
269 char header [20];
270
271 stream.SetReadPosition (tagOffset);
272
273 stream.Get (header, sizeof (header));
274
275 if (memcmp (header, "[Ricoh Camera Info]", 19) == 0)
276 {
277
278 ParseMakerNoteIFD (host,
279 stream,
280 tagCount - 20,
281 tagOffset + 20,
282 offsetDelta,
283 tagOffset + 20,
284 tagOffset + tagCount,
285 tcRicohMakerNoteCameraInfo);
286
287 return;
288
289 }
290
291 }
292
293 #if qDNGValidate
294
295 {
296
297 stream.SetReadPosition (tagOffset);
298
299 if (gVerbose)
300 {
301
302 printf ("*");
303
304 DumpTagValues (stream,
305 LookupTagType (tagType),
306 parentCode,
307 tagCode,
308 tagType,
309 tagCount);
310
311 }
312
313 // If type is ASCII, then parse anyway so we report any ASCII
314 // NULL termination or character set errors.
315
316 else if (tagType == ttAscii)
317 {
318
319 dng_string s;
320
321 ParseStringTag (stream,
322 parentCode,
323 tagCode,
324 tagCount,
325 s,
326 false);
327
328 }
329
330 }
331
332 #endif
333
334 }
335
336/*****************************************************************************/
337
338bool dng_info::ValidateIFD (dng_stream &stream,
339 uint64 ifdOffset,
340 int64 offsetDelta)
341 {
342
343 // Make sure we have a count.
344
345 if (ifdOffset + 2 > stream.Length ())
346 {
347 return false;
348 }
349
350 // Get entry count.
351
352 stream.SetReadPosition (ifdOffset);
353
354 uint32 ifdEntries = stream.Get_uint16 ();
355
356 if (ifdEntries < 1)
357 {
358 return false;
359 }
360
361 // Make sure we have room for all entries and next IFD link.
362
363 if (ifdOffset + 2 + ifdEntries * 12 + 4 > stream.Length ())
364 {
365 return false;
366 }
367
368 // Check each entry.
369
370 for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++)
371 {
372
373 stream.SetReadPosition (ifdOffset + 2 + tag_index * 12);
374
375 stream.Skip (2); // Ignore tag code.
376
377 uint32 tagType = stream.Get_uint16 ();
378 uint32 tagCount = stream.Get_uint32 ();
379
380 uint32 tag_type_size = TagTypeSize (tagType);
381
382 if (tag_type_size == 0)
383 {
384 return false;
385 }
386
387 uint32 tag_data_size = SafeUint32Mult(tagCount, tag_type_size);
388
389 if (tag_data_size > 4)
390 {
391
392 uint64 tagOffset = stream.Get_uint32 ();
393
394 tagOffset += offsetDelta;
395
396 if (SafeUint64Add(tagOffset, tag_data_size) > stream.Length())
397 {
398 return false;
399 }
400
401 }
402
403 }
404
405 return true;
406
407 }
408
409/*****************************************************************************/
410
411void dng_info::ParseIFD (dng_host &host,
412 dng_stream &stream,
413 dng_exif *exif,
414 dng_shared *shared,
415 dng_ifd *ifd,
416 uint64 ifdOffset,
417 int64 offsetDelta,
418 uint32 parentCode)
419 {
420
421 #if qDNGValidate
422
423 bool isMakerNote = (parentCode >= tcFirstMakerNoteIFD &&
424 parentCode <= tcLastMakerNoteIFD);
425
426 #endif
427
428 stream.SetReadPosition (ifdOffset);
429
430 if (ifd)
431 {
432 ifd->fThisIFD = ifdOffset;
433 }
434
435 uint32 ifdEntries = stream.Get_uint16 ();
436
437 #if qDNGValidate
438
439 if (gVerbose)
440 {
441
442 printf ("%s: Offset = %u, Entries = %u\n\n",
443 LookupParentCode (parentCode),
444 (unsigned) ifdOffset,
445 (unsigned) ifdEntries);
446
447 }
448
449 if ((ifdOffset & 1) && !isMakerNote)
450 {
451
452 char message [256];
453
454 sprintf (message,
455 "%s has odd offset (%u)",
456 LookupParentCode (parentCode),
457 (unsigned) ifdOffset);
458
459 ReportWarning (message);
460
461 }
462
463 #endif
464
465 uint32 prev_tag_code = 0;
466
467 for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++)
468 {
469
470 stream.SetReadPosition (ifdOffset + 2 + tag_index * 12);
471
472 uint32 tagCode = stream.Get_uint16 ();
473 uint32 tagType = stream.Get_uint16 ();
474
475 // Minolta 7D files have a bug in the EXIF block where the count
476 // is wrong, and we run off into next IFD link. So if abort parsing
477 // if we get a zero code/type combinations.
478
479 if (tagCode == 0 && tagType == 0)
480 {
481
482 #if qDNGValidate
483
484 char message [256];
485
486 sprintf (message,
487 "%s had zero/zero tag code/type entry",
488 LookupParentCode (parentCode));
489
490 ReportWarning (message);
491
492 #endif
493
494 return;
495
496 }
497
498 uint32 tagCount = stream.Get_uint32 ();
499
500 #if qDNGValidate
501
502 {
503
504 if (tag_index > 0 && tagCode <= prev_tag_code && !isMakerNote)
505 {
506
507 char message [256];
508
509 sprintf (message,
510 "%s tags are not sorted in ascending numerical order",
511 LookupParentCode (parentCode));
512
513 ReportWarning (message);
514
515 }
516
517 }
518
519 #endif
520
521 prev_tag_code = tagCode;
522
523 uint32 tag_type_size = TagTypeSize (tagType);
524
525 if (tag_type_size == 0)
526 {
527
528 #if qDNGValidate
529
530 {
531
532 char message [256];
533
534 sprintf (message,
535 "%s %s has unknown type (%u)",
536 LookupParentCode (parentCode),
537 LookupTagCode (parentCode, tagCode),
538 (unsigned) tagType);
539
540 ReportWarning (message);
541
542 }
543
544 #endif
545
546 continue;
547
548 }
549
550 uint64 tagOffset = ifdOffset + 2 + tag_index * 12 + 8;
551
552 if (SafeUint32Mult(tagCount, tag_type_size) > 4)
553 {
554
555 tagOffset = stream.Get_uint32 ();
556
557 #if qDNGValidate
558
559 {
560
561 if (!(ifdOffset & 1) &&
562 (tagOffset & 1) &&
563 !isMakerNote &&
564 parentCode != tcKodakDCRPrivateIFD &&
565 parentCode != tcKodakKDCPrivateIFD)
566 {
567
568 char message [256];
569
570 sprintf (message,
571 "%s %s has odd data offset (%u)",
572 LookupParentCode (parentCode),
573 LookupTagCode (parentCode, tagCode),
574 (unsigned) tagOffset);
575
576 ReportWarning (message);
577
578 }
579
580 }
581
582 #endif
583
584 tagOffset += offsetDelta;
585
586 stream.SetReadPosition (tagOffset);
587
588 }
589
590 ParseTag (host,
591 stream,
592 exif,
593 shared,
594 ifd,
595 parentCode,
596 tagCode,
597 tagType,
598 tagCount,
599 tagOffset,
600 offsetDelta);
601
602 }
603
604 stream.SetReadPosition (ifdOffset + 2 + ifdEntries * 12);
605
606 uint32 nextIFD = stream.Get_uint32 ();
607
608 #if qDNGValidate
609
610 if (gVerbose)
611 {
612 printf ("NextIFD = %u\n", (unsigned) nextIFD);
613 }
614
615 #endif
616
617 if (ifd)
618 {
619 ifd->fNextIFD = nextIFD;
620 }
621
622 #if qDNGValidate
623
624 if (nextIFD)
625 {
626
627 if (parentCode != 0 &&
628 (parentCode < tcFirstChainedIFD ||
629 parentCode > tcLastChainedIFD ))
630 {
631
632 char message [256];
633
634 sprintf (message,
635 "%s has an unexpected non-zero NextIFD (%u)",
636 LookupParentCode (parentCode),
637 (unsigned) nextIFD);
638
639 ReportWarning (message);
640
641 }
642
643 }
644
645 if (gVerbose)
646 {
647 printf ("\n");
648 }
649
650 #endif
651
652 }
653
654/*****************************************************************************/
655
656bool dng_info::ParseMakerNoteIFD (dng_host &host,
657 dng_stream &stream,
658 uint64 ifdSize,
659 uint64 ifdOffset,
660 int64 offsetDelta,
661 uint64 minOffset,
662 uint64 maxOffset,
663 uint32 parentCode)
664 {
665
666 uint32 tagIndex;
667 uint32 tagCode;
668 uint32 tagType;
669 uint32 tagCount;
670
671 // Assume there is no next IFD pointer.
672
673 fMakerNoteNextIFD = 0;
674
675 // If size is too small to hold a single entry IFD, abort.
676
677 if (ifdSize < 14)
678 {
679 return false;
680 }
681
682 // Get entry count.
683
684 stream.SetReadPosition (ifdOffset);
685
686 uint32 ifdEntries = stream.Get_uint16 ();
687
688 // Make the entry count if reasonable for the MakerNote size.
689
690 if (ifdEntries < 1 || 2 + ifdEntries * 12 > ifdSize)
691 {
692 return false;
693 }
694
695 // Scan IFD to verify all the tag types are all valid.
696
697 for (tagIndex = 0; tagIndex < ifdEntries; tagIndex++)
698 {
699
700 stream.SetReadPosition (ifdOffset + 2 + tagIndex * 12 + 2);
701
702 tagType = stream.Get_uint16 ();
703
704 // Kludge: Some Canon MakerNotes contain tagType = 0 tags, so we
705 // need to ignore them. This was a "firmware 1.0.4" Canon 40D raw file.
706
707 if (parentCode == tcCanonMakerNote && tagType == 0)
708 {
709 continue;
710 }
711
712 if (TagTypeSize (tagType) == 0)
713 {
714 return false;
715 }
716
717 }
718
719 // OK, the IFD looks reasonable enough to parse.
720
721 #if qDNGValidate
722
723 if (gVerbose)
724 {
725
726 printf ("%s: Offset = %u, Entries = %u\n\n",
727 LookupParentCode (parentCode),
728 (unsigned) ifdOffset,
729 (unsigned) ifdEntries);
730
731 }
732
733 #endif
734
735 for (tagIndex = 0; tagIndex < ifdEntries; tagIndex++)
736 {
737
738 stream.SetReadPosition (ifdOffset + 2 + tagIndex * 12);
739
740 tagCode = stream.Get_uint16 ();
741 tagType = stream.Get_uint16 ();
742 tagCount = stream.Get_uint32 ();
743
744 if (tagType == 0)
745 {
746 continue;
747 }
748
749 uint32 tagSize = SafeUint32Mult(tagCount, TagTypeSize (tagType));
750
751 uint64 tagOffset = ifdOffset + 2 + tagIndex * 12 + 8;
752
753 if (tagSize > 4)
754 {
755
756 tagOffset = stream.Get_uint32 () + offsetDelta;
757
758 if (tagOffset < minOffset ||
759 SafeUint64Add(tagOffset, tagSize) > maxOffset)
760 {
761
762 // Tag data is outside the valid offset range,
763 // so ignore this tag.
764
765 continue;
766
767 }
768
769 stream.SetReadPosition (tagOffset);
770
771 }
772
773 // Olympus switched to using IFDs in version 3 makernotes.
774
775 if (parentCode == tcOlympusMakerNote &&
776 tagType == ttIFD &&
777 tagCount == 1)
778 {
779
780 uint32 olympusMakerParent = 0;
781
782 switch (tagCode)
783 {
784
785 case 8208:
786 olympusMakerParent = tcOlympusMakerNote8208;
787 break;
788
789 case 8224:
790 olympusMakerParent = tcOlympusMakerNote8224;
791 break;
792
793 case 8240:
794 olympusMakerParent = tcOlympusMakerNote8240;
795 break;
796
797 case 8256:
798 olympusMakerParent = tcOlympusMakerNote8256;
799 break;
800
801 case 8272:
802 olympusMakerParent = tcOlympusMakerNote8272;
803 break;
804
805 case 12288:
806 olympusMakerParent = tcOlympusMakerNote12288;
807 break;
808
809 default:
810 break;
811
812 }
813
814 if (olympusMakerParent)
815 {
816
817 stream.SetReadPosition (tagOffset);
818
819 uint64 subMakerNoteOffset = stream.Get_uint32 () + offsetDelta;
820
821 if (subMakerNoteOffset >= minOffset &&
822 subMakerNoteOffset < maxOffset)
823 {
824
825 if (ParseMakerNoteIFD (host,
826 stream,
827 maxOffset - subMakerNoteOffset,
828 subMakerNoteOffset,
829 offsetDelta,
830 minOffset,
831 maxOffset,
832 olympusMakerParent))
833 {
834
835 continue;
836
837 }
838
839 }
840
841 }
842
843 stream.SetReadPosition (tagOffset);
844
845 }
846
847 ParseTag (host,
848 stream,
849 fExif.Get (),
850 fShared.Get (),
851 NULL,
852 parentCode,
853 tagCode,
854 tagType,
855 tagCount,
856 tagOffset,
857 offsetDelta);
858
859 }
860
861 // Grab next IFD pointer, for possible use.
862
863 if (ifdSize >= 2 + ifdEntries * 12 + 4)
864 {
865
866 stream.SetReadPosition (ifdOffset + 2 + ifdEntries * 12);
867
868 fMakerNoteNextIFD = stream.Get_uint32 ();
869
870 }
871
872 #if qDNGValidate
873
874 if (gVerbose)
875 {
876 printf ("\n");
877 }
878
879 #endif
880
881 return true;
882
883 }
884
885/*****************************************************************************/
886
887void dng_info::ParseMakerNote (dng_host &host,
888 dng_stream &stream,
889 uint32 makerNoteCount,
890 uint64 makerNoteOffset,
891 int64 offsetDelta,
892 uint64 minOffset,
893 uint64 maxOffset)
894 {
895
896 uint8 firstBytes [16];
897
898 memset (firstBytes, 0, sizeof (firstBytes));
899
900 stream.SetReadPosition (makerNoteOffset);
901
902 stream.Get (firstBytes, (uint32) Min_uint64 (sizeof (firstBytes),
903 makerNoteCount));
904
905 // Epson MakerNote with header.
906
907 if (memcmp (firstBytes, "EPSON\000\001\000", 8) == 0)
908 {
909
910 if (makerNoteCount > 8)
911 {
912
913 ParseMakerNoteIFD (host,
914 stream,
915 makerNoteCount - 8,
916 makerNoteOffset + 8,
917 offsetDelta,
918 minOffset,
919 maxOffset,
920 tcEpsonMakerNote);
921
922 }
923
924 return;
925
926 }
927
928 // Fujifilm MakerNote.
929
930 if (memcmp (firstBytes, "FUJIFILM", 8) == 0)
931 {
932
933 stream.SetReadPosition (makerNoteOffset + 8);
934
935 TempLittleEndian tempEndian (stream);
936
937 uint32 ifd_offset = stream.Get_uint32 ();
938
939 if (ifd_offset >= 12 && ifd_offset < makerNoteCount)
940 {
941
942 ParseMakerNoteIFD (host,
943 stream,
944 makerNoteCount - ifd_offset,
945 makerNoteOffset + ifd_offset,
946 makerNoteOffset,
947 minOffset,
948 maxOffset,
949 tcFujiMakerNote);
950
951 }
952
953 return;
954
955 }
956
957 // Leica MakerNote for models that store entry offsets relative to the start of
958 // the MakerNote (e.g., M9).
959
960 if ((memcmp (firstBytes, "LEICA\000\000\000", 8) == 0) ||
961 (memcmp (firstBytes, "LEICA0\003\000", 8) == 0) ||
962 (memcmp (firstBytes, "LEICA\000\001\000", 8) == 0) ||
963 (memcmp (firstBytes, "LEICA\000\005\000", 8) == 0))
964 {
965
966 if (makerNoteCount > 8)
967 {
968
969 ParseMakerNoteIFD (host,
970 stream,
971 makerNoteCount - 8,
972 makerNoteOffset + 8,
973 makerNoteOffset,
974 minOffset,
975 maxOffset,
976 tcLeicaMakerNote);
977
978 }
979
980 return;
981
982 }
983
984 // Leica MakerNote for models that store absolute entry offsets (i.e., relative
985 // to the start of the file, e.g., S2).
986
987 if (memcmp (firstBytes, "LEICA\000\002\377", 8) == 0)
988 {
989
990 if (makerNoteCount > 8)
991 {
992
993 ParseMakerNoteIFD (host,
994 stream,
995 makerNoteCount - 8,
996 makerNoteOffset + 8,
997 offsetDelta,
998 minOffset,
999 maxOffset,
1000 tcLeicaMakerNote);
1001
1002 }
1003
1004 return;
1005
1006 }
1007
1008 // Nikon version 2 MakerNote with header.
1009
1010 if (memcmp (firstBytes, "Nikon\000\002", 7) == 0)
1011 {
1012
1013 stream.SetReadPosition (makerNoteOffset + 10);
1014
1015 bool bigEndian = false;
1016
1017 uint16 endianMark = stream.Get_uint16 ();
1018
1019 if (endianMark == byteOrderMM)
1020 {
1021 bigEndian = true;
1022 }
1023
1024 else if (endianMark != byteOrderII)
1025 {
1026 return;
1027 }
1028
1029 TempBigEndian temp_endian (stream, bigEndian);
1030
1031 uint16 magic = stream.Get_uint16 ();
1032
1033 if (magic != 42)
1034 {
1035 return;
1036 }
1037
1038 uint32 ifd_offset = stream.Get_uint32 ();
1039
1040 if (ifd_offset >= 8 && ifd_offset < makerNoteCount - 10)
1041 {
1042
1043 ParseMakerNoteIFD (host,
1044 stream,
1045 makerNoteCount - 10 - ifd_offset,
1046 makerNoteOffset + 10 + ifd_offset,
1047 makerNoteOffset + 10,
1048 minOffset,
1049 maxOffset,
1050 tcNikonMakerNote);
1051
1052 }
1053
1054 return;
1055
1056 }
1057
1058 // Newer version of Olympus MakerNote with byte order mark.
1059
1060 if (memcmp (firstBytes, "OLYMPUS\000", 8) == 0)
1061 {
1062
1063 stream.SetReadPosition (makerNoteOffset + 8);
1064
1065 bool bigEndian = false;
1066
1067 uint16 endianMark = stream.Get_uint16 ();
1068
1069 if (endianMark == byteOrderMM)
1070 {
1071 bigEndian = true;
1072 }
1073
1074 else if (endianMark != byteOrderII)
1075 {
1076 return;
1077 }
1078
1079 TempBigEndian temp_endian (stream, bigEndian);
1080
1081 uint16 version = stream.Get_uint16 ();
1082
1083 if (version != 3)
1084 {
1085 return;
1086 }
1087
1088 if (makerNoteCount > 12)
1089 {
1090
1091 ParseMakerNoteIFD (host,
1092 stream,
1093 makerNoteCount - 12,
1094 makerNoteOffset + 12,
1095 makerNoteOffset,
1096 minOffset,
1097 maxOffset,
1098 tcOlympusMakerNote);
1099
1100 }
1101
1102 return;
1103
1104 }
1105
1106 // Olympus MakerNote with header.
1107
1108 if (memcmp (firstBytes, "OLYMP", 5) == 0)
1109 {
1110
1111 if (makerNoteCount > 8)
1112 {
1113
1114 ParseMakerNoteIFD (host,
1115 stream,
1116 makerNoteCount - 8,
1117 makerNoteOffset + 8,
1118 offsetDelta,
1119 minOffset,
1120 maxOffset,
1121 tcOlympusMakerNote);
1122
1123 }
1124
1125 return;
1126
1127 }
1128
1129 // Panasonic MakerNote.
1130
1131 if (memcmp (firstBytes, "Panasonic\000\000\000", 12) == 0)
1132 {
1133
1134 if (makerNoteCount > 12)
1135 {
1136
1137 ParseMakerNoteIFD (host,
1138 stream,
1139 makerNoteCount - 12,
1140 makerNoteOffset + 12,
1141 offsetDelta,
1142 minOffset,
1143 maxOffset,
1144 tcPanasonicMakerNote);
1145
1146 }
1147
1148 return;
1149
1150 }
1151
1152 // Pentax MakerNote.
1153
1154 if (memcmp (firstBytes, "AOC", 4) == 0)
1155 {
1156
1157 if (makerNoteCount > 6)
1158 {
1159
1160 stream.SetReadPosition (makerNoteOffset + 4);
1161
1162 bool bigEndian = stream.BigEndian ();
1163
1164 uint16 endianMark = stream.Get_uint16 ();
1165
1166 if (endianMark == byteOrderMM)
1167 {
1168 bigEndian = true;
1169 }
1170
1171 else if (endianMark == byteOrderII)
1172 {
1173 bigEndian = false;
1174 }
1175
1176 TempBigEndian temp_endian (stream, bigEndian);
1177
1178 ParseMakerNoteIFD (host,
1179 stream,
1180 makerNoteCount - 6,
1181 makerNoteOffset + 6,
1182 offsetDelta,
1183 minOffset,
1184 maxOffset,
1185 tcPentaxMakerNote);
1186
1187 }
1188
1189 return;
1190
1191 }
1192
1193 // Ricoh MakerNote.
1194
1195 if (memcmp (firstBytes, "RICOH", 5) == 0 ||
1196 memcmp (firstBytes, "Ricoh", 5) == 0)
1197 {
1198
1199 if (makerNoteCount > 8)
1200 {
1201
1202 TempBigEndian tempEndian (stream);
1203
1204 ParseMakerNoteIFD (host,
1205 stream,
1206 makerNoteCount - 8,
1207 makerNoteOffset + 8,
1208 offsetDelta,
1209 minOffset,
1210 maxOffset,
1211 tcRicohMakerNote);
1212
1213 }
1214
1215 return;
1216
1217 }
1218
1219 // Nikon MakerNote without header.
1220
1221 if (fExif->fMake.StartsWith ("NIKON"))
1222 {
1223
1224 ParseMakerNoteIFD (host,
1225 stream,
1226 makerNoteCount,
1227 makerNoteOffset,
1228 offsetDelta,
1229 minOffset,
1230 maxOffset,
1231 tcNikonMakerNote);
1232
1233 return;
1234
1235 }
1236
1237 // Canon MakerNote.
1238
1239 if (fExif->fMake.StartsWith ("CANON"))
1240 {
1241
1242 ParseMakerNoteIFD (host,
1243 stream,
1244 makerNoteCount,
1245 makerNoteOffset,
1246 offsetDelta,
1247 minOffset,
1248 maxOffset,
1249 tcCanonMakerNote);
1250
1251 return;
1252
1253 }
1254
1255 // Minolta MakerNote.
1256
1257 if (fExif->fMake.StartsWith ("MINOLTA" ) ||
1258 fExif->fMake.StartsWith ("KONICA MINOLTA"))
1259 {
1260
1261 ParseMakerNoteIFD (host,
1262 stream,
1263 makerNoteCount,
1264 makerNoteOffset,
1265 offsetDelta,
1266 minOffset,
1267 maxOffset,
1268 tcMinoltaMakerNote);
1269
1270 return;
1271
1272 }
1273
1274 // Sony MakerNote.
1275
1276 if (fExif->fMake.StartsWith ("SONY"))
1277 {
1278
1279 ParseMakerNoteIFD (host,
1280 stream,
1281 makerNoteCount,
1282 makerNoteOffset,
1283 offsetDelta,
1284 minOffset,
1285 maxOffset,
1286 tcSonyMakerNote);
1287
1288 return;
1289
1290 }
1291
1292 // Kodak MakerNote.
1293
1294 if (fExif->fMake.StartsWith ("EASTMAN KODAK"))
1295 {
1296
1297 ParseMakerNoteIFD (host,
1298 stream,
1299 makerNoteCount,
1300 makerNoteOffset,
1301 offsetDelta,
1302 minOffset,
1303 maxOffset,
1304 tcKodakMakerNote);
1305
1306 return;
1307
1308 }
1309
1310 // Mamiya MakerNote.
1311
1312 if (fExif->fMake.StartsWith ("Mamiya"))
1313 {
1314
1315 ParseMakerNoteIFD (host,
1316 stream,
1317 makerNoteCount,
1318 makerNoteOffset,
1319 offsetDelta,
1320 minOffset,
1321 maxOffset,
1322 tcMamiyaMakerNote);
1323
1324 // Mamiya uses a MakerNote chain.
1325
1326 while (fMakerNoteNextIFD)
1327 {
1328
1329 ParseMakerNoteIFD (host,
1330 stream,
1331 makerNoteCount,
1332 offsetDelta + fMakerNoteNextIFD,
1333 offsetDelta,
1334 minOffset,
1335 maxOffset,
1336 tcMamiyaMakerNote);
1337
1338 }
1339
1340 return;
1341
1342 }
1343
1344 // Nikon MakerNote without header.
1345
1346 if (fExif->fMake.StartsWith ("Hasselblad"))
1347 {
1348
1349 ParseMakerNoteIFD (host,
1350 stream,
1351 makerNoteCount,
1352 makerNoteOffset,
1353 offsetDelta,
1354 minOffset,
1355 maxOffset,
1356 tcHasselbladMakerNote);
1357
1358 return;
1359
1360 }
1361
1362 // Samsung MakerNote.
1363
1364 if (fExif->fMake.StartsWith ("Samsung"))
1365 {
1366
1367 ParseMakerNoteIFD (host,
1368 stream,
1369 makerNoteCount,
1370 makerNoteOffset,
1371 makerNoteOffset,
1372 minOffset,
1373 maxOffset,
1374 tcSamsungMakerNote);
1375
1376 return;
1377
1378 }
1379
1380 // Casio MakerNote.
1381
1382 if (fExif->fMake.StartsWith ("CASIO COMPUTER") &&
1383 memcmp (firstBytes, "QVC\000\000\000", 6) == 0)
1384 {
1385
1386 ParseMakerNoteIFD (host,
1387 stream,
1388 makerNoteCount - 6,
1389 makerNoteOffset + 6,
1390 makerNoteOffset,
1391 minOffset,
1392 maxOffset,
1393 tcCasioMakerNote);
1394
1395 return;
1396
1397 }
1398
1399 }
1400
1401/*****************************************************************************/
1402
1403void dng_info::ParseSonyPrivateData (dng_host & /* host */,
1404 dng_stream & /* stream */,
1405 uint64 /* count */,
1406 uint64 /* oldOffset */,
1407 uint64 /* newOffset */)
1408 {
1409
1410 // Sony private data is encrypted, sorry.
1411
1412 }
1413
1414/*****************************************************************************/
1415
1416void dng_info::ParseDNGPrivateData (dng_host &host,
1417 dng_stream &stream)
1418 {
1419
1420 if (fShared->fDNGPrivateDataCount < 2)
1421 {
1422 return;
1423 }
1424
1425 // DNG private data should always start with a null-terminated
1426 // company name, to define the format of the private data.
1427
1428 dng_string privateName;
1429
1430 {
1431
1432 char buffer [64];
1433
1434 stream.SetReadPosition (fShared->fDNGPrivateDataOffset);
1435
1436 uint32 readLength = Min_uint32 (fShared->fDNGPrivateDataCount,
1437 sizeof (buffer) - 1);
1438
1439 stream.Get (buffer, readLength);
1440
1441 buffer [readLength] = 0;
1442
1443 privateName.Set (buffer);
1444
1445 }
1446
1447 // Pentax is storing their MakerNote in the DNGPrivateData data.
1448
1449 if (privateName.StartsWith ("PENTAX" ) ||
1450 privateName.StartsWith ("SAMSUNG"))
1451 {
1452
1453 #if qDNGValidate
1454
1455 if (gVerbose)
1456 {
1457 printf ("Parsing Pentax/Samsung DNGPrivateData\n\n");
1458 }
1459
1460 #endif
1461
1462 stream.SetReadPosition (fShared->fDNGPrivateDataOffset + 8);
1463
1464 bool bigEndian = stream.BigEndian ();
1465
1466 uint16 endianMark = stream.Get_uint16 ();
1467
1468 if (endianMark == byteOrderMM)
1469 {
1470 bigEndian = true;
1471 }
1472
1473 else if (endianMark == byteOrderII)
1474 {
1475 bigEndian = false;
1476 }
1477
1478 TempBigEndian temp_endian (stream, bigEndian);
1479
1480 ParseMakerNoteIFD (host,
1481 stream,
1482 fShared->fDNGPrivateDataCount - 10,
1483 fShared->fDNGPrivateDataOffset + 10,
1484 fShared->fDNGPrivateDataOffset,
1485 fShared->fDNGPrivateDataOffset,
1486 fShared->fDNGPrivateDataOffset + fShared->fDNGPrivateDataCount,
1487 tcPentaxMakerNote);
1488
1489 return;
1490
1491 }
1492
1493 // Stop parsing if this is not an Adobe format block.
1494
1495 if (!privateName.Matches ("Adobe"))
1496 {
1497 return;
1498 }
1499
1500 TempBigEndian temp_order (stream);
1501
1502 uint32 section_offset = 6;
1503
1504 while (SafeUint32Add(section_offset, 8) < fShared->fDNGPrivateDataCount)
1505 {
1506
1507 stream.SetReadPosition (SafeUint64Add(fShared->fDNGPrivateDataOffset,
1508 section_offset));
1509
1510 uint32 section_key = stream.Get_uint32 ();
1511 uint32 section_count = stream.Get_uint32 ();
1512
1513 if (section_key == DNG_CHAR4 ('M','a','k','N') && section_count > 6)
1514 {
1515
1516 #if qDNGValidate
1517
1518 if (gVerbose)
1519 {
1520 printf ("Found MakerNote inside DNGPrivateData\n\n");
1521 }
1522
1523 #endif
1524
1525 uint16 order_mark = stream.Get_uint16 ();
1526 int64 old_offset = stream.Get_uint32 ();
1527
1528 uint32 tempSize = SafeUint32Sub(section_count, 6);
1529
1530 AutoPtr<dng_memory_block> tempBlock (host.Allocate (tempSize));
1531
1532 uint64 positionInOriginalFile = stream.PositionInOriginalFile();
1533
1534 stream.Get (tempBlock->Buffer (), tempSize);
1535
1536 dng_stream tempStream (tempBlock->Buffer (),
1537 tempSize,
1538 positionInOriginalFile);
1539
1540 tempStream.SetBigEndian (order_mark == byteOrderMM);
1541
1542 ParseMakerNote (host,
1543 tempStream,
1544 tempSize,
1545 0,
1546 0 - old_offset,
1547 0,
1548 tempSize);
1549
1550 }
1551
1552 else if (section_key == DNG_CHAR4 ('S','R','2',' ') && section_count > 6)
1553 {
1554
1555 #if qDNGValidate
1556
1557 if (gVerbose)
1558 {
1559 printf ("Found Sony private data inside DNGPrivateData\n\n");
1560 }
1561
1562 #endif
1563
1564 uint16 order_mark = stream.Get_uint16 ();
1565 uint64 old_offset = stream.Get_uint32 ();
1566
1567 uint64 new_offset = fShared->fDNGPrivateDataOffset + section_offset + 14;
1568
1569 TempBigEndian sr2_order (stream, order_mark == byteOrderMM);
1570
1571 ParseSonyPrivateData (host,
1572 stream,
1573 section_count - 6,
1574 old_offset,
1575 new_offset);
1576
1577 }
1578
1579 else if (section_key == DNG_CHAR4 ('R','A','F',' ') && section_count > 4)
1580 {
1581
1582 #if qDNGValidate
1583
1584 if (gVerbose)
1585 {
1586 printf ("Found Fuji RAF tags inside DNGPrivateData\n\n");
1587 }
1588
1589 #endif
1590
1591 uint16 order_mark = stream.Get_uint16 ();
1592
1593 uint32 tagCount = stream.Get_uint32 ();
1594
1595 uint64 tagOffset = stream.Position ();
1596
1597 if (tagCount)
1598 {
1599
1600 TempBigEndian raf_order (stream, order_mark == byteOrderMM);
1601
1602 ParseTag (host,
1603 stream,
1604 fExif.Get (),
1605 fShared.Get (),
1606 NULL,
1607 tcFujiRAF,
1608 tcFujiHeader,
1609 ttUndefined,
1610 tagCount,
1611 tagOffset,
1612 0);
1613
1614 stream.SetReadPosition (SafeUint64Add(tagOffset, tagCount));
1615
1616 }
1617
1618 tagCount = stream.Get_uint32 ();
1619
1620 tagOffset = stream.Position ();
1621
1622 if (tagCount)
1623 {
1624
1625 TempBigEndian raf_order (stream, order_mark == byteOrderMM);
1626
1627 ParseTag (host,
1628 stream,
1629 fExif.Get (),
1630 fShared.Get (),
1631 NULL,
1632 tcFujiRAF,
1633 tcFujiRawInfo1,
1634 ttUndefined,
1635 tagCount,
1636 tagOffset,
1637 0);
1638
1639 stream.SetReadPosition (SafeUint64Add(tagOffset, tagCount));
1640
1641 }
1642
1643 tagCount = stream.Get_uint32 ();
1644
1645 tagOffset = stream.Position ();
1646
1647 if (tagCount)
1648 {
1649
1650 TempBigEndian raf_order (stream, order_mark == byteOrderMM);
1651
1652 ParseTag (host,
1653 stream,
1654 fExif.Get (),
1655 fShared.Get (),
1656 NULL,
1657 tcFujiRAF,
1658 tcFujiRawInfo2,
1659 ttUndefined,
1660 tagCount,
1661 tagOffset,
1662 0);
1663
1664 stream.SetReadPosition (SafeUint64Add(tagOffset, tagCount));
1665
1666 }
1667
1668 }
1669
1670 else if (section_key == DNG_CHAR4 ('C','n','t','x') && section_count > 4)
1671 {
1672
1673 #if qDNGValidate
1674
1675 if (gVerbose)
1676 {
1677 printf ("Found Contax Raw header inside DNGPrivateData\n\n");
1678 }
1679
1680 #endif
1681
1682 uint16 order_mark = stream.Get_uint16 ();
1683
1684 uint32 tagCount = stream.Get_uint32 ();
1685
1686 uint64 tagOffset = stream.Position ();
1687
1688 if (tagCount)
1689 {
1690
1691 TempBigEndian contax_order (stream, order_mark == byteOrderMM);
1692
1693 ParseTag (host,
1694 stream,
1695 fExif.Get (),
1696 fShared.Get (),
1697 NULL,
1698 tcContaxRAW,
1699 tcContaxHeader,
1700 ttUndefined,
1701 tagCount,
1702 tagOffset,
1703 0);
1704
1705 }
1706
1707 }
1708
1709 else if (section_key == DNG_CHAR4 ('C','R','W',' ') && section_count > 4)
1710 {
1711
1712 #if qDNGValidate
1713
1714 if (gVerbose)
1715 {
1716 printf ("Found Canon CRW tags inside DNGPrivateData\n\n");
1717 }
1718
1719 #endif
1720
1721 uint16 order_mark = stream.Get_uint16 ();
1722 uint32 entries = stream.Get_uint16 ();
1723
1724 uint64 crwTagStart = stream.Position ();
1725
1726 for (uint32 parsePass = 1; parsePass <= 2; parsePass++)
1727 {
1728
1729 stream.SetReadPosition (crwTagStart);
1730
1731 for (uint32 index = 0; index < entries; index++)
1732 {
1733
1734 uint32 tagCode = stream.Get_uint16 ();
1735
1736 uint32 tagCount = stream.Get_uint32 ();
1737
1738 uint64 tagOffset = stream.Position ();
1739
1740 // We need to grab the model id tag first, and then all the
1741 // other tags.
1742
1743 if ((parsePass == 1) == (tagCode == 0x5834))
1744 {
1745
1746 TempBigEndian tag_order (stream, order_mark == byteOrderMM);
1747
1748 ParseTag (host,
1749 stream,
1750 fExif.Get (),
1751 fShared.Get (),
1752 NULL,
1753 tcCanonCRW,
1754 tagCode,
1755 ttUndefined,
1756 tagCount,
1757 tagOffset,
1758 0);
1759
1760 }
1761
1762 stream.SetReadPosition (tagOffset + tagCount);
1763
1764 }
1765
1766 }
1767
1768 }
1769
1770 else if (section_count > 4)
1771 {
1772
1773 uint32 parentCode = 0;
1774
1775 bool code32 = false;
1776 bool hasType = true;
1777
1778 switch (section_key)
1779 {
1780
1781 case DNG_CHAR4 ('M','R','W',' '):
1782 {
1783 parentCode = tcMinoltaMRW;
1784 code32 = true;
1785 hasType = false;
1786 break;
1787 }
1788
1789 case DNG_CHAR4 ('P','a','n','o'):
1790 {
1791 parentCode = tcPanasonicRAW;
1792 break;
1793 }
1794
1795 case DNG_CHAR4 ('L','e','a','f'):
1796 {
1797 parentCode = tcLeafMOS;
1798 break;
1799 }
1800
1801 case DNG_CHAR4 ('K','o','d','a'):
1802 {
1803 parentCode = tcKodakDCRPrivateIFD;
1804 break;
1805 }
1806
1807 case DNG_CHAR4 ('K','D','C',' '):
1808 {
1809 parentCode = tcKodakKDCPrivateIFD;
1810 break;
1811 }
1812
1813 default:
1814 break;
1815
1816 }
1817
1818 if (parentCode)
1819 {
1820
1821 #if qDNGValidate
1822
1823 if (gVerbose)
1824 {
1825 printf ("Found %s tags inside DNGPrivateData\n\n",
1826 LookupParentCode (parentCode));
1827 }
1828
1829 #endif
1830
1831 uint16 order_mark = stream.Get_uint16 ();
1832 uint32 entries = stream.Get_uint16 ();
1833
1834 for (uint32 index = 0; index < entries; index++)
1835 {
1836
1837 uint32 tagCode = code32 ? stream.Get_uint32 ()
1838 : stream.Get_uint16 ();
1839
1840 uint32 tagType = hasType ? stream.Get_uint16 ()
1841 : ttUndefined;
1842
1843 uint32 tagCount = stream.Get_uint32 ();
1844
1845 uint32 tagSize = SafeUint32Mult(tagCount, TagTypeSize (tagType));
1846
1847 uint64 tagOffset = stream.Position ();
1848
1849 TempBigEndian tag_order (stream, order_mark == byteOrderMM);
1850
1851 ParseTag (host,
1852 stream,
1853 fExif.Get (),
1854 fShared.Get (),
1855 NULL,
1856 parentCode,
1857 tagCode,
1858 tagType,
1859 tagCount,
1860 tagOffset,
1861 0);
1862
1863 stream.SetReadPosition (SafeUint64Add(tagOffset, tagSize));
1864
1865 }
1866
1867 }
1868
1869 }
1870
1871 section_offset = SafeUint32Add(section_offset, 8);
1872 section_offset = SafeUint32Add(section_offset, section_count);
1873
1874 if (section_offset & 1)
1875 {
1876 section_offset = SafeUint32Add(section_offset, 1);
1877 }
1878
1879 }
1880
1881 }
1882
1883/*****************************************************************************/
1884
1885void dng_info::Parse (dng_host &host,
1886 dng_stream &stream)
1887 {
1888
1889 fTIFFBlockOffset = stream.Position ();
1890
1891 fTIFFBlockOriginalOffset = stream.PositionInOriginalFile ();
1892
1893 // Check byte order indicator.
1894
1895 uint16 byteOrder = stream.Get_uint16 ();
1896
1897 if (byteOrder == byteOrderII)
1898 {
1899
1900 fBigEndian = false;
1901
1902 #if qDNGValidate
1903
1904 if (gVerbose)
1905 {
1906 printf ("\nUses little-endian byte order\n");
1907 }
1908
1909 #endif
1910
1911 stream.SetLittleEndian ();
1912
1913 }
1914
1915 else if (byteOrder == byteOrderMM)
1916 {
1917
1918 fBigEndian = true;
1919
1920 #if qDNGValidate
1921
1922 if (gVerbose)
1923 {
1924 printf ("\nUses big-endian byte order\n");
1925 }
1926
1927 #endif
1928
1929 stream.SetBigEndian ();
1930
1931 }
1932
1933 else
1934 {
1935
1936 #if qDNGValidate
1937
1938 ReportError ("Unknown byte order");
1939
1940 #endif
1941
1942 ThrowBadFormat ();
1943
1944 }
1945
1946 // Check "magic number" indicator.
1947
1948 fMagic = stream.Get_uint16 ();
1949
1950 #if qDNGValidate
1951
1952 if (gVerbose)
1953 {
1954 printf ("Magic number = %u\n\n", (unsigned) fMagic);
1955 }
1956
1957 #endif
1958
1959 ValidateMagic ();
1960
1961 // Parse IFD 0.
1962
1963 uint64 next_offset = stream.Get_uint32 ();
1964
1965 fExif.Reset (host.Make_dng_exif ());
1966
1967 fShared.Reset (host.Make_dng_shared ());
1968
1969 fIFD [0].Reset (host.Make_dng_ifd ());
1970
1971 ParseIFD (host,
1972 stream,
1973 fExif.Get (),
1974 fShared.Get (),
1975 fIFD [0].Get (),
1976 fTIFFBlockOffset + next_offset,
1977 fTIFFBlockOffset,
1978 0);
1979
1980 next_offset = fIFD [0]->fNextIFD;
1981
1982 fIFDCount = 1;
1983
1984 // Parse chained IFDs.
1985
1986 while (next_offset)
1987 {
1988
1989 if (next_offset >= stream.Length ())
1990 {
1991
1992 #if qDNGValidate
1993
1994 {
1995
1996 ReportWarning ("Chained IFD offset past end of stream");
1997
1998 }
1999
2000 #endif
2001
2002 break;
2003
2004 }
2005
2006 // Some TIFF file writers forget about the next IFD offset, so
2007 // validate the IFD at that offset before parsing it.
2008
2009 if (!ValidateIFD (stream,
2010 fTIFFBlockOffset + next_offset,
2011 fTIFFBlockOffset))
2012 {
2013
2014 #if qDNGValidate
2015
2016 {
2017
2018 ReportWarning ("Chained IFD is not valid");
2019
2020 }
2021
2022 #endif
2023
2024 break;
2025
2026 }
2027
2028 if (fChainedIFDCount == kMaxChainedIFDs)
2029 {
2030
2031 #if qDNGValidate
2032
2033 {
2034
2035 ReportWarning ("Chained IFD count exceeds DNG SDK parsing limit");
2036
2037 }
2038
2039 #endif
2040
2041 break;
2042
2043 }
2044
2045 fChainedIFD [fChainedIFDCount].Reset (host.Make_dng_ifd ());
2046
2047 ParseIFD (host,
2048 stream,
2049 NULL,
2050 NULL,
2051 fChainedIFD [fChainedIFDCount].Get (),
2052 fTIFFBlockOffset + next_offset,
2053 fTIFFBlockOffset,
2054 tcFirstChainedIFD + fChainedIFDCount);
2055
2056 next_offset = fChainedIFD [fChainedIFDCount]->fNextIFD;
2057
2058 fChainedIFDCount++;
2059
2060 }
2061
2062 // Parse SubIFDs.
2063
2064 uint32 searchedIFDs = 0;
2065
2066 bool tooManySubIFDs = false;
2067
2068 while (searchedIFDs < fIFDCount && !tooManySubIFDs)
2069 {
2070
2071 uint32 searchLimit = fIFDCount;
2072
2073 for (uint32 searchIndex = searchedIFDs;
2074 searchIndex < searchLimit && !tooManySubIFDs;
2075 searchIndex++)
2076 {
2077
2078 for (uint32 subIndex = 0;
2079 subIndex < fIFD [searchIndex]->fSubIFDsCount;
2080 subIndex++)
2081 {
2082
2083 if (fIFDCount == kMaxSubIFDs + 1)
2084 {
2085
2086 tooManySubIFDs = true;
2087
2088 break;
2089
2090 }
2091
2092 stream.SetReadPosition (fIFD [searchIndex]->fSubIFDsOffset +
2093 subIndex * 4);
2094
2095 uint32 sub_ifd_offset = stream.Get_uint32 ();
2096
2097 fIFD [fIFDCount].Reset (host.Make_dng_ifd ());
2098
2099 ParseIFD (host,
2100 stream,
2101 fExif.Get (),
2102 fShared.Get (),
2103 fIFD [fIFDCount].Get (),
2104 fTIFFBlockOffset + sub_ifd_offset,
2105 fTIFFBlockOffset,
2106 tcFirstSubIFD + fIFDCount - 1);
2107
2108 fIFDCount++;
2109
2110 }
2111
2112 searchedIFDs = searchLimit;
2113
2114 }
2115
2116 }
2117
2118 #if qDNGValidate
2119
2120 {
2121
2122 if (tooManySubIFDs)
2123 {
2124
2125 ReportWarning ("SubIFD count exceeds DNG SDK parsing limit");
2126
2127 }
2128
2129 }
2130
2131 #endif
2132
2133 // Parse EXIF IFD.
2134
2135 if (fShared->fExifIFD)
2136 {
2137
2138 ParseIFD (host,
2139 stream,
2140 fExif.Get (),
2141 fShared.Get (),
2142 NULL,
2143 fTIFFBlockOffset + fShared->fExifIFD,
2144 fTIFFBlockOffset,
2145 tcExifIFD);
2146
2147 }
2148
2149 // Parse GPS IFD.
2150
2151 if (fShared->fGPSInfo)
2152 {
2153
2154 ParseIFD (host,
2155 stream,
2156 fExif.Get (),
2157 fShared.Get (),
2158 NULL,
2159 fTIFFBlockOffset + fShared->fGPSInfo,
2160 fTIFFBlockOffset,
2161 tcGPSInfo);
2162
2163 }
2164
2165 // Parse Interoperability IFD.
2166
2167 if (fShared->fInteroperabilityIFD)
2168 {
2169
2170 // Some Kodak KDC files have bogus Interoperability IFDs, so
2171 // validate the IFD before trying to parse it.
2172
2173 if (ValidateIFD (stream,
2174 fTIFFBlockOffset + fShared->fInteroperabilityIFD,
2175 fTIFFBlockOffset))
2176 {
2177
2178 ParseIFD (host,
2179 stream,
2180 fExif.Get (),
2181 fShared.Get (),
2182 NULL,
2183 fTIFFBlockOffset + fShared->fInteroperabilityIFD,
2184 fTIFFBlockOffset,
2185 tcInteroperabilityIFD);
2186
2187 }
2188
2189 #if qDNGValidate
2190
2191 else
2192 {
2193
2194 ReportWarning ("The Interoperability IFD is not a valid IFD");
2195
2196 }
2197
2198 #endif
2199
2200 }
2201
2202 // Parse Kodak DCR Private IFD.
2203
2204 if (fShared->fKodakDCRPrivateIFD)
2205 {
2206
2207 ParseIFD (host,
2208 stream,
2209 fExif.Get (),
2210 fShared.Get (),
2211 NULL,
2212 fTIFFBlockOffset + fShared->fKodakDCRPrivateIFD,
2213 fTIFFBlockOffset,
2214 tcKodakDCRPrivateIFD);
2215
2216 }
2217
2218 // Parse Kodak KDC Private IFD.
2219
2220 if (fShared->fKodakKDCPrivateIFD)
2221 {
2222
2223 ParseIFD (host,
2224 stream,
2225 fExif.Get (),
2226 fShared.Get (),
2227 NULL,
2228 fTIFFBlockOffset + fShared->fKodakKDCPrivateIFD,
2229 fTIFFBlockOffset,
2230 tcKodakKDCPrivateIFD);
2231
2232 }
2233
2234 // Parse MakerNote tag.
2235
2236 if (fShared->fMakerNoteCount)
2237 {
2238
2239 ParseMakerNote (host,
2240 stream,
2241 (uint32) (fTIFFBlockOffset + fShared->fMakerNoteCount),
2242 fShared->fMakerNoteOffset,
2243 fTIFFBlockOffset,
2244 0,
2245 stream.Length ());
2246
2247 }
2248
2249 // Parse DNGPrivateData tag.
2250
2251 if (fShared->fDNGPrivateDataCount &&
2252 fShared->fDNGVersion)
2253 {
2254
2255 ParseDNGPrivateData (host, stream);
2256
2257 }
2258
2259 #if qDNGValidate
2260
2261 // If we are running dng_validate on stand-alone camera profile file,
2262 // complete the validation of the profile.
2263
2264 if (fMagic == magicExtendedProfile)
2265 {
2266
2267 dng_camera_profile_info &profileInfo = fShared->fCameraProfile;
2268
2269 dng_camera_profile profile;
2270
2271 profile.Parse (stream, profileInfo);
2272
2273 if (profileInfo.fColorPlanes < 3 || !profile.IsValid (profileInfo.fColorPlanes))
2274 {
2275
2276 ReportError ("Invalid camera profile file");
2277
2278 }
2279
2280 }
2281
2282 #endif
2283
2284 }
2285
2286/*****************************************************************************/
2287
2288void dng_info::PostParse (dng_host &host)
2289 {
2290
2291 uint32 index;
2292
2293 fExif->PostParse (host, *fShared.Get ());
2294
2295 fShared->PostParse (host, *fExif.Get ());
2296
2297 for (index = 0; index < fIFDCount; index++)
2298 {
2299
2300 fIFD [index]->PostParse ();
2301
2302 }
2303
2304 for (index = 0; index < fChainedIFDCount; index++)
2305 {
2306
2307 fChainedIFD [index]->PostParse ();
2308
2309 }
2310
2311 if (fShared->fDNGVersion != 0)
2312 {
2313
2314 // Find main IFD.
2315
2316 fMainIndex = -1;
2317
2318 for (index = 0; index < fIFDCount; index++)
2319 {
2320
2321 if (fIFD [index]->fUsesNewSubFileType &&
2322 fIFD [index]->fNewSubFileType == sfMainImage)
2323 {
2324
2325 if (fMainIndex == -1)
2326 {
2327
2328 fMainIndex = index;
2329
2330 }
2331
2332 #if qDNGValidate
2333
2334 else
2335 {
2336
2337 ReportError ("Multiple IFDs marked as main image");
2338
2339 }
2340
2341 #endif
2342
2343 }
2344
2345 else if (fIFD [index]->fNewSubFileType == sfPreviewImage ||
2346 fIFD [index]->fNewSubFileType == sfAltPreviewImage)
2347 {
2348
2349 // Fill in default color space for DNG previews if not included.
2350
2351 if (fIFD [index]->fPreviewInfo.fColorSpace == previewColorSpace_MaxEnum)
2352 {
2353
2354 if (fIFD [index]->fSamplesPerPixel == 1)
2355 {
2356
2357 fIFD [index]->fPreviewInfo.fColorSpace = previewColorSpace_GrayGamma22;
2358
2359 }
2360
2361 else
2362 {
2363
2364 fIFD [index]->fPreviewInfo.fColorSpace = previewColorSpace_sRGB;
2365
2366 }
2367
2368 }
2369
2370 }
2371
2372 }
2373
2374 // Deal with lossless JPEG bug in early DNG versions.
2375
2376 if (fShared->fDNGVersion < dngVersion_1_1_0_0)
2377 {
2378
2379 if (fMainIndex != -1)
2380 {
2381
2382 fIFD [fMainIndex]->fLosslessJPEGBug16 = true;
2383
2384 }
2385
2386 }
2387
2388 // Find mask index.
2389
2390 for (index = 0; index < fIFDCount; index++)
2391 {
2392
2393 if (fIFD [index]->fNewSubFileType == sfTransparencyMask)
2394 {
2395
2396 if (fMaskIndex == -1)
2397 {
2398
2399 fMaskIndex = index;
2400
2401 }
2402
2403 #if qDNGValidate
2404
2405 else
2406 {
2407
2408 ReportError ("Multiple IFDs marked as transparency mask image");
2409
2410 }
2411
2412 #endif
2413
2414 }
2415
2416 }
2417
2418 // Warn about Chained IFDs.
2419
2420 #if qDNGValidate
2421
2422 if (fChainedIFDCount > 0)
2423 {
2424
2425 ReportWarning ("This file has Chained IFDs, which will be ignored by DNG readers");
2426
2427 }
2428
2429 #endif
2430
2431 }
2432
2433 }
2434
2435/*****************************************************************************/
2436
2437bool dng_info::IsValidDNG ()
2438 {
2439
2440 // Check shared info.
2441
2442 if (!fShared->IsValidDNG ())
2443 {
2444
2445 return false;
2446
2447 }
2448
2449 // Check TIFF magic number.
2450
2451 if (fMagic != 42)
2452 {
2453
2454 #if qDNGValidate
2455
2456 ReportError ("Invalid TIFF magic number");
2457
2458 #endif
2459
2460 return false;
2461
2462 }
2463
2464 // Make sure we have a main image IFD.
2465
2466 if (fMainIndex == -1)
2467 {
2468
2469 #if qDNGValidate
2470
2471 ReportError ("Unable to find main image IFD");
2472
2473 #endif
2474
2475 return false;
2476
2477 }
2478
2479 // Make sure is each IFD is valid.
2480
2481 for (uint32 index = 0; index < fIFDCount; index++)
2482 {
2483
2484 uint32 parentCode = (index == 0 ? 0 : tcFirstSubIFD + index - 1);
2485
2486 if (!fIFD [index]->IsValidDNG (*fShared.Get (),
2487 parentCode))
2488 {
2489
2490 // Only errors in the main and transparency mask IFDs are fatal to parsing.
2491
2492 if (index == (uint32) fMainIndex ||
2493 index == (uint32) fMaskIndex)
2494 {
2495
2496 return false;
2497
2498 }
2499
2500 }
2501
2502 }
2503
2504 return true;
2505
2506 }
2507
2508/*****************************************************************************/
2509