File Coverage

blib/lib/Image/ExifTool/MakerNotes.pm
Criterion Covered Total %
statement 240 354 67.8
branch 139 254 54.7
condition 68 155 43.8
subroutine 12 15 80.0
pod 0 11 0.0
total 459 789 58.1


line stmt bran cond sub pod time code
1             #------------------------------------------------------------------------------
2             # File: MakerNotes.pm
3             #
4             # Description: Read and write EXIF maker notes
5             #
6             # Revisions: 11/11/2004 - P. Harvey Created
7             #------------------------------------------------------------------------------
8              
9             package Image::ExifTool::MakerNotes;
10              
11 106     106   742 use strict;
  106         219  
  106         3528  
12 106     106   599 use vars qw($VERSION);
  106         222  
  106         4622  
13 106     106   631 use Image::ExifTool qw(:DataAccess);
  106         238  
  106         18484  
14 106     106   803 use Image::ExifTool::Exif;
  106         220  
  106         641920  
15              
16             sub ProcessUnknown($$$);
17             sub ProcessUnknownOrPreview($$$);
18             sub ProcessCanon($$$);
19             sub ProcessGE2($$$);
20             sub ProcessKodakPatch($$$);
21             sub WriteUnknownOrPreview($$$);
22             sub FixLeicaBase($$;$);
23              
24             $VERSION = '2.14';
25              
26             my $debug; # set to 1 to enable debugging code
27              
28             # conditional list of maker notes
29             # Notes:
30             # - This is NOT a normal tag table!
31             # - All byte orders are now specified because we can now
32             # write maker notes into a file with different byte ordering!
33             # - Put these in alphabetical order to make TagNames documentation nicer.
34             @Image::ExifTool::MakerNotes::Main = (
35             # decide which MakerNotes to use (based on makernote header and camera make/model)
36             {
37             Name => 'MakerNoteApple',
38             Condition => '$$valPt =~ /^Apple iOS\0/',
39             SubDirectory => {
40             TagTable => 'Image::ExifTool::Apple::Main',
41             Start => '$valuePtr + 14',
42             Base => '$start - 14',
43             ByteOrder => 'Unknown',
44             },
45             },
46             {
47             # this maker notes starts with a standard TIFF header at offset 0x0a
48             # (must check Nikon signature first because Nikon Capture NX can generate
49             # NEF images containing Nikon maker notes from JPEG images of any camera model)
50             Name => 'MakerNoteNikon',
51             Condition => '$$valPt=~/^Nikon\x00\x02/',
52             SubDirectory => {
53             TagTable => 'Image::ExifTool::Nikon::Main',
54             Start => '$valuePtr + 18',
55             Base => '$start - 8',
56             ByteOrder => 'Unknown',
57             },
58             },
59             {
60             Name => 'MakerNoteCanon',
61             # (starts with an IFD)
62             Condition => '$$self{Make} =~ /^Canon/',
63             SubDirectory => {
64             TagTable => 'Image::ExifTool::Canon::Main',
65             ProcessProc => \&ProcessCanon,
66             ByteOrder => 'Unknown',
67             },
68             },
69             {
70             Name => 'MakerNoteCasio',
71             # do negative lookahead assertion just to get tags
72             # in a nice order for documentation
73             # (starts with an IFD)
74             Condition => '$$self{Make}=~/^CASIO/ and $$valPt!~/^(QVC|DCI)\0/',
75             SubDirectory => {
76             TagTable => 'Image::ExifTool::Casio::Main',
77             ByteOrder => 'Unknown',
78             },
79             },
80             {
81             Name => 'MakerNoteCasio2',
82             # (starts with "QVC\0" [Casio] or "DCI\0" [Concord])
83             # (also found in AVI and MOV videos)
84             Condition => '$$valPt =~ /^(QVC|DCI)\0/',
85             SubDirectory => {
86             TagTable => 'Image::ExifTool::Casio::Type2',
87             Start => '$valuePtr + 6',
88             ByteOrder => 'Unknown',
89             FixBase => 1, # necessary for AVI and MOV videos
90             },
91             },
92             {
93             Name => 'MakerNoteDJIInfo',
94             Condition => '$$valPt =~ /^\[ae_dbg_info:/',
95             NotIFD => 1,
96             SubDirectory => { TagTable => 'Image::ExifTool::DJI::Info' },
97             },
98             {
99             Name => 'MakerNoteDJI',
100             Condition => '$$self{Make} eq "DJI" and $$valPt !~ /^(...\@AMBA|DJI)/s',
101             SubDirectory => {
102             TagTable => 'Image::ExifTool::DJI::Main',
103             Start => '$valuePtr',
104             ByteOrder => 'Unknown',
105             },
106             },
107             {
108             Name => 'MakerNoteFLIR',
109             # (starts with IFD, Make is 'FLIR Systems AB' or 'FLIR Systems')
110             Condition => '$$self{Make} =~ /^FLIR Systems/',
111             SubDirectory => {
112             TagTable => 'Image::ExifTool::FLIR::Main',
113             Start => '$valuePtr',
114             ByteOrder => 'Unknown',
115             },
116             },
117             {
118             # The Fuji maker notes use a structure similar to a self-contained
119             # TIFF file, but with "FUJIFILM" instead of the standard TIFF header
120             Name => 'MakerNoteFujiFilm',
121             # (starts with "FUJIFILM" -- also used by some Leica, Minolta and Sharp models)
122             # (GE FujiFilm models start with "GENERALE")
123             Condition => '$$valPt =~ /^(FUJIFILM|GENERALE)/',
124             SubDirectory => {
125             TagTable => 'Image::ExifTool::FujiFilm::Main',
126             # there is an 8-byte maker tag (FUJIFILM) we must skip over
127             OffsetPt => '$valuePtr+8',
128             # the pointers are relative to the subdirectory start
129             # (before adding the offsetPt) - PH
130             Base => '$start',
131             ByteOrder => 'LittleEndian',
132             },
133             },
134             {
135             Name => 'MakerNoteGE',
136             Condition => '$$valPt =~ /^GE(\0\0|NIC\0)/',
137             SubDirectory => {
138             TagTable => 'Image::ExifTool::GE::Main',
139             Start => '$valuePtr + 18',
140             FixBase => 1,
141             AutoFix => 1,
142             ByteOrder => 'Unknown',
143             },
144             },
145             {
146             Name => 'MakerNoteGE2',
147             Condition => '$$valPt =~ /^GE\x0c\0\0\0\x16\0\0\0/',
148             # Note: we will get a "Maker notes could not be parsed" warning when writing
149             # these maker notes because they aren't currently supported for writing
150             SubDirectory => {
151             TagTable => 'Image::ExifTool::FujiFilm::Main',
152             ProcessProc => \&ProcessGE2,
153             Start => '$valuePtr + 12',
154             Base => '$start - 6',
155             ByteOrder => 'LittleEndian',
156             # hard patch for crazy offsets
157             FixOffsets => '$valuePtr -= 210 if $tagID >= 0x1303',
158             },
159             },
160             {
161             Name => 'MakerNoteHasselblad',
162             Condition => '$$self{Make} eq "Hasselblad"',
163             SubDirectory => {
164             TagTable => 'Image::ExifTool::Unknown::Main',
165             ByteOrder => 'Unknown',
166             Start => '$valuePtr',
167             Base => 0, # (avoids warnings since maker notes are not self-contained)
168             },
169             # 0x0011 - sensor code (ref IB)
170             # 0x0012 - camera model id?
171             # 0x0015 - camera model name
172             # 0x0016 - coating code (ref IB)
173             },
174             # (the GE X5 has really messed up EXIF-like maker notes starting with
175             # "GENIC\x0c\0" --> currently not decoded)
176             {
177             Name => 'MakerNoteHP', # PhotoSmart 720 (also Vivitar 3705, 3705B and 3715)
178             Condition => '$$valPt =~ /^(Hewlett-Packard|Vivitar)/',
179             SubDirectory => {
180             TagTable => 'Image::ExifTool::HP::Main',
181             ProcessProc => \&ProcessUnknown,
182             ByteOrder => 'Unknown',
183             },
184             },
185             {
186             Name => 'MakerNoteHP2', # PhotoSmart E427
187             # (this type of maker note also used by BenQ, Mustek, Sanyo, Traveler and Vivitar)
188             Condition => '$$valPt =~ /^610[\0-\4]/',
189             NotIFD => 1,
190             SubDirectory => {
191             TagTable => 'Image::ExifTool::HP::Type2',
192             Start => '$valuePtr',
193             ByteOrder => 'LittleEndian',
194             },
195             },
196             {
197             Name => 'MakerNoteHP4', # PhotoSmart M627
198             Condition => '$$valPt =~ /^IIII\x04\0/',
199             NotIFD => 1,
200             SubDirectory => {
201             TagTable => 'Image::ExifTool::HP::Type4',
202             Start => '$valuePtr',
203             ByteOrder => 'LittleEndian',
204             },
205             },
206             {
207             Name => 'MakerNoteHP6', # PhotoSmart M425, M525 and M527
208             Condition => '$$valPt =~ /^IIII\x06\0/',
209             NotIFD => 1,
210             SubDirectory => {
211             TagTable => 'Image::ExifTool::HP::Type6',
212             Start => '$valuePtr',
213             ByteOrder => 'LittleEndian',
214             },
215             },
216             {
217             Name => 'MakerNoteISL', # (used in Samsung GX20 samples)
218             Condition => '$$valPt =~ /^ISLMAKERNOTE000\0/',
219             # this maker notes starts with a TIFF-like header at offset 0x10
220             SubDirectory => {
221             TagTable => 'Image::ExifTool::Unknown::Main',
222             Start => '$valuePtr + 24',
223             Base => '$start - 8',
224             ByteOrder => 'Unknown',
225             },
226             },
227             {
228             Name => 'MakerNoteJVC',
229             Condition => '$$valPt=~/^JVC /',
230             SubDirectory => {
231             TagTable => 'Image::ExifTool::JVC::Main',
232             Start => '$valuePtr + 4',
233             ByteOrder => 'Unknown',
234             },
235             },
236             {
237             Name => 'MakerNoteJVCText',
238             Condition => '$$self{Make}=~/^(JVC|Victor)/ and $$valPt=~/^VER:/',
239             NotIFD => 1,
240             SubDirectory => {
241             TagTable => 'Image::ExifTool::JVC::Text',
242             },
243             },
244             {
245             Name => 'MakerNoteKodak1a',
246             Condition => '$$self{Make}=~/^EASTMAN KODAK/ and $$valPt=~/^KDK INFO/',
247             NotIFD => 1,
248             SubDirectory => {
249             TagTable => 'Image::ExifTool::Kodak::Main',
250             Start => '$valuePtr + 8',
251             ByteOrder => 'BigEndian',
252             },
253             },
254             {
255             Name => 'MakerNoteKodak1b',
256             Condition => '$$self{Make}=~/^EASTMAN KODAK/ and $$valPt=~/^KDK/',
257             NotIFD => 1,
258             SubDirectory => {
259             TagTable => 'Image::ExifTool::Kodak::Main',
260             Start => '$valuePtr + 8',
261             ByteOrder => 'LittleEndian',
262             },
263             },
264             {
265             # used by various Kodak, HP, Pentax and Minolta models
266             Name => 'MakerNoteKodak2',
267             Condition => q{
268             $$valPt =~ /^.{8}Eastman Kodak/s or
269             $$valPt =~ /^\x01\0[\0\x01]\0\0\0\x04\0[a-zA-Z]{4}/
270             },
271             NotIFD => 1,
272             SubDirectory => {
273             TagTable => 'Image::ExifTool::Kodak::Type2',
274             ByteOrder => 'BigEndian',
275             },
276             },
277             {
278             # not much to key on here, but we know the
279             # upper byte of the year should be 0x07:
280             Name => 'MakerNoteKodak3',
281             Condition => q{
282             $$self{Make} =~ /^EASTMAN KODAK/ and
283             $$valPt =~ /^(?!MM|II).{12}\x07/s and
284             $$valPt !~ /^(MM|II|AOC)/
285             },
286             NotIFD => 1,
287             SubDirectory => {
288             TagTable => 'Image::ExifTool::Kodak::Type3',
289             ByteOrder => 'BigEndian',
290             },
291             },
292             {
293             Name => 'MakerNoteKodak4',
294             Condition => q{
295             $$self{Make} =~ /^Eastman Kodak/ and
296             $$valPt =~ /^.{41}JPG/s and
297             $$valPt !~ /^(MM|II|AOC)/
298             },
299             NotIFD => 1,
300             SubDirectory => {
301             TagTable => 'Image::ExifTool::Kodak::Type4',
302             ByteOrder => 'BigEndian',
303             },
304             },
305             {
306             Name => 'MakerNoteKodak5',
307             Condition => q{
308             $$self{Make}=~/^EASTMAN KODAK/ and
309             ($$self{Model}=~/CX(4200|4230|4300|4310|6200|6230)/ or
310             # try to pick up similar models we haven't tested yet
311             $$valPt=~/^\0(\x1a\x18|\x3a\x08|\x59\xf8|\x14\x80)\0/)
312             },
313             NotIFD => 1,
314             SubDirectory => {
315             TagTable => 'Image::ExifTool::Kodak::Type5',
316             ByteOrder => 'BigEndian',
317             },
318             },
319             {
320             Name => 'MakerNoteKodak6a',
321             Condition => q{
322             $$self{Make}=~/^EASTMAN KODAK/ and
323             $$self{Model}=~/DX3215/
324             },
325             NotIFD => 1,
326             SubDirectory => {
327             TagTable => 'Image::ExifTool::Kodak::Type6',
328             ByteOrder => 'BigEndian',
329             },
330             },
331             {
332             Name => 'MakerNoteKodak6b',
333             Condition => q{
334             $$self{Make}=~/^EASTMAN KODAK/ and
335             $$self{Model}=~/DX3700/
336             },
337             NotIFD => 1,
338             SubDirectory => {
339             TagTable => 'Image::ExifTool::Kodak::Type6',
340             ByteOrder => 'LittleEndian',
341             },
342             },
343             {
344             Name => 'MakerNoteKodak7',
345             # look for something that looks like a serial number
346             # (confirmed serial numbers have the format KXXXX########, but we also
347             # accept other strings from sample images that may be serial numbers)
348             Condition => q{
349             $$self{Make}=~/Kodak/i and
350             $$valPt =~ /^[CK][A-Z\d]{3} ?[A-Z\d]{1,2}\d{2}[A-Z\d]\d{4}[ \0]/
351             },
352             NotIFD => 1,
353             SubDirectory => {
354             TagTable => 'Image::ExifTool::Kodak::Type7',
355             ByteOrder => 'LittleEndian',
356             },
357             },
358             {
359             Name => 'MakerNoteKodak8a',
360             # IFD-format maker notes: look for reasonable number of
361             # entries and check format and count of first IFD entry
362             Condition => q{
363             $$self{Make}=~/Kodak/i and
364             ($$valPt =~ /^\0[\x02-\x7f]..\0[\x01-\x0c]\0\0/s or
365             $$valPt =~ /^[\x02-\x7f]\0..[\x01-\x0c]\0..\0\0/s)
366             },
367             SubDirectory => {
368             TagTable => 'Image::ExifTool::Kodak::Type8',
369             ProcessProc => \&ProcessUnknown,
370             ByteOrder => 'Unknown',
371             },
372             },
373             {
374             Name => 'MakerNoteKodak8b',
375             # these maker notes have an extra 2 bytes after the entry count
376             # (this is handled by the patch). Also, the IFD uses a Format 13,
377             # which is some 2-byte format (not Float, as decoded by ExifTool)
378             # - written by the PixPro AZ251, AZ361, AZ262, AZ521
379             Condition => q{
380             $$self{Make}=~/Kodak/i and
381             $$valPt =~ /^MM\0\x2a\0\0\0\x08\0.\0\0/
382             },
383             SubDirectory => {
384             TagTable => 'Image::ExifTool::Kodak::Type8',
385             ProcessProc => \&ProcessKodakPatch,
386             ByteOrder => 'BigEndian',
387             Start => '$valuePtr + 8',
388             Base => '$start - 8',
389             },
390             },
391             {
392             Name => 'MakerNoteKodak8c',
393             # TIFF-format maker notes
394             Condition => q{
395             $$self{Make}=~/Kodak/i and
396             $$valPt =~ /^(MM\0\x2a\0\0\0\x08|II\x2a\0\x08\0\0\0)/
397             },
398             SubDirectory => {
399             TagTable => 'Image::ExifTool::Kodak::Type8',
400             ProcessProc => \&ProcessUnknown,
401             ByteOrder => 'Unknown',
402             Start => '$valuePtr + 8',
403             Base => '$start - 8',
404             },
405             },
406             {
407             Name => 'MakerNoteKodak9',
408             # test header and Kodak:DateTimeOriginal
409             Condition => '$$valPt =~ m{^IIII[\x02\x03]\0.{14}\d{4}/\d{2}/\d{2} }s',
410             NotIFD => 1,
411             SubDirectory => {
412             TagTable => 'Image::ExifTool::Kodak::Type9',
413             ByteOrder => 'LittleEndian',
414             },
415             },
416             {
417             Name => 'MakerNoteKodak10',
418             # yet another type of Kodak IFD-format maker notes:
419             # this type begins with a byte order indicator,
420             # followed immediately by the IFD
421             Condition => q{
422             $$self{Make}=~/Kodak/i and
423             $$valPt =~ /^(MM\0[\x02-\x7f]|II[\x02-\x7f]\0)/
424             },
425             SubDirectory => {
426             TagTable => 'Image::ExifTool::Kodak::Type10',
427             ProcessProc => \&ProcessUnknown,
428             ByteOrder => 'Unknown',
429             Start => '$valuePtr + 2',
430             },
431             },
432             {
433             Name => 'MakerNoteKodak11',
434             # these maker notes have a 4-byte entry count
435             # - written by the PixPro S-1 (Note: Make is "JK Imaging, Ltd.", so check Model for "Kodak")
436             Condition => q{
437             $$self{Model}=~/(Kodak|PixPro)/i and
438             $$valPt =~ /^II\x2a\0\x08\0\0\0.\0\0\0/s
439             },
440             SubDirectory => {
441             TagTable => 'Image::ExifTool::Kodak::Type11',
442             ProcessProc => \&ProcessKodakPatch,
443             ByteOrder => 'LittleEndian',
444             Start => '$valuePtr + 8',
445             Base => '$start - 8',
446             },
447             },
448             {
449             Name => 'MakerNoteKodak12',
450             # these maker notes have a 4-byte entry count
451             # - written by the PixPro AZ901 (Note: Make is "JK Imaging, Ltd.", so check Model for "Kodak")
452             Condition => q{
453             $$self{Model}=~/(Kodak|PixPro)/i and
454             $$valPt =~ /^MM\0\x2a\0\0\0\x08\0\0\0./s
455             },
456             SubDirectory => {
457             TagTable => 'Image::ExifTool::Kodak::Type11',
458             ProcessProc => \&ProcessKodakPatch,
459             ByteOrder => 'BigEndian',
460             Start => '$valuePtr + 8',
461             Base => '$start - 8',
462             },
463             },
464             {
465             Name => 'MakerNoteKodakUnknown',
466             Condition => '$$self{Make}=~/Kodak/i and $$valPt!~/^AOC\0/',
467             NotIFD => 1,
468             SubDirectory => {
469             TagTable => 'Image::ExifTool::Kodak::Unknown',
470             ByteOrder => 'BigEndian',
471             },
472             },
473             {
474             Name => 'MakerNoteKyocera',
475             # (starts with "KYOCERA")
476             Condition => '$$valPt =~ /^KYOCERA/',
477             SubDirectory => {
478             TagTable => 'Image::ExifTool::Unknown::Main',
479             Start => '$valuePtr + 22',
480             Base => '$start + 2',
481             EntryBased => 1,
482             ByteOrder => 'Unknown',
483             },
484             },
485             {
486             Name => 'MakerNoteMinolta',
487             Condition => q{
488             $$self{Make}=~/^(Konica Minolta|Minolta)/i and
489             $$valPt !~ /^(MINOL|CAMER|MLY0|KC|\+M\+M|\xd7)/
490             },
491             SubDirectory => {
492             TagTable => 'Image::ExifTool::Minolta::Main',
493             ByteOrder => 'Unknown',
494             },
495             },
496             {
497             # the DiMAGE E323 (MINOL) and E500 (CAMER), and some models
498             # of Mustek, Pentax, Ricoh and Vivitar (CAMER).
499             Name => 'MakerNoteMinolta2',
500             Condition => '$$valPt =~ /^(MINOL|CAMER)\0/ and $$self{OlympusCAMER} = 1',
501             SubDirectory => {
502             # these models use Olympus tags in the range 0x200-0x221 plus 0xf00
503             TagTable => 'Image::ExifTool::Olympus::Main',
504             Start => '$valuePtr + 8',
505             ByteOrder => 'Unknown',
506             },
507             },
508             {
509             # /^MLY0/ - DiMAGE G400, G500, G530, G600
510             # /^KC/ - Revio KD-420Z, DiMAGE E203
511             # /^+M+M/ - DiMAGE E201
512             # /^\xd7/ - DiMAGE RD3000
513             Name => 'MakerNoteMinolta3',
514             Condition => '$$self{Make} =~ /^(Konica Minolta|Minolta)/i',
515             Binary => 1,
516             Notes => 'not EXIF-based',
517             },
518             {
519             Name => 'MakerNoteMotorola',
520             Condition => '$$valPt=~/^MOT\0/',
521             SubDirectory => {
522             TagTable => 'Image::ExifTool::Motorola::Main',
523             Start => '$valuePtr + 8',
524             Base => '$start - 8',
525             ByteOrder => 'Unknown',
526             },
527             },
528             {
529             # older Nikon maker notes
530             Name => 'MakerNoteNikon2',
531             Condition => '$$valPt=~/^Nikon\x00\x01/',
532             SubDirectory => {
533             TagTable => 'Image::ExifTool::Nikon::Type2',
534             Start => '$valuePtr + 8',
535             ByteOrder => 'LittleEndian',
536             },
537             },
538             {
539             # headerless Nikon maker notes
540             Name => 'MakerNoteNikon3',
541             Condition => '$$self{Make}=~/^NIKON/i',
542             SubDirectory => {
543             TagTable => 'Image::ExifTool::Nikon::Main',
544             ByteOrder => 'Unknown', # most are little-endian, but D1 is big
545             },
546             },
547             {
548             Name => 'MakerNoteNintendo',
549             # (starts with an IFD)
550             Condition => '$$self{Make} eq "Nintendo"',
551             SubDirectory => {
552             TagTable => 'Image::ExifTool::Nintendo::Main',
553             ByteOrder => 'Unknown',
554             },
555             },
556             {
557             Name => 'MakerNoteOlympus',
558             # (if Make is 'SEIKO EPSON CORP.', starts with "EPSON\0")
559             # (if Make is 'OLYMPUS OPTICAL CO.,LTD' or 'OLYMPUS CORPORATION',
560             # starts with "OLYMP\0")
561             Condition => '$$valPt =~ /^(OLYMP|EPSON)\0/',
562             SubDirectory => {
563             TagTable => 'Image::ExifTool::Olympus::Main',
564             Start => '$valuePtr + 8',
565             ByteOrder => 'Unknown',
566             },
567             },
568             {
569             Name => 'MakerNoteOlympus2',
570             # new Olympus maker notes start with "OLYMPUS\0"
571             Condition => '$$valPt =~ /^OLYMPUS\0/',
572             SubDirectory => {
573             TagTable => 'Image::ExifTool::Olympus::Main',
574             Start => '$valuePtr + 12',
575             Base => '$start - 12',
576             ByteOrder => 'Unknown',
577             },
578             },
579             {
580             Name => 'MakerNoteOlympus3',
581             # new Olympus maker notes start with "OLYMPUS\0"
582             Condition => '$$valPt =~ /^OM SYSTEM\0/',
583             SubDirectory => {
584             TagTable => 'Image::ExifTool::Olympus::Main',
585             Start => '$valuePtr + 16',
586             Base => '$start - 16',
587             ByteOrder => 'Unknown',
588             },
589             },
590             {
591             Name => 'MakerNoteLeica',
592             # (starts with "LEICA\0\0\0")
593             Condition => '$$self{Make} eq "LEICA"',
594             SubDirectory => {
595             # many Leica models use the same format as Panasonic
596             TagTable => 'Image::ExifTool::Panasonic::Main',
597             Start => '$valuePtr + 8',
598             ByteOrder => 'Unknown',
599             },
600             },
601             {
602             Name => 'MakerNoteLeica2', # used by the M8
603             # (starts with "LEICA\0\0\0")
604             Condition => '$$self{Make} =~ /^Leica Camera AG/ and $$valPt =~ /^LEICA\0\0\0/',
605             SubDirectory => {
606             TagTable => 'Image::ExifTool::Panasonic::Leica2',
607             # (the offset base is different in JPEG and DNG images, but we
608             # can copy makernotes from one to the other, so we need special
609             # logic to decide which base to apply)
610             ProcessProc => \&FixLeicaBase,
611             Start => '$valuePtr + 8',
612             Base => '$start', # (- 8 for DNG images!)
613             ByteOrder => 'Unknown',
614             },
615             },
616             {
617             Name => 'MakerNoteLeica3', # used by the R8 and R9
618             # (starts with IFD)
619             Condition => q{
620             $$self{Make} =~ /^Leica Camera AG/ and $$valPt !~ /^LEICA/ and
621             $$self{Model} ne "S2" and $$self{Model} ne "LEICA M (Typ 240)"
622             },
623             SubDirectory => {
624             TagTable => 'Image::ExifTool::Panasonic::Leica3',
625             Start => '$valuePtr',
626             ByteOrder => 'Unknown',
627             },
628             },
629             {
630             Name => 'MakerNoteLeica4', # used by the M9/M-Monochrom
631             # (M9 and M Monochrom start with "LEICA0\x03\0")
632             Condition => '$$self{Make} =~ /^Leica Camera AG/ and $$valPt =~ /^LEICA0/',
633             SubDirectory => {
634             TagTable => 'Image::ExifTool::Panasonic::Leica4',
635             Start => '$valuePtr + 8',
636             Base => '$start - 8', # (yay! Leica fixed the M8 problem)
637             ByteOrder => 'Unknown',
638             },
639             },
640             {
641             Name => 'MakerNoteLeica5', # used by the X1/X2/X VARIO/T/X-U
642             # (X1 starts with "LEICA\0\x01\0", Make is "LEICA CAMERA AG")
643             # (X2 starts with "LEICA\0\x05\0", Make is "LEICA CAMERA AG")
644             # (X VARIO starts with "LEICA\0\x04\0", Make is "LEICA CAMERA AG")
645             # (T (Typ 701) starts with "LEICA\0\0x6", Make is "LEICA CAMERA AG")
646             # (X (Typ 113) starts with "LEICA\0\0x7", Make is "LEICA CAMERA AG")
647             # (X-U (Typ 113) starts with "LEICA\0\x10\0", Make is "LEICA CAMERA AG")
648             Condition => '$$valPt =~ /^LEICA\0[\x01\x04\x05\x06\x07\x10\x1a]\0/',
649             SubDirectory => {
650             TagTable => 'Image::ExifTool::Panasonic::Leica5',
651             Start => '$valuePtr + 8',
652             Base => '$start - 8',
653             ByteOrder => 'Unknown',
654             },
655             },
656             {
657             Name => 'MakerNoteLeica6', # used by the S2, M (Typ 240) and S (Typ 006)
658             # (starts with "LEICA\0\x02\xff", Make is "Leica Camera AG", but test the
659             # model names separately because the maker notes data may not be loaded
660             # at the time this is tested if they are in a JPEG trailer. Also, this
661             # header is used by the M Monochrom (Type 246), with different offsets.)
662             Condition => q{
663             ($$self{Make} eq 'Leica Camera AG' and ($$self{Model} eq 'S2' or
664             $$self{Model} eq 'LEICA M (Typ 240)' or $$self{Model} eq 'LEICA S (Typ 006)'))
665             },
666             DataTag => 'LeicaTrailer', # (generates fixup name for this tag)
667             LeicaTrailer => 1, # flag to special-case this tag in the Exif code
668             SubDirectory => {
669             TagTable => 'Image::ExifTool::Panasonic::Leica6',
670             Start => '$valuePtr + 8',
671             ByteOrder => 'Unknown',
672             # NOTE: Leica uses absolute file offsets when this maker note is stored
673             # as a JPEG trailer -- this case is handled by ProcessLeicaTrailer in
674             # Panasonic.pm, and any "Base" defined here is ignored for this case.
675             # ExifTool may also create S2/M maker notes inside the APP1 segment when
676             # copying from other files, and for this the normal EXIF offsets are used,
677             # Base should not be defined!
678             },
679             },
680             {
681             Name => 'MakerNoteLeica7', # used by the M Monochrom (Typ 246)
682             # (starts with "LEICA\0\x02\xff", Make is "Leica Camera AG")
683             Condition => '$$valPt =~ /^LEICA\0\x02\xff/',
684             DataTag => 'LeicaTrailer', # (generates fixup name for this tag)
685             LeicaTrailer => 1, # flag to special-case this tag in the Exif code
686             SubDirectory => {
687             TagTable => 'Image::ExifTool::Panasonic::Leica6',
688             Start => '$valuePtr + 8',
689             ByteOrder => 'Unknown',
690             Base => '-$base', # uses absolute file offsets (not based on TIFF header offset)
691             },
692             },
693             {
694             Name => 'MakerNoteLeica8', # used by the Q (Type 116)
695             # (Q (Typ 116) starts with "LEICA\0\x08\0", Make is "LEICA CAMERA AG")
696             # (SL (Typ 601) and CL start with "LEICA\0\x09\0", Make is "LEICA CAMERA AG")
697             Condition => '$$valPt =~ /^LEICA\0[\x08\x09]\0/',
698             SubDirectory => {
699             TagTable => 'Image::ExifTool::Panasonic::Leica5',
700             Start => '$valuePtr + 8',
701             ByteOrder => 'Unknown',
702             },
703             },
704             {
705             Name => 'MakerNoteLeica9', # used by the M10/S
706             # (M10 and S start with "LEICA0\x02\0")
707             Condition => '$$self{Make} =~ /^Leica Camera AG/ and $$valPt =~ /^LEICA\0\x02\0/',
708             SubDirectory => {
709             TagTable => 'Image::ExifTool::Panasonic::Leica9',
710             Start => '$valuePtr + 8',
711             ByteOrder => 'Unknown',
712             },
713             },
714             {
715             Name => 'MakerNoteLeica10', # used by the D-Lux7
716             Condition => '$$valPt =~ /^LEICA CAMERA AG\0/',
717             SubDirectory => {
718             TagTable => 'Image::ExifTool::Panasonic::Main',
719             Start => '$valuePtr + 18',
720             ByteOrder => 'Unknown',
721             },
722             },
723             {
724             Name => 'MakerNotePanasonic',
725             # (starts with "Panasonic\0")
726             Condition => '$$valPt=~/^Panasonic/ and $$self{Model} ne "DC-FT7"',
727             SubDirectory => {
728             TagTable => 'Image::ExifTool::Panasonic::Main',
729             Start => '$valuePtr + 12',
730             ByteOrder => 'Unknown',
731             },
732             },
733             {
734             Name => 'MakerNotePanasonic2',
735             # (starts with "Panasonic\0")
736             Condition => '$$self{Make}=~/^Panasonic/ and $$valPt=~/^MKE/',
737             SubDirectory => {
738             TagTable => 'Image::ExifTool::Panasonic::Type2',
739             ByteOrder => 'LittleEndian',
740             },
741             },
742             {
743             Name => 'MakerNotePanasonic3', # (DC-FT7)
744             # (starts with "Panasonic\0")
745             Condition => '$$valPt=~/^Panasonic/',
746             SubDirectory => {
747             TagTable => 'Image::ExifTool::Panasonic::Main',
748             Start => '$valuePtr + 12',
749             Base => 12, # crazy!
750             ByteOrder => 'Unknown',
751             },
752             },
753             {
754             Name => 'MakerNotePentax',
755             # (starts with "AOC\0", but so does MakerNotePentax3)
756             # (also used by some Samsung models)
757             Condition => q{
758             $$valPt=~/^AOC\0/ and
759             $$self{Model} !~ /^PENTAX Optio ?[34]30RS\s*$/
760             },
761             SubDirectory => {
762             TagTable => 'Image::ExifTool::Pentax::Main',
763             # process as Unknown maker notes because the start offset and
764             # byte ordering are so variable
765             ProcessProc => \&ProcessUnknown,
766             # offsets can be totally whacky for Pentax maker notes,
767             # so attempt to fix the offset base if possible
768             FixBase => 1,
769             ByteOrder => 'Unknown',
770             },
771             },
772             {
773             Name => 'MakerNotePentax2',
774             # (starts with an IFD)
775             # Casio-like maker notes used only by the Optio 330 and 430
776             Condition => '$$self{Make}=~/^Asahi/ and $$valPt!~/^AOC\0/',
777             SubDirectory => {
778             TagTable => 'Image::ExifTool::Pentax::Type2',
779             ProcessProc => \&ProcessUnknown,
780             FixBase => 1,
781             ByteOrder => 'Unknown',
782             },
783             },
784             {
785             Name => 'MakerNotePentax3',
786             # (starts with "AOC\0", like the more common Pentax maker notes)
787             # Casio maker notes used only by the Optio 330RS and 430RS
788             Condition => '$$self{Make}=~/^Asahi/',
789             SubDirectory => {
790             TagTable => 'Image::ExifTool::Casio::Type2',
791             ProcessProc => \&ProcessUnknown,
792             FixBase => 1,
793             ByteOrder => 'Unknown',
794             },
795             },
796             {
797             Name => 'MakerNotePentax4',
798             # (starts with 3 or 4 digits)
799             # HP2-like text-based maker notes used by Optio E20
800             Condition => '$$self{Make}=~/^PENTAX/ and $$valPt=~/^\d{3}/',
801             NotIFD => 1,
802             SubDirectory => {
803             TagTable => 'Image::ExifTool::Pentax::Type4',
804             Start => '$valuePtr',
805             ByteOrder => 'LittleEndian',
806             },
807             },
808             {
809             Name => 'MakerNotePentax5',
810             # (starts with "PENTAX \0")
811             # used by cameras such as the Q, Optio S1, RS1500 and WG-1
812             Condition => '$$valPt=~/^PENTAX \0/',
813             SubDirectory => {
814             TagTable => 'Image::ExifTool::Pentax::Main',
815             Start => '$valuePtr + 10',
816             Base => '$start - 10',
817             ByteOrder => 'Unknown',
818             },
819             },
820             {
821             Name => 'MakerNotePentax6',
822             # (starts with "S1\0\0\0\0\0\0\x0c\0\0\0")
823             Condition => '$$valPt=~/^S1\0{6}\x0c\0{3}/',
824             SubDirectory => {
825             TagTable => 'Image::ExifTool::Pentax::S1',
826             Start => '$valuePtr + 12',
827             Base => '$start - 12',
828             ByteOrder => 'Unknown',
829             },
830             },
831             {
832             Name => 'MakerNotePhaseOne',
833             # Starts with: 'IIIITwaR' or 'IIIICwaR' (have seen both written by P25)
834             # (have also seen code which expects 'MMMMRawT')
835             Condition => q{
836             return undef unless $$valPt =~ /^(IIII.waR|MMMMRaw.)/s;
837             $self->OverrideFileType($$self{TIFF_TYPE} = 'IIQ') if $count > 1000000;
838             return 1;
839             },
840             NotIFD => 1,
841             IsPhaseOne => 1, # flag to rebuild these differently
842             SubDirectory => { TagTable => 'Image::ExifTool::PhaseOne::Main' },
843             PutFirst => 1, # place immediately after TIFF header
844             },
845             {
846             Name => 'MakerNoteReconyx',
847             Condition => q{
848             $$valPt =~ /^\x01\xf1([\x02\x03]\x00)?/ and
849             ($1 or $$self{Make} eq "RECONYX")
850             },
851             SubDirectory => {
852             TagTable => 'Image::ExifTool::Reconyx::Main',
853             ByteOrder => 'Little-endian',
854             },
855             },
856             {
857             Name => 'MakerNoteReconyx2',
858             Condition => '$$valPt =~ /^RECONYXUF\0/',
859             SubDirectory => {
860             TagTable => 'Image::ExifTool::Reconyx::Type2',
861             ByteOrder => 'Little-endian',
862             },
863             },
864             {
865             Name => 'MakerNoteReconyx3',
866             Condition => '$$valPt =~ /^RECONYXH2\0/',
867             SubDirectory => {
868             TagTable => 'Image::ExifTool::Reconyx::Type3',
869             ByteOrder => 'Little-endian',
870             },
871             },
872             {
873             Name => 'MakerNoteRicohPentax',
874             # used by cameras such as the Ricoh GR III
875             Condition => '$$valPt=~/^RICOH\0(II|MM)/',
876             SubDirectory => {
877             TagTable => 'Image::ExifTool::Pentax::Main',
878             Start => '$valuePtr + 8',
879             Base => '$start - 8',
880             ByteOrder => 'Unknown',
881             },
882             },
883             {
884             Name => 'MakerNoteRicoh',
885             # (my test R50 image starts with " \x02\x01" - PH)
886             Condition => q{
887             $$self{Make} =~ /^(PENTAX )?RICOH/ and
888             $$valPt =~ /^(Ricoh| |MM\0\x2a|II\x2a\0)/i and
889             $$valPt !~ /^(MM\0\x2a\0\0\0\x08\0.\0\0|II\x2a\0\x08\0\0\0.\0\0\0)/s and
890             $$self{Model} ne 'RICOH WG-M1'
891             },
892             SubDirectory => {
893             TagTable => 'Image::ExifTool::Ricoh::Main',
894             Start => '$valuePtr + 8',
895             ByteOrder => 'Unknown',
896             },
897             },
898             {
899             Name => 'MakerNoteRicoh2',
900             # (the Ricoh HZ15 starts with "MM\0\x2a" and the Pentax XG-1 starts with "II\x2a\0",
901             # but an extra 2 bytes of padding after the IFD entry count prevents these from
902             # being processed as a standard IFD. Note that the offsets for the HZ15 are all
903             # zeros, but they seem to be mostly OK for the XG-1)
904             Condition => q{
905             $$self{Make} =~ /^(PENTAX )?RICOH/ and ($$self{Model} eq 'RICOH WG-M1' or
906             $$valPt =~ /^(MM\0\x2a\0\0\0\x08\0.\0\0|II\x2a\0\x08\0\0\0.\0\0\0)/s)
907             },
908             SubDirectory => {
909             TagTable => 'Image::ExifTool::Ricoh::Type2',
910             Start => '$valuePtr + 8',
911             Base => '$start - 8',
912             ByteOrder => 'Unknown',
913             ProcessProc => \&ProcessKodakPatch,
914             },
915             },
916             {
917             Name => 'MakerNoteRicohText',
918             Condition => '$$self{Make}=~/^RICOH/',
919             NotIFD => 1,
920             SubDirectory => {
921             TagTable => 'Image::ExifTool::Ricoh::Text',
922             ByteOrder => 'Unknown',
923             },
924             },
925             {
926             Name => 'MakerNoteSamsung1a',
927             # Samsung STMN maker notes WITHOUT PreviewImage
928             Condition => '$$valPt =~ /^STMN\d{3}.\0{4}/s',
929             Binary => 1,
930             Notes => 'Samsung "STMN" maker notes without PreviewImage',
931             },
932             {
933             Name => 'MakerNoteSamsung1b',
934             # Samsung STMN maker notes WITH PreviewImage
935             Condition => '$$valPt =~ /^STMN\d{3}/',
936             SubDirectory => {
937             TagTable => 'Image::ExifTool::Samsung::Main',
938             },
939             },
940             {
941             Name => 'MakerNoteSamsung2',
942             # Samsung EXIF-format maker notes (
943             Condition => q{
944             uc $$self{Make} eq 'SAMSUNG' and ($$self{TIFF_TYPE} eq 'SRW' or
945             $$valPt=~/^(\0.\0\x01\0\x07\0{3}\x04|.\0\x01\0\x07\0\x04\0{3})0100/s)
946             },
947             SubDirectory => {
948             TagTable => 'Image::ExifTool::Samsung::Type2',
949             # Samsung is very inconsistent here, and uses absolute offsets for some
950             # models and relative offsets for others, so process as Unknown
951             ProcessProc => \&ProcessUnknown,
952             FixBase => 1,
953             ByteOrder => 'Unknown',
954             },
955             },
956             {
957             Name => 'MakerNoteSanyo',
958             # (starts with "SANYO\0")
959             Condition => '$$self{Make}=~/^SANYO/ and $$self{Model}!~/^(C4|J\d|S\d)\b/',
960             SubDirectory => {
961             TagTable => 'Image::ExifTool::Sanyo::Main',
962             Validate => '$val =~ /^SANYO/',
963             Start => '$valuePtr + 8',
964             ByteOrder => 'Unknown',
965             },
966             },
967             {
968             Name => 'MakerNoteSanyoC4',
969             # The C4 offsets are wrong by 12, so they must be fixed
970             Condition => '$$self{Make}=~/^SANYO/ and $$self{Model}=~/^C4\b/',
971             SubDirectory => {
972             TagTable => 'Image::ExifTool::Sanyo::Main',
973             Validate => '$val =~ /^SANYO/',
974             Start => '$valuePtr + 8',
975             FixBase => 1,
976             ByteOrder => 'Unknown',
977             },
978             },
979             {
980             Name => 'MakerNoteSanyoPatch',
981             # The J1, J2, J4, S1, S3 and S4 offsets are completely screwy
982             Condition => '$$self{Make}=~/^SANYO/',
983             SubDirectory => {
984             TagTable => 'Image::ExifTool::Sanyo::Main',
985             Validate => '$val =~ /^SANYO/',
986             Start => '$valuePtr + 8',
987             ByteOrder => 'Unknown',
988             FixOffsets => 'Image::ExifTool::Sanyo::FixOffsets($valuePtr, $valEnd, $size, $tagID, $wFlag)',
989             },
990             },
991             {
992             Name => 'MakerNoteSigma',
993             Condition => q{
994             return undef unless $$self{Make}=~/^(SIGMA|FOVEON)/;
995             # save version number in "MakerNoteSigmaVer" member variable
996             $$self{MakerNoteSigmaVer} = $$valPt=~/^SIGMA\0\0\0\0(.)/ ? ord($1) : -1;
997             return 1;
998             },
999             SubDirectory => {
1000             TagTable => 'Image::ExifTool::Sigma::Main',
1001             Validate => '$val =~ /^(SIGMA|FOVEON)/',
1002             Start => '$valuePtr + 10',
1003             ByteOrder => 'Unknown',
1004             },
1005             },
1006             {
1007             Name => 'MakerNoteSony',
1008             # (starts with "SONY DSC \0" or "SONY CAM \0")
1009             # (TF1 starts with "\0\0SONY PIC\0")
1010             # (Hasselblad models start with "VHAB \0")
1011             Condition => '$$valPt=~/^(SONY (DSC|CAM|MOBILE)|\0\0SONY PIC\0|VHAB \0)/',
1012             SubDirectory => {
1013             TagTable => 'Image::ExifTool::Sony::Main',
1014             Start => '$valuePtr + 12',
1015             ByteOrder => 'Unknown',
1016             },
1017             },
1018             {
1019             Name => 'MakerNoteSony2',
1020             # (starts with "SONY PI\0" -- DSC-S650/S700/S750)
1021             Condition => '$$valPt=~/^SONY PI\0/ and $$self{OlympusCAMER}=1',
1022             SubDirectory => {
1023             TagTable => 'Image::ExifTool::Olympus::Main',
1024             Start => '$valuePtr + 12',
1025             ByteOrder => 'Unknown',
1026             },
1027             },
1028             {
1029             Name => 'MakerNoteSony3',
1030             # (starts with "PREMI\0" -- DSC-S45/S500)
1031             Condition => '$$valPt=~/^(PREMI)\0/ and $$self{OlympusCAMER}=1',
1032             SubDirectory => {
1033             TagTable => 'Image::ExifTool::Olympus::Main',
1034             Start => '$valuePtr + 8',
1035             ByteOrder => 'Unknown',
1036             },
1037             },
1038             {
1039             Name => 'MakerNoteSony4',
1040             # (starts with "SONY PIC\0" -- DSC-H200/J20/W370/W510, MHS-TS20)
1041             Condition => '$$valPt=~/^SONY PIC\0/',
1042             SubDirectory => { TagTable => 'Image::ExifTool::Sony::PIC' },
1043             },
1044             {
1045             Name => 'MakerNoteSony5', # used in SR2 and ARW images
1046             Condition => '$$self{Make}=~/^SONY/ and $$valPt!~/^\x01\x00/',
1047             Condition => q{
1048             ($$self{Make}=~/^SONY/ or ($$self{Make}=~/^HASSELBLAD/ and
1049             $$self{Model}=~/^(HV|Stellar|Lusso|Lunar)/)) and $$valPt!~/^\x01\x00/
1050             },
1051             SubDirectory => {
1052             TagTable => 'Image::ExifTool::Sony::Main',
1053             Start => '$valuePtr',
1054             ByteOrder => 'Unknown',
1055             },
1056             },
1057             {
1058             Name => 'MakerNoteSonyEricsson',
1059             Condition => '$$valPt =~ /^SEMC MS\0/',
1060             SubDirectory => {
1061             TagTable => 'Image::ExifTool::Sony::Ericsson',
1062             Start => '$valuePtr + 20',
1063             Base => '$start - 8',
1064             ByteOrder => 'Unknown',
1065             },
1066             },
1067             {
1068             Name => 'MakerNoteSonySRF',
1069             Condition => '$$self{Make}=~/^SONY/',
1070             SubDirectory => {
1071             TagTable => 'Image::ExifTool::Sony::SRF',
1072             Start => '$valuePtr',
1073             ByteOrder => 'Unknown',
1074             },
1075             },
1076             {
1077             Name => 'MakerNoteUnknownText',
1078             Condition => '$$valPt =~ /^[\x09\x0d\x0a\x20-\x7e]+\0*$/',
1079             Notes => 'unknown text-based maker notes',
1080             # show as binary if it is too long
1081             ValueConv => 'length($val) > 64 ? \$val : $val',
1082             ValueConvInv => '$val',
1083             },
1084             {
1085             Name => 'MakerNoteUnknownBinary',
1086             # "LSI1\0" - SilverFast
1087             Condition => '$$valPt =~ /^LSI1\0/',
1088             Notes => 'unknown binary maker notes',
1089             Binary => 1,
1090             },
1091             {
1092             Name => 'MakerNoteUnknown',
1093             PossiblePreview => 1,
1094             SubDirectory => {
1095             TagTable => 'Image::ExifTool::Unknown::Main',
1096             ProcessProc => \&ProcessUnknownOrPreview,
1097             WriteProc => \&WriteUnknownOrPreview,
1098             ByteOrder => 'Unknown',
1099             FixBase => 2,
1100             },
1101             },
1102             );
1103              
1104             # insert writable properties so we can write our maker notes
1105             my $tagInfo;
1106             foreach $tagInfo (@Image::ExifTool::MakerNotes::Main) {
1107             $$tagInfo{Writable} = 'undef';
1108             $$tagInfo{Format} = 'undef', # (make sure we don't convert this when reading)
1109             $$tagInfo{WriteGroup} = 'ExifIFD';
1110             $$tagInfo{Groups} = { 1 => 'MakerNotes' };
1111             next unless $$tagInfo{SubDirectory};
1112             # make all SubDirectory tags block-writable
1113             $$tagInfo{Binary} = 1,
1114             $$tagInfo{MakerNotes} = 1;
1115             }
1116              
1117             #------------------------------------------------------------------------------
1118             # Get normal offset of value data from end of maker note IFD
1119             # Inputs: 0) ExifTool object reference
1120             # Returns: Array: 0) relative flag (undef for no change)
1121             # 1) normal offset from end of IFD to first value (empty if unknown)
1122             # 2-N) other possible offsets used by some models
1123             # Notes: Directory size should be validated before calling this routine
1124             sub GetMakerNoteOffset($)
1125             {
1126 179     179 0 458 my $et = shift;
1127             # figure out where we expect the value data based on camera type
1128 179         520 my $make = $$et{Make};
1129 179         473 my $model = $$et{Model};
1130 179         457 my ($relative, @offsets);
1131              
1132             # normally value data starts 4 bytes after end of directory, so this is the default.
1133             # offsets of 0 and 4 are always allowed even if not specified,
1134             # but the first offset specified is the one used when writing
1135 179 100 100     3365 if ($make =~ /^Canon/) {
    100 66        
    100 33        
    50 33        
    50          
    100          
    50          
    100          
    100          
    50          
    100          
    50          
    100          
    100          
    100          
1136 62 100       465 push @offsets, ($model =~ /\b(20D|350D|REBEL XT|Kiss Digital N)\b/) ? 6 : 4;
1137             # some Canon models (FV-M30, Optura50, Optura60) leave 24 unused bytes
1138             # at the end of the IFD (2 spare IFD entries?)
1139 62 50       382 push @offsets, 28 if $model =~ /\b(FV\b|OPTURA)/;
1140             # some Canon PowerShot models leave 12 unused bytes
1141 62 50       503 push @offsets, 16 if $model =~ /(PowerShot|IXUS|IXY)/;
1142             } elsif ($make =~ /^CASIO/) {
1143             # Casio AVI and MOV images use no padding, and their JPEG's use 4,
1144             # except some models like the EX-S770,Z65,Z70,Z75 and Z700 which use 16,
1145             # and the EX-Z35 which uses 2 (grrrr...)
1146 5 50       39 push @offsets, $$et{FILE_TYPE} =~ /^(RIFF|MOV)$/ ? 0 : (4, 16, 2);
1147             } elsif ($make =~ /^(General Imaging Co.|GEDSC IMAGING CORP.)/i) {
1148 4         8 push @offsets, 0;
1149             } elsif ($make =~ /^KYOCERA/) {
1150 0         0 push @offsets, 12;
1151             } elsif ($make =~ /^Leica Camera AG/) {
1152 0 0       0 if ($model eq 'S2') {
    0          
    0          
    0          
1153             # lots of empty space before first value in S2 images
1154 0 0       0 push @offsets, 4, ($$et{FILE_TYPE} eq 'JPEG' ? 286 : 274);
1155             } elsif ($model eq 'LEICA M MONOCHROM (Typ 246)') {
1156 0         0 push @offsets, 4, 130;
1157             } elsif ($model eq 'LEICA M (Typ 240)') {
1158 0         0 push @offsets, 4, 118;
1159             } elsif ($model =~ /^(R8|R9|M8)\b/) {
1160 0         0 push @offsets, 6;
1161             } else {
1162 0         0 push @offsets, 4;
1163             }
1164             } elsif ($make =~ /^OLYMPUS/ and $model =~ /^E-(1|300|330)\b/) {
1165 4         15 push @offsets, 16;
1166             } elsif ($make =~ /^OLYMPUS/ and
1167             # these Olympus models are just weird
1168             $model =~ /^(C2500L|C-1Z?|C-5000Z|X-2|C720UZ|C725UZ|C150|C2Z|E-10|E-20|FerrariMODEL2003|u20D|u10D)\b/)
1169             {
1170             # no expected offset --> determine offset empirically via FixBase()
1171             } elsif ($make =~ /^(Panasonic|JVC)\b/) {
1172 13         37 push @offsets, 0;
1173             } elsif ($make =~ /^SONY/) {
1174             # earlier DSLR and "PREMI" models use an offset of 4
1175 12 50 33     100 if ($model =~ /^(DSLR-.*|SLT-A(33|35|55V)|NEX-(3|5|C3|VG10E))$/ or
1176             $$et{OlympusCAMER})
1177             {
1178 0         0 push @offsets, 4;
1179             } else {
1180 12         36 push @offsets, 0;
1181             }
1182             } elsif ($$et{TIFF_TYPE} eq 'SRW' and $make eq 'SAMSUNG' and $model eq 'EK-GN120') {
1183 0         0 push @offsets, 40; # patch to read most of the maker notes, but breaks PreviewIFD
1184             } elsif ($make eq 'FUJIFILM') {
1185             # some models have offset of 6, so allow that too (A345,A350,A360,A370)
1186 9         47 push @offsets, 4, 6;
1187             } elsif ($make =~ /^TOSHIBA/) {
1188             # similar to Canon, can also have 24 bytes of padding
1189 0         0 push @offsets, 0, 24;
1190             } elsif ($make =~ /^PENTAX/) {
1191 8         24 push @offsets, 4;
1192             # the Pentax addressing mode is determined automatically, but
1193             # sometimes the algorithm gets it wrong, but Pentax always uses
1194             # absolute addressing, so force it to be absolute
1195 8         26 $relative = 0;
1196             } elsif ($make =~ /^Konica Minolta/i) {
1197             # patch for DiMAGE X50, Xg, Z2 and Z10
1198 3         8 push @offsets, 4, -16;
1199             } elsif ($make =~ /^Minolta/) {
1200             # patch for DiMAGE 7, X20 and Z1
1201 4         11 push @offsets, 4, -8, -12;
1202             } else {
1203 55         166 push @offsets, 4; # the normal offset
1204             }
1205 179         847 return ($relative, @offsets);
1206             }
1207              
1208             #------------------------------------------------------------------------------
1209             # Get hash of value offsets / block sizes
1210             # Inputs: 0) Data pointer, 1) offset to start of directory,
1211             # 2) hash ref to return value pointers based on tag ID
1212             # Returns: 0) hash reference: keys are offsets, values are block sizes
1213             # 1) same thing, but with keys adjusted for value-based offsets
1214             # Notes: Directory size should be validated before calling this routine
1215             # - calculates MIN and MAX offsets in entry-based hash
1216             sub GetValueBlocks($$;$)
1217             {
1218 149     149 0 528 my ($dataPt, $dirStart, $tagPtr) = @_;
1219 149         510 my $numEntries = Get16u($dataPt, $dirStart);
1220 149         560 my ($index, $valPtr, %valBlock, %valBlkAdj, $end);
1221 149         692 for ($index=0; $index<$numEntries; ++$index) {
1222 3662         5719 my $entry = $dirStart + 2 + 12 * $index;
1223 3662         7630 my $format = Get16u($dataPt, $entry+2);
1224 3662 50 33     12062 last if $format < 1 or $format > 13;
1225 3662         7483 my $count = Get32u($dataPt, $entry+4);
1226 3662         6667 my $size = $count * $Image::ExifTool::Exif::formatSize[$format];
1227 3662 100       8320 next if $size <= 4;
1228 2103         4823 $valPtr = Get32u($dataPt, $entry+8);
1229 2103 50       6033 $tagPtr and $$tagPtr{Get16u($dataPt, $entry)} = $valPtr;
1230             # save location and size of longest block at this offset
1231 2103 50 66     6290 unless (defined $valBlock{$valPtr} and $valBlock{$valPtr} > $size) {
1232 2103         5590 $valBlock{$valPtr} = $size;
1233             }
1234             # adjust for case of value-based offsets
1235 2103         3150 $valPtr += 12 * $index;
1236 2103 50 33     4848 unless (defined $valBlkAdj{$valPtr} and $valBlkAdj{$valPtr} > $size) {
1237 2103         5408 $valBlkAdj{$valPtr} = $size;
1238 2103         3108 my $end = $valPtr + $size;
1239 2103 100       3959 if (defined $valBlkAdj{MIN}) {
1240             # save minimum only if it has a value of 12 or greater
1241 1957 100 66     6754 $valBlkAdj{MIN} = $valPtr if $valBlkAdj{MIN} < 12 or $valBlkAdj{MIN} > $valPtr;
1242 1957 100       5374 $valBlkAdj{MAX} = $end if $valBlkAdj{MAX} > $end;
1243             } else {
1244 146         432 $valBlkAdj{MIN} = $valPtr;
1245 146         607 $valBlkAdj{MAX} = $end;
1246             }
1247             }
1248             }
1249 149         872 return(\%valBlock, \%valBlkAdj);
1250             }
1251              
1252             #------------------------------------------------------------------------------
1253             # Fix base for value offsets in maker notes IFD (if necessary)
1254             # Inputs: 0) ExifTool object ref, 1) DirInfo hash ref
1255             # Return: amount of base shift (and $dirInfo Base and DataPos are updated,
1256             # FixedBy is set if offsets fixed, and Relative or EntryBased may be set)
1257             sub FixBase($$)
1258             {
1259 190     190 0 510 local $_;
1260 190         626 my ($et, $dirInfo) = @_;
1261             # don't fix base if fixing offsets individually or if we don't want to fix them
1262 190 100 66     1522 return 0 if $$dirInfo{FixOffsets} or $$dirInfo{NoFixBase};
1263              
1264 149         444 my $dataPt = $$dirInfo{DataPt};
1265 149         389 my $dataPos = $$dirInfo{DataPos};
1266 149   100     709 my $dirStart = $$dirInfo{DirStart} || 0;
1267 149         369 my $entryBased = $$dirInfo{EntryBased};
1268 149         413 my $dirName = $$dirInfo{DirName};
1269 149         610 my $fixBase = $et->Options('FixBase');
1270 149 50 33     1273 my $setBase = (defined $fixBase and $fixBase ne '') ? 1 : 0;
1271 149         484 my ($fix, $fixedBy, %tagPtr);
1272              
1273             # get hash of value block positions
1274 149         846 my ($valBlock, $valBlkAdj) = GetValueBlocks($dataPt, $dirStart, \%tagPtr);
1275 149 100       675 return 0 unless %$valBlock;
1276             # get sorted list of value offsets
1277 146         1481 my @valPtrs = sort { $a <=> $b } keys %$valBlock;
  6304         9973  
1278             #
1279             # handle special case of Canon maker notes with TIFF footer containing original offset
1280             #
1281 146 100 66     1596 if ($$et{Make} =~ /^Canon/ and $$dirInfo{DirLen} > 8) {
1282 65         253 my $footerPos = $dirStart + $$dirInfo{DirLen} - 8;
1283 65         267 my $footer = substr($$dataPt, $footerPos, 8);
1284 65 100 66     501 if ($footer =~ /^(II\x2a\0|MM\0\x2a)/ and # check for TIFF footer
1285             substr($footer,0,2) eq GetByteOrder()) # validate byte ordering
1286             {
1287 23         102 my $oldOffset = Get32u(\$footer, 4);
1288 23         87 my $newOffset = $dirStart + $dataPos;
1289 23 50       131 if ($setBase) {
1290 0         0 $fix = $fixBase;
1291             } else {
1292 23         62 $fix = $newOffset - $oldOffset;
1293 23 50       422 return 0 unless $fix;
1294             # Picasa and ACDSee have a bug where they update other offsets without
1295             # updating the TIFF footer (PH - 2009/02/25), so test for this case:
1296             # validate Canon maker note footer fix by checking offset of last value
1297 0         0 my $maxPt = $valPtrs[-1] + $$valBlock{$valPtrs[-1]};
1298             # compare to end of maker notes, taking 8-byte footer into account
1299 0         0 my $endDiff = $dirStart + $$dirInfo{DirLen} - ($maxPt - $dataPos) - 8;
1300             # ignore footer offset only if end difference is exactly correct
1301             # (allow for possible padding byte, although I have never seen this)
1302 0 0 0     0 if (not $endDiff or $endDiff == 1) {
1303 0         0 $et->Warn('Canon maker note footer may be invalid (ignored)',1);
1304 0         0 return 0;
1305             }
1306             }
1307 0         0 $et->Warn("Adjusted $dirName base by $fix",1);
1308 0         0 $$dirInfo{FixedBy} = $fix;
1309 0         0 $$dirInfo{Base} += $fix;
1310 0         0 $$dirInfo{DataPos} -= $fix;
1311 0         0 return $fix;
1312             }
1313             }
1314             #
1315             # analyze value offsets to see if they need fixing. The first task is to determine
1316             # the minimum valid offset used (this is tricky, because we have to weed out bad
1317             # offsets written by some cameras)
1318             #
1319 123         526 my $minPt = $$dirInfo{MinOffset} = $valPtrs[0]; # if life were simple, this would be it
1320 123         589 my $ifdLen = 2 + 12 * Get16u($$dirInfo{DataPt}, $dirStart);
1321 123         470 my $ifdEnd = $dirStart + $ifdLen;
1322 123         650 my ($relative, @offsets) = GetMakerNoteOffset($et);
1323 123         354 my $makeDiff = $offsets[0];
1324 123         551 my $verbose = $et->Options('Verbose');
1325 123         491 my ($diff, $shift);
1326              
1327             # calculate expected minimum value offset
1328 123 50       718 my $expected = $dataPos + $ifdEnd + (defined $makeDiff ? $makeDiff : 4);
1329 123 50       469 $debug and print "$expected expected\n";
1330              
1331             # zero our counters
1332 123         332 my ($countNeg12, $countZero, $countOverlap) = (0, 0, 0);
1333 123         304 my ($valPtr, $last);
1334 123         408 foreach $valPtr (@valPtrs) {
1335 1639 50 0     2808 printf("%d - %d (%d)\n", $valPtr, $valPtr + $$valBlock{$valPtr},
1336             $valPtr - ($last || 0)) if $debug;
1337 1639 100       2944 if (defined $last) {
1338 1516         2203 my $gap = $valPtr - $last;
1339 1516 100 100     3567 if ($gap == 0 or $gap == 1) {
    100 66        
    50          
    100          
1340 1499         2022 ++$countZero;
1341             } elsif ($gap == -12 and not $entryBased) {
1342             # you get this when value offsets are relative to the IFD entry
1343 12         17 ++$countNeg12;
1344             } elsif ($gap < 0) {
1345             # any other negative difference indicates overlapping values
1346 0 0       0 ++$countOverlap if $valPtr; # (but ignore zero value pointers)
1347             } elsif ($gap >= $ifdLen) {
1348             # ignore previous minimum if we took a jump to near the expected value
1349             # (some values can be stored before the IFD)
1350 2 50       9 $minPt = $valPtr if abs($valPtr - $expected) <= 4;
1351             }
1352             # an offset less than 12 is surely garbage, so ignore it
1353 1516 100       2712 $minPt = $valPtr if $minPt < 12;
1354             }
1355 1639         2796 $last = $valPtr + $$valBlock{$valPtr};
1356             }
1357             # could this IFD be using entry-based offsets?
1358 123 100 66     2011 if ((($countNeg12 > $countZero and $$valBlkAdj{MIN} >= $ifdLen - 2) or
      66        
1359             ($$valBlkAdj{MIN} == $ifdLen - 2 or $$valBlkAdj{MIN} == $ifdLen + 2)
1360             ) and $$valBlkAdj{MAX} <= $$dirInfo{DirLen}-2)
1361             {
1362             # looks like these offsets are entry-based, so use the offsets
1363             # which have been correcting for individual entry position
1364 3         9 $entryBased = 1;
1365 3 50       9 $verbose and $et->Warn("$dirName offsets are entry-based",1);
1366             } else {
1367             # calculate offset difference from end of IFD to first value
1368 120         375 $diff = ($minPt - $dataPos) - $ifdEnd;
1369 120         329 $shift = 0;
1370 120 50       390 $countOverlap and $et->Warn("Overlapping $dirName values",1);
1371 120 50       486 if ($entryBased) {
1372 0         0 $et->Warn("$dirName offsets do NOT look entry-based",1);
1373 0         0 undef $entryBased;
1374 0         0 undef $relative;
1375             }
1376             # use PrintIM tag to do special check for correct absolute offsets
1377 120 100       495 if ($tagPtr{0xe00}) {
1378 26         83 my $ptr = $tagPtr{0xe00} - $dataPos;
1379 26 50 33     581 return 0 if $ptr > 0 and $ptr <= length($$dataPt) - 8 and
      33        
1380             substr($$dataPt, $ptr, 8) eq "PrintIM\0";
1381             }
1382             # allow a range of reasonable differences for Unknown maker notes
1383 94 50 66     514 if ($$dirInfo{FixBase} and $$dirInfo{FixBase} == 2) {
1384 0 0 0     0 return 0 if $diff >=0 and $diff <= 24;
1385             }
1386             # ******** (used for testing to extract differences) ********
1387             # $et->FoundTag('Diff', $diff);
1388             # $et->FoundTag('MakeDiff',$makeDiff);
1389             }
1390             #
1391             # handle entry-based offsets
1392             #
1393 97 100       395 if ($entryBased) {
1394 3 50       11 $debug and print "--> entry-based!\n";
1395             # most of my entry-based samples have first value immediately
1396             # after last IFD entry (ie. no padding or next IFD pointer)
1397 3         6 $makeDiff = 0;
1398 3         6 push @offsets, 4; # but some do have a next IFD pointer
1399             # corrected entry-based offsets are relative to start of first entry
1400 3         13 my $expected = 12 * Get16u($$dirInfo{DataPt}, $dirStart);
1401 3         7 $diff = $$valBlkAdj{MIN} - $expected;
1402             # set up directory to read values with entry-based offsets
1403             # (ignore everything and set base to start of first entry)
1404 3         15 $shift = $dataPos + $dirStart + 2;
1405 3         8 $$dirInfo{Base} += $shift;
1406 3         7 $$dirInfo{DataPos} -= $shift;
1407 3         8 $$dirInfo{EntryBased} = 1;
1408 3         10 $$dirInfo{Relative} = 1; # entry-based offsets are relative
1409 3         6 delete $$dirInfo{FixBase}; # no automatic base fix
1410 3 50       10 undef $fixBase unless $setBase;
1411             }
1412             #
1413             # return without doing shift if offsets look OK
1414             #
1415 97 50       371 unless ($setBase) {
1416             # don't try to fix offsets for whacky cameras
1417 97 50       377 return $shift unless defined $makeDiff;
1418             # normal value data starts 4 bytes after IFD, but allow 0 or 4...
1419 97 100 100     1824 return $shift if $diff == 0 or $diff == 4;
1420             # also check for allowed make-specific differences
1421 3         9 foreach (@offsets) {
1422 3 100       25 return $shift if $diff == $_;
1423             }
1424             }
1425             #
1426             # apply the fix, or issue a warning
1427             #
1428             # use default padding of 4 bytes unless already specified
1429 2 50       6 $makeDiff = 4 unless defined $makeDiff;
1430 2         4 $fix = $makeDiff - $diff; # assume standard diff for this make
1431              
1432 2 50       6 if ($$dirInfo{FixBase}) {
    0          
1433             # set flag if offsets are relative (base is at or above directory start)
1434 2 50       8 if ($dataPos - $fix + $dirStart <= 0) {
1435 0 0       0 $$dirInfo{Relative} = (defined $relative) ? $relative : 1;
1436             }
1437 2 50       6 if ($setBase) {
1438 0         0 $fixedBy = $fixBase;
1439 0         0 $fix += $fixBase;
1440             }
1441             } elsif (defined $fixBase) {
1442 0 0       0 $fix = $fixBase if $fixBase ne '';
1443 0         0 $fixedBy = $fix;
1444             } else {
1445             # print warning unless difference looks reasonable
1446 0 0 0     0 if ($diff < 0 or $diff > 16 or ($diff & 0x01)) {
      0        
1447 0         0 $et->Warn("Possibly incorrect maker notes offsets (fix by $fix?)",1);
1448             }
1449             # don't do the fix (but we already adjusted base if entry-based)
1450 0         0 return $shift;
1451             }
1452 2 50       6 if (defined $fixedBy) {
1453 0         0 $et->Warn("Adjusted $dirName base by $fixedBy",1);
1454 0         0 $$dirInfo{FixedBy} = $fixedBy;
1455             }
1456 2         5 $$dirInfo{Base} += $fix;
1457 2         4 $$dirInfo{DataPos} -= $fix;
1458 2         20 return $fix + $shift;
1459             }
1460              
1461             #------------------------------------------------------------------------------
1462             # Find start of IFD in unknown maker notes
1463             # Inputs: 0) reference to directory information
1464             # Returns: offset to IFD on success, undefined otherwise
1465             # - dirInfo may contain TagInfo reference for tag associated with directory
1466             # - on success, updates DirStart, DirLen, Base and DataPos in dirInfo
1467             # - also sets Relative flag in dirInfo if offsets are relative to IFD
1468             # Note: Changes byte ordering!
1469             sub LocateIFD($$)
1470             {
1471 66     66 0 290 my ($et, $dirInfo) = @_;
1472 66         525 my $dataPt = $$dirInfo{DataPt};
1473 66   100     308 my $dirStart = $$dirInfo{DirStart} || 0;
1474             # (ignore MakerNotes DirLen since sometimes this is incorrect)
1475 66         219 my $size = $$dirInfo{DataLen} - $dirStart;
1476 66 50       327 my $dirLen = defined $$dirInfo{DirLen} ? $$dirInfo{DirLen} : $size;
1477 66         188 my $tagInfo = $$dirInfo{TagInfo};
1478 66         226 my $ifdOffsetPos;
1479             # the IFD should be within the first 32 bytes
1480             # (Kyocera sets the current record at 22 bytes)
1481 66         226 my ($firstTry, $lastTry) = (0, 32);
1482              
1483             # make sure Base and DataPos are defined
1484 66 100       256 $$dirInfo{Base} or $$dirInfo{Base} = 0;
1485 66 100       365 $$dirInfo{DataPos} or $$dirInfo{DataPos} = 0;
1486             #
1487             # use tag information (if provided) to determine directory location
1488             #
1489 66 50 33     529 if ($tagInfo and $$tagInfo{SubDirectory}) {
1490 66         201 my $subdir = $$tagInfo{SubDirectory};
1491 66 100 100     1088 unless ($$subdir{ProcessProc} and
      100        
1492             ($$subdir{ProcessProc} eq \&ProcessUnknown or
1493             $$subdir{ProcessProc} eq \&ProcessUnknownOrPreview))
1494             {
1495             # look for the IFD at the "Start" specified in our SubDirectory information
1496 56         197 my $valuePtr = $dirStart;
1497 56         185 my $newStart = $dirStart;
1498 56 100       230 if (defined $$subdir{Start}) {
1499             #### eval Start ($valuePtr)
1500 18         1123 $newStart = eval($$subdir{Start});
1501             }
1502 56 100       312 if ($$subdir{Base}) {
1503             # calculate subdirectory start relative to $base for eval
1504 9         43 my $start = $newStart + $$dirInfo{DataPos};
1505 9   100     46 my $base = $$dirInfo{Base} || 0;
1506             #### eval Base ($start,$base)
1507 9         594 my $baseShift = eval($$subdir{Base});
1508             # shift directory base (note: we may do this again below
1509             # if an OffsetPt is defined, but that doesn't matter since
1510             # the base shift is relative to DataPos, which we set too)
1511 9         51 $$dirInfo{Base} += $baseShift;
1512 9         33 $$dirInfo{DataPos} -= $baseShift;
1513             # this is a relative directory if Base depends on $start
1514 9 50       73 if ($$subdir{Base} =~ /\$start\b/) {
1515 9         36 $$dirInfo{Relative} = 1;
1516             # hack to fix Leica quirk
1517 9 50 33     66 if ($$subdir{ProcessProc} and $$subdir{ProcessProc} eq \&FixLeicaBase) {
1518 0         0 my $oldStart = $$dirInfo{DirStart};
1519 0         0 $$dirInfo{DirStart} = $newStart;
1520 0         0 FixLeicaBase($et, $dirInfo);
1521 0         0 $$dirInfo{DirStart} = $oldStart;
1522             }
1523             }
1524             }
1525             # add offset to the start of the directory if necessary
1526 56 100       265 if ($$subdir{OffsetPt}) {
1527 6 50       37 if ($$subdir{ByteOrder} =~ /^Little/i) {
    0          
1528 6         25 SetByteOrder('II');
1529             } elsif ($$subdir{ByteOrder} =~ /^Big/i) {
1530 0         0 SetByteOrder('MM');
1531             } else {
1532 0         0 warn "Can't have variable byte ordering for SubDirectories using OffsetPt\n";
1533 0         0 return undef;
1534             }
1535             #### eval OffsetPt ($valuePtr)
1536 6         361 $ifdOffsetPos = eval($$subdir{OffsetPt}) - $dirStart;
1537             }
1538             # pinpoint position to look for this IFD
1539 56         223 $firstTry = $lastTry = $newStart - $dirStart;
1540             }
1541             }
1542             #
1543             # scan for something that looks like an IFD
1544             #
1545 66 50       417 if ($dirLen >= 14 + $firstTry) { # minimum size for an IFD
1546 66         129 my $offset;
1547 66         352 IFD_TRY: for ($offset=$firstTry; $offset<=$lastTry; $offset+=2) {
1548 133 50       402 last if $offset + 14 > $dirLen; # 14 bytes is minimum size for an IFD
1549 133         303 my $pos = $dirStart + $offset;
1550             #
1551             # look for a standard TIFF header (Nikon uses it, others may as well),
1552             #
1553 133 50 66     661 if (SetByteOrder(substr($$dataPt, $pos, 2)) and
1554             Get16u($dataPt, $pos + 2) == 0x2a)
1555             {
1556 0         0 $ifdOffsetPos = 4;
1557             }
1558 133 100       497 if (defined $ifdOffsetPos) {
1559             # get pointer to IFD
1560 6         28 my $ptr = Get32u($dataPt, $pos + $ifdOffsetPos);
1561 6 50 33     91 if ($ptr >= $ifdOffsetPos + 4 and $ptr + $offset + 14 <= $dirLen) {
1562             # shift directory start and shorten dirLen accordingly
1563 6         20 $$dirInfo{DirStart} += $ptr + $offset;
1564 6         20 $$dirInfo{DirLen} -= $ptr + $offset;
1565             # shift pointer base to the start of the TIFF header
1566 6         21 my $shift = $$dirInfo{DataPos} + $dirStart + $offset;
1567 6         16 $$dirInfo{Base} += $shift;
1568 6         14 $$dirInfo{DataPos} -= $shift;
1569 6         16 $$dirInfo{Relative} = 1; # set "relative offsets" flag
1570 6         26 return $ptr + $offset;
1571             }
1572 0         0 undef $ifdOffsetPos;
1573             }
1574             #
1575             # look for a standard IFD (starts with 2-byte entry count)
1576             #
1577 127         380 my $num = Get16u($dataPt, $pos);
1578 127 100       428 next unless $num;
1579             # number of entries in an IFD should be between 1 and 255
1580 119 100       573 if (!($num & 0xff)) {
    100          
1581             # lower byte is zero -- byte order could be wrong
1582 9         62 ToggleByteOrder();
1583 9         35 $num >>= 8;
1584             } elsif ($num & 0xff00) {
1585             # upper byte isn't zero -- not an IFD
1586 48         106 next;
1587             }
1588 71         297 my $bytesFromEnd = $size - ($offset + 2 + 12 * $num);
1589 71 50       260 if ($bytesFromEnd < 4) {
1590 0 0 0     0 next unless $bytesFromEnd == 2 or $bytesFromEnd == 0;
1591             }
1592             # do a quick validation of all format types
1593 71         165 my $index;
1594 71         338 for ($index=0; $index<$num; ++$index) {
1595 1663         2651 my $entry = $pos + 2 + 12 * $index;
1596 1663         3386 my $format = Get16u($dataPt, $entry+2);
1597 1663         3604 my $count = Get32u($dataPt, $entry+4);
1598 1663 100       3566 unless ($format) {
1599             # patch for buggy Samsung NX200 JPEG MakerNotes entry count
1600 4 0 33     27 if ($num == 23 and $index == 21 and $$et{Make} eq 'SAMSUNG') {
      33        
1601 0         0 Set16u(21, $dataPt, $pos); # really 21 IFD entries!
1602 0         0 $et->Warn('Fixed incorrect Makernote entry count', 1);
1603 0         0 last;
1604             }
1605             # allow everything to be zero if not first entry
1606             # because some manufacturers pad with null entries
1607 4 50 33     16 next unless $count or $index == 0;
1608             # patch for Canon EOS 40D firmware 1.0.4 bug: allow zero format for last entry
1609 4 50 33     22 next if $index==$num-1 and $$et{Model}=~/EOS 40D/;
1610             }
1611             # patch for Sony cameras like the DSC-P10 that have invalid MakerNote entries
1612 1663 50 66     3428 next if $num == 12 and $$et{Make} eq 'SONY' and $index >= 8;
      33        
1613             # patch for Apple ProRaw DNG which uses format 16 in the maker notes
1614 1663 50 33     3160 next if $format == 16 and $$et{Make} eq 'Apple';
1615             # (would like to verify tag ID, but some manufactures don't
1616             # sort entries in order of tag ID so we don't have much of
1617             # a handle to verify this field)
1618             # verify format
1619 1663 100 100     4815 next IFD_TRY if $format < 1 or $format > 13;
1620             # count must be reasonable (can't test for zero count because
1621             # cameras like the 1DmkIII use this value)
1622 1651 50       2991 next IFD_TRY if $count & 0xff000000;
1623             # extra tests to avoid mis-identifying Samsung makernotes (GT-I9000, etc)
1624 1651 50       4088 next unless $num == 1;
1625 0         0 my $valueSize = $count * $Image::ExifTool::Exif::formatSize[$format];
1626 0 0       0 if ($valueSize > 4) {
1627 0 0       0 next IFD_TRY if $valueSize > $size;
1628 0         0 my $valuePtr = Get32u($dataPt, $entry+8);
1629 0 0       0 next IFD_TRY if $valuePtr > 0x10000;
1630             }
1631             }
1632 59         268 $$dirInfo{DirStart} += $offset; # update directory start
1633 59         171 $$dirInfo{DirLen} -= $offset;
1634 59         338 return $offset; # success!!
1635             }
1636             }
1637 1         4 return undef;
1638             }
1639              
1640             #------------------------------------------------------------------------------
1641             # Fix base offset for Leica maker notes
1642             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
1643             # Returns: 1 on success, and updates $dirInfo if necessary for new directory
1644             sub FixLeicaBase($$;$)
1645             {
1646 0     0 0 0 my ($et, $dirInfo, $tagTablePtr) = @_;
1647 0         0 my $dataPt = $$dirInfo{DataPt};
1648 0   0     0 my $dirStart = $$dirInfo{DirStart} || 0;
1649             # get hash of value block positions
1650 0         0 my ($valBlock, $valBlkAdj) = GetValueBlocks($dataPt, $dirStart);
1651 0 0       0 if (%$valBlock) {
1652             # get sorted list of value offsets
1653 0         0 my @valPtrs = sort { $a <=> $b } keys %$valBlock;
  0         0  
1654 0         0 my $numEntries = Get16u($dataPt, $dirStart);
1655 0         0 my $diff = $valPtrs[0] - ($numEntries * 12 + 4);
1656 0 0       0 if ($diff > 8) {
1657 0         0 $$dirInfo{Base} -= 8;
1658 0         0 $$dirInfo{DataPos} += 8;
1659             }
1660             }
1661 0         0 my $success = 1;
1662 0 0       0 if ($tagTablePtr) {
1663 0         0 $success = Image::ExifTool::Exif::ProcessExif($et, $dirInfo, $tagTablePtr);
1664             }
1665 0         0 return $success;
1666             }
1667              
1668             #------------------------------------------------------------------------------
1669             # Process Canon maker notes
1670             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
1671             # Returns: 1 on success
1672             sub ProcessCanon($$$)
1673             {
1674 47     47 0 271 my ($et, $dirInfo, $tagTablePtr) = @_;
1675             # identify Canon MakerNote footer in HtmlDump
1676             # (this code moved from FixBase so it also works for Adobe MakN in DNG images)
1677 47 50 33     444 if ($$et{HTML_DUMP} and $$dirInfo{DirLen} > 8) {
1678 0         0 my $dataPos = $$dirInfo{DataPos};
1679 0   0     0 my $dirStart = $$dirInfo{DirStart} || 0;
1680 0         0 my $footerPos = $dirStart + $$dirInfo{DirLen} - 8;
1681 0         0 my $footer = substr(${$$dirInfo{DataPt}}, $footerPos, 8);
  0         0  
1682 0 0 0     0 if ($footer =~ /^(II\x2a\0|MM\0\x2a)/ and substr($footer,0,2) eq GetByteOrder()) {
1683 0         0 my $oldOffset = Get32u(\$footer, 4);
1684 0         0 my $newOffset = $dirStart + $dataPos;
1685 0         0 my $str = sprintf('Original maker note offset: 0x%.4x', $oldOffset);
1686 0 0       0 if ($oldOffset != $newOffset) {
1687 0         0 $str .= sprintf("\nCurrent maker note offset: 0x%.4x", $newOffset);
1688             }
1689 0   0     0 my $filePos = ($$dirInfo{Base} || 0) + $dataPos + $footerPos;
1690 0         0 $et->HDump($filePos, 8, '[Canon MakerNotes footer]', $str);
1691             }
1692             }
1693             # process as normal
1694 47         546 return Image::ExifTool::Exif::ProcessExif($et, $dirInfo, $tagTablePtr);
1695             }
1696              
1697             #------------------------------------------------------------------------------
1698             # Process GE type 2 maker notes
1699             # Inputs: 0) ExifTool object ref, 1) DirInfo ref, 2) tag table ref
1700             # Returns: 1 on success
1701             sub ProcessGE2($$$)
1702             {
1703 0     0 0 0 my ($et, $dirInfo, $tagTablePtr) = @_;
1704 0 0       0 my $dataPt = $$dirInfo{DataPt} or return 0;
1705 0   0     0 my $dirStart = $$dirInfo{DirStart} || 0;
1706              
1707             # these maker notes are missing the IFD entry count, but they
1708             # always have 25 entries, so write the entry count manually
1709 0         0 Set16u(25, $dataPt, $dirStart);
1710 0         0 return Image::ExifTool::Exif::ProcessExif($et, $dirInfo, $tagTablePtr);
1711             }
1712              
1713             #------------------------------------------------------------------------------
1714             # Process broken Kodak type 8b maker notes
1715             # Inputs: 0) ExifTool object ref, 1) DirInfo ref, 2) tag table ref
1716             # Returns: 1 on success
1717             sub ProcessKodakPatch($$$)
1718             {
1719 0     0 0 0 my ($et, $dirInfo, $tagTablePtr) = @_;
1720 0 0       0 my $dataPt = $$dirInfo{DataPt} or return 0;
1721 0   0     0 my $dirStart = $$dirInfo{DirStart} || 0;
1722              
1723             # these maker notes have an 2 extra null bytes either before or after the entry count,
1724             # so fix this by making a 2-byte entry count just before the first IFD entry
1725 0 0       0 return 0 unless $$dirInfo{DirLen} >= 4;
1726 0         0 my $t1 = Get16u($dataPt,$dirStart);
1727 0         0 my $t2 = Get16u($dataPt,$dirStart+2);
1728 0   0     0 Set16u($t1 || $t2, $dataPt, $dirStart+2);
1729 0         0 $$dirInfo{DirStart} += 2;
1730 0         0 return Image::ExifTool::Exif::ProcessExif($et, $dirInfo, $tagTablePtr);
1731             }
1732              
1733             #------------------------------------------------------------------------------
1734             # Process unknown maker notes or PreviewImage
1735             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
1736             # Returns: 1 on success, and updates $dirInfo if necessary for new directory
1737             sub ProcessUnknownOrPreview($$$)
1738             {
1739 3     3 0 17 my ($et, $dirInfo, $tagTablePtr) = @_;
1740 3         9 my $dataPt = $$dirInfo{DataPt};
1741 3         7 my $dirStart = $$dirInfo{DirStart};
1742 3         7 my $dirLen = $$dirInfo{DirLen};
1743             # check to see if this is a preview image
1744 3 50 33     21 if ($dirLen > 6 and substr($$dataPt, $dirStart, 3) eq "\xff\xd8\xff") {
1745 0         0 $et->VerboseDir('PreviewImage');
1746 0 0       0 if ($$et{HTML_DUMP}) {
1747 0         0 my $pos = $$dirInfo{DataPos} + $$dirInfo{Base} + $dirStart;
1748 0         0 $et->HDump($pos, $dirLen, '(MakerNotes:PreviewImage data)', "Size: $dirLen bytes")
1749             }
1750 0         0 $et->FoundTag('PreviewImage', substr($$dataPt, $dirStart, $dirLen));
1751 0         0 return 1;
1752             }
1753 3         16 return ProcessUnknown($et, $dirInfo, $tagTablePtr);
1754             }
1755              
1756             #------------------------------------------------------------------------------
1757             # Write unknown maker notes or PreviewImage
1758             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
1759             # Returns: directory data, '' to delete, or undef on error
1760             sub WriteUnknownOrPreview($$$)
1761             {
1762 1     1 0 13 my ($et, $dirInfo, $tagTablePtr) = @_;
1763 1         3 my $dataPt = $$dirInfo{DataPt};
1764 1         3 my $dirStart = $$dirInfo{DirStart};
1765 1         3 my $dirLen = $$dirInfo{DirLen};
1766 1         2 my $newVal;
1767             # check to see if this is a preview image
1768 1 50 33     9 if ($dirLen > 6 and substr($$dataPt, $dirStart, 3) eq "\xff\xd8\xff") {
1769 0 0       0 if ($$et{NEW_VALUE}{$Image::ExifTool::Extra{PreviewImage}}) {
1770             # write or delete new preview (if deleted, it can't currently be added back again)
1771 0   0     0 $newVal = $et->GetNewValue('PreviewImage') || '';
1772 0 0       0 if ($et->Options('Verbose') > 1) {
1773 0         0 $et->VerboseValue("- MakerNotes:PreviewImage", substr($$dataPt, $dirStart, $dirLen));
1774 0 0       0 $et->VerboseValue("+ MakerNotes:PreviewImage", $newVal) if $newVal;
1775             }
1776 0         0 ++$$et{CHANGED};
1777             } else {
1778 0         0 $newVal = substr($$dataPt, $dirStart, $dirLen);
1779             }
1780             } else {
1781             # rewrite MakerNote IFD
1782 1         111 $newVal = Image::ExifTool::Exif::WriteExif($et, $dirInfo, $tagTablePtr);
1783             }
1784 1         5 return $newVal;
1785             }
1786              
1787             #------------------------------------------------------------------------------
1788             # Process unknown maker notes assuming it is in EXIF IFD format
1789             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
1790             # Returns: 1 on success, and updates $dirInfo if necessary for new directory
1791             sub ProcessUnknown($$$)
1792             {
1793 7     7 0 44 my ($et, $dirInfo, $tagTablePtr) = @_;
1794 7         17 my $success = 0;
1795              
1796 7         88 my $loc = LocateIFD($et, $dirInfo);
1797 7 100       41 if (defined $loc) {
1798 6         27 $$et{UnknownByteOrder} = GetByteOrder();
1799 6 50       29 if ($et->Options('Verbose') > 1) {
1800 0         0 my $out = $et->Options('TextOut');
1801 0         0 my $indent = $$et{INDENT};
1802 0         0 $indent =~ s/\| $/ /;
1803             printf $out "${indent}Found IFD at offset 0x%.4x in maker notes:\n",
1804 0         0 $$dirInfo{DirStart} + $$dirInfo{DataPos} + $$dirInfo{Base};
1805             }
1806 6         181 $success = Image::ExifTool::Exif::ProcessExif($et, $dirInfo, $tagTablePtr);
1807             } else {
1808 1         4 $$et{UnknownByteOrder} = ''; # indicates we tried but didn't set byte order
1809 1         6 $et->Warn("Unrecognized $$dirInfo{DirName}", 1);
1810             }
1811 7         27 return $success;
1812             }
1813              
1814              
1815             1; # end
1816              
1817             __END__