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