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