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