source: main/trunk/greenstone2/perllib/cpan/Image/ExifTool/MIE.pm@ 34921

Last change on this file since 34921 was 34921, checked in by anupama, 3 years ago

Committing the improvements to EmbeddedMetaPlugin's processing of Keywords vs other metadata fields. Keywords were literally stored as arrays of words rather than phrases in PDFs (at least in Diego's sample PDF), whereas other meta fields like Subjects and Creators stored them as arrays of phrases. To get both to work, Kathy updated EXIF to a newer version, to retrieve the actual EXIF values stored in the PDF. And Kathy and Dr Bainbridge came up with a new option that I added called apply_join_before_split_to_metafields that's a regex which can list the metadata fields to apply the join_before_split to and whcih previously always got applied to all metadata fields. Now it's applied to any *Keywords metafields by default, as that's the metafield we have experience of that behaves differently to the others, as it stores by word instead of phrases. Tested on Diego's sample PDF. Diego has double-checked it to works on his sample PDF too, setting the split char to ; and turning on the join_before_split and leaving apply_join_before_split_to_metafields at its default of .*Keywords. File changes are strings.properties for the tooltip, the plugin introducing the option and working with it and Kathy's EXIF updates affecting cpan/File and cpan/Image.

File size: 102.0 KB
Line 
1#------------------------------------------------------------------------------
2# File: MIE.pm
3#
4# Description: Read/write MIE meta information
5#
6# Revisions: 11/18/2005 - P. Harvey Created
7#------------------------------------------------------------------------------
8
9package Image::ExifTool::MIE;
10
11use strict;
12use vars qw($VERSION %tableDefaults);
13use Image::ExifTool qw(:DataAccess :Utils);
14use Image::ExifTool::Exif;
15use Image::ExifTool::GPS;
16
17$VERSION = '1.48';
18
19sub ProcessMIE($$);
20sub ProcessMIEGroup($$$);
21sub WriteMIEGroup($$$);
22sub CheckMIE($$$);
23sub GetLangInfo($$);
24
25# local variables
26my $hasZlib; # 1=Zlib available, 0=no Zlib
27my %mieCode; # reverse lookup for MIE format names
28my $doneMieMap; # flag indicating we added user-defined groups to %mieMap
29
30# MIE format codes
31my %mieFormat = (
32 0x00 => 'undef',
33 0x10 => 'MIE',
34 0x18 => 'MIE',
35 0x20 => 'string', # ASCII (ISO 8859-1)
36 0x28 => 'utf8',
37 0x29 => 'utf16',
38 0x2a => 'utf32',
39 0x30 => 'string_list',
40 0x38 => 'utf8_list',
41 0x39 => 'utf16_list',
42 0x3a => 'utf32_list',
43 0x40 => 'int8u',
44 0x41 => 'int16u',
45 0x42 => 'int32u',
46 0x43 => 'int64u',
47 0x48 => 'int8s',
48 0x49 => 'int16s',
49 0x4a => 'int32s',
50 0x4b => 'int64s',
51 0x52 => 'rational32u',
52 0x53 => 'rational64u',
53 0x5a => 'rational32s',
54 0x5b => 'rational64s',
55 0x61 => 'fixed16u',
56 0x62 => 'fixed32u',
57 0x69 => 'fixed16s',
58 0x6a => 'fixed32s',
59 0x72 => 'float',
60 0x73 => 'double',
61 0x80 => 'free',
62);
63
64# map of MIE directory locations
65my %mieMap = (
66 'MIE-Meta' => 'MIE',
67 'MIE-Audio' => 'MIE-Meta',
68 'MIE-Camera' => 'MIE-Meta',
69 'MIE-Doc' => 'MIE-Meta',
70 'MIE-Geo' => 'MIE-Meta',
71 'MIE-Image' => 'MIE-Meta',
72 'MIE-MakerNotes' => 'MIE-Meta',
73 'MIE-Preview' => 'MIE-Meta',
74 'MIE-Thumbnail' => 'MIE-Meta',
75 'MIE-Video' => 'MIE-Meta',
76 'MIE-Flash' => 'MIE-Camera',
77 'MIE-Lens' => 'MIE-Camera',
78 'MIE-Orient' => 'MIE-Camera',
79 'MIE-Extender' => 'MIE-Lens',
80 'MIE-GPS' => 'MIE-Geo',
81 'MIE-UTM' => 'MIE-Geo',
82 'MIE-Canon' => 'MIE-MakerNotes',
83 EXIF => 'MIE-Meta',
84 XMP => 'MIE-Meta',
85 IPTC => 'MIE-Meta',
86 ICC_Profile => 'MIE-Meta',
87 ID3 => 'MIE-Meta',
88 CanonVRD => 'MIE-Canon',
89 IFD0 => 'EXIF',
90 IFD1 => 'IFD0',
91 ExifIFD => 'IFD0',
92 GPS => 'IFD0',
93 SubIFD => 'IFD0',
94 GlobParamIFD => 'IFD0',
95 PrintIM => 'IFD0',
96 InteropIFD => 'ExifIFD',
97 MakerNotes => 'ExifIFD',
98);
99
100# convenience variables for common tagInfo entries
101my %binaryConv = (
102 Writable => 'undef',
103 Binary => 1,
104);
105my %dateInfo = (
106 Shift => 'Time',
107 PrintConv => '$self->ConvertDateTime($val)',
108 PrintConvInv => '$self->InverseDateTime($val)',
109);
110my %noYes = ( 0 => 'No', 1 => 'Yes' );
111my %offOn = ( 0 => 'Off', 1 => 'On' );
112
113# default entries for MIE tag tables
114%tableDefaults = (
115 PROCESS_PROC => \&ProcessMIE,
116 WRITE_PROC => \&ProcessMIE,
117 CHECK_PROC => \&CheckMIE,
118 LANG_INFO => \&GetLangInfo,
119 WRITABLE => 'string',
120 PREFERRED => 1,
121);
122
123# MIE info
124%Image::ExifTool::MIE::Main = (
125 %tableDefaults,
126 GROUPS => { 1 => 'MIE-Main' },
127 WRITE_GROUP => 'MIE-Main',
128 NOTES => q{
129 MIE is a flexible format which may be used as a stand-alone meta information
130 format, for encapsulation of other files and information, or as a trailer
131 appended to other file formats. The tables below represent currently
132 defined MIE tags, however ExifTool will also extract any other information
133 present in a MIE file.
134
135 When writing MIE information, some special features are supported:
136
137 1) String values may be written as ASCII (ISO 8859-1) or UTF-8. ExifTool
138 automatically detects the presence of wide characters and treats the string
139 appropriately. Internally, UTF-8 text may be converted to UTF-16 or UTF-32
140 and stored in this format in the file if it is more compact.
141
142 2) All MIE string-value tags support localized text. Localized values are
143 written by adding a language/country code to the tag name in the form
144 C<TAG-xx_YY>, where C<TAG> is the tag name, C<xx> is a 2-character lower
145 case ISO 639-1 language code, and C<YY> is a 2-character upper case ISO
146 3166-1 alpha 2 country code (eg. C<Title-en_US>). But as usual, the user
147 interface is case-insensitive, and ExifTool will write the correct case to
148 the file.
149
150 3) Some numerical MIE tags allow units of measurement to be specified. For
151 these tags, units may be added in brackets immediately following the value
152 (eg. C<55(mi/h)>). If no units are specified, the default units are
153 written.
154
155 4) ExifTool writes compressed metadata to MIE files if the L<Compress|../ExifTool.html#Compress> (-z)
156 option is used and Compress::Zlib is available.
157
158 See L<https://exiftool.org/MIE1.1-20070121.pdf> for the official MIE
159 specification.
160 },
161 '0Type' => {
162 Name => 'SubfileType',
163 Notes => q{
164 the capitalized common extension for this type of file. If the extension
165 has a dot-3 abbreviation, then the longer version is used here. For
166 instance, JPEG and TIFF are used, not JPG and TIF
167 },
168 },
169 '0Vers' => {
170 Name => 'MIEVersion',
171 Notes => 'version 1.1 is assumed if not specified',
172 },
173 '1Directory' => {
174 Name => 'SubfileDirectory',
175 Notes => 'original directory for the file',
176 },
177 '1Name' => {
178 Name => 'SubfileName',
179 Notes => 'the file name, including extension if it exists',
180 },
181 '2MIME' => { Name => 'SubfileMIMEType' },
182 Meta => {
183 SubDirectory => {
184 TagTable => 'Image::ExifTool::MIE::Meta',
185 DirName => 'MIE-Meta',
186 },
187 },
188 data => {
189 Name => 'SubfileData',
190 Notes => 'the subfile data',
191 %binaryConv,
192 },
193 rsrc => {
194 Name => 'SubfileResource',
195 Notes => 'subfile resource fork if it exists',
196 %binaryConv,
197 },
198 zmd5 => {
199 Name => 'MD5Digest',
200 Notes => q{
201 16-byte MD5 digest written in binary form or as a 32-character hex-encoded
202 ASCII string. Value is an MD5 digest of the entire 0MIE group as it would be
203 with the digest value itself set to all null bytes
204 },
205 },
206 zmie => {
207 Name => 'TrailerSignature',
208 Writable => 'undef',
209 Notes => q{
210 used as the last element in the main "0MIE" group to identify a MIE trailer
211 when appended to another type of file. ExifTool will create this tag if set
212 to any value, but always with an empty data block
213 },
214 ValueConvInv => '""', # data block must be empty
215 },
216);
217
218# MIE meta information group
219%Image::ExifTool::MIE::Meta = (
220 %tableDefaults,
221 GROUPS => { 1 => 'MIE-Meta', 2 => 'Image' },
222 WRITE_GROUP => 'MIE-Meta',
223 Audio => {
224 SubDirectory => {
225 TagTable => 'Image::ExifTool::MIE::Audio',
226 DirName => 'MIE-Audio',
227 },
228 },
229 Camera => {
230 SubDirectory => {
231 TagTable => 'Image::ExifTool::MIE::Camera',
232 DirName => 'MIE-Camera',
233 },
234 },
235 Document => {
236 SubDirectory => {
237 TagTable => 'Image::ExifTool::MIE::Doc',
238 DirName => 'MIE-Doc',
239 },
240 },
241 EXIF => {
242 SubDirectory => {
243 TagTable => 'Image::ExifTool::Exif::Main',
244 ProcessProc => \&Image::ExifTool::ProcessTIFF,
245 WriteProc => \&Image::ExifTool::WriteTIFF,
246 },
247 },
248 Geo => {
249 SubDirectory => {
250 TagTable => 'Image::ExifTool::MIE::Geo',
251 DirName => 'MIE-Geo',
252 },
253 },
254 ICCProfile => {
255 Name => 'ICC_Profile',
256 SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::Main' },
257 },
258 ID3 => { SubDirectory => { TagTable => 'Image::ExifTool::ID3::Main' } },
259 IPTC => { SubDirectory => { TagTable => 'Image::ExifTool::IPTC::Main' } },
260 Image => {
261 SubDirectory => {
262 TagTable => 'Image::ExifTool::MIE::Image',
263 DirName => 'MIE-Image',
264 },
265 },
266 MakerNotes => {
267 SubDirectory => {
268 TagTable => 'Image::ExifTool::MIE::MakerNotes',
269 DirName => 'MIE-MakerNotes',
270 },
271 },
272 Preview => {
273 SubDirectory => {
274 TagTable => 'Image::ExifTool::MIE::Preview',
275 DirName => 'MIE-Preview',
276 },
277 },
278 Thumbnail => {
279 SubDirectory => {
280 TagTable => 'Image::ExifTool::MIE::Thumbnail',
281 DirName => 'MIE-Thumbnail',
282 },
283 },
284 Video => {
285 SubDirectory => {
286 TagTable => 'Image::ExifTool::MIE::Video',
287 DirName => 'MIE-Video',
288 },
289 },
290 XMP => { SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' } },
291);
292
293# MIE document information
294%Image::ExifTool::MIE::Doc = (
295 %tableDefaults,
296 GROUPS => { 1 => 'MIE-Doc', 2 => 'Document' },
297 WRITE_GROUP => 'MIE-Doc',
298 NOTES => 'Information describing the main document, image or file.',
299 Author => { Groups => { 2 => 'Author' } },
300 Comment => { },
301 Contributors=> { Groups => { 2 => 'Author' }, List => 1 },
302 Copyright => { Groups => { 2 => 'Author' } },
303 CreateDate => { Groups => { 2 => 'Time' }, %dateInfo },
304 EMail => { Name => 'Email', Groups => { 2 => 'Author' } },
305 Keywords => { List => 1 },
306 ModifyDate => { Groups => { 2 => 'Time' }, %dateInfo },
307 OriginalDate=> {
308 Name => 'DateTimeOriginal',
309 Description => 'Date/Time Original',
310 Groups => { 2 => 'Time' },
311 %dateInfo,
312 },
313 Phone => { Name => 'PhoneNumber', Groups => { 2 => 'Author' } },
314 References => { List => 1 },
315 Software => { },
316 Title => { },
317 URL => { },
318);
319
320# MIE geographic information
321%Image::ExifTool::MIE::Geo = (
322 %tableDefaults,
323 GROUPS => { 1 => 'MIE-Geo', 2 => 'Location' },
324 WRITE_GROUP => 'MIE-Geo',
325 NOTES => 'Information related to geographic location.',
326 Address => { },
327 City => { },
328 Country => { },
329 GPS => {
330 SubDirectory => {
331 TagTable => 'Image::ExifTool::MIE::GPS',
332 DirName => 'MIE-GPS',
333 },
334 },
335 PostalCode => { },
336 State => { Notes => 'state or province' },
337 UTM => {
338 SubDirectory => {
339 TagTable => 'Image::ExifTool::MIE::UTM',
340 DirName => 'MIE-UTM',
341 },
342 },
343);
344
345# MIE GPS information
346%Image::ExifTool::MIE::GPS = (
347 %tableDefaults,
348 GROUPS => { 1 => 'MIE-GPS', 2 => 'Location' },
349 WRITE_GROUP => 'MIE-GPS',
350 Altitude => {
351 Name => 'GPSAltitude',
352 Writable => 'rational64s',
353 Units => [ qw(m ft) ],
354 Notes => q{'m' above sea level unless 'ft' specified},
355 },
356 Bearing => {
357 Name => 'GPSDestBearing',
358 Writable => 'rational64s',
359 Units => [ qw(deg deg{mag}) ],
360 Notes => q{'deg' CW from true north unless 'deg{mag}' specified},
361 },
362 Datum => { Name => 'GPSMapDatum', Notes => 'WGS-84 assumed if not specified' },
363 Differential => {
364 Name => 'GPSDifferential',
365 Writable => 'int8u',
366 PrintConv => {
367 0 => 'No Correction',
368 1 => 'Differential Corrected',
369 },
370 },
371 Distance => {
372 Name => 'GPSDestDistance',
373 Writable => 'rational64s',
374 Units => [ qw(km mi nmi) ],
375 Notes => q{'km' unless 'mi' or 'nmi' specified},
376 },
377 Heading => {
378 Name => 'GPSTrack',
379 Writable => 'rational64s',
380 Units => [ qw(deg deg{mag}) ],
381 Notes => q{'deg' CW from true north unless 'deg{mag}' specified},
382 },
383 Latitude => {
384 Name => 'GPSLatitude',
385 Writable => 'rational64s',
386 Count => -1,
387 Notes => q{
388 1 to 3 numbers: degrees, minutes then seconds. South latitudes are stored
389 as all negative numbers, but may be entered as positive numbers with a
390 trailing 'S' for convenience. For example, these are all equivalent: "-40
391 -30", "-40.5", "40 30 0.00 S"
392 },
393 ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)',
394 ValueConvInv => 'Image::ExifTool::GPS::ToDMS($self, $val, 0)',
395 PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
396 PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1)',
397 },
398 Longitude => {
399 Name => 'GPSLongitude',
400 Writable => 'rational64s',
401 Count => -1,
402 Notes => q{
403 1 to 3 numbers: degrees, minutes then seconds. West longitudes are
404 negative, but may be entered as positive numbers with a trailing 'W'
405 },
406 ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)',
407 ValueConvInv => 'Image::ExifTool::GPS::ToDMS($self, $val, 0)',
408 PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
409 PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1)',
410 },
411 MeasureMode => {
412 Name => 'GPSMeasureMode',
413 Writable => 'int8u',
414 PrintConv => { 2 => '2-D', 3 => '3-D' },
415 },
416 Satellites => 'GPSSatellites',
417 Speed => {
418 Name => 'GPSSpeed',
419 Writable => 'rational64s',
420 Units => [ qw(km/h mi/h m/s kn) ],
421 Notes => q{'km/h' unless 'mi/h', 'm/s' or 'kn' specified},
422 },
423 DateTime => { Name => 'GPSDateTime', Groups => { 2 => 'Time' }, %dateInfo },
424);
425
426# MIE UTM information
427%Image::ExifTool::MIE::UTM = (
428 %tableDefaults,
429 GROUPS => { 1 => 'MIE-UTM', 2 => 'Location' },
430 WRITE_GROUP => 'MIE-UTM',
431 Datum => { Name => 'UTMMapDatum', Notes => 'WGS-84 assumed if not specified' },
432 Easting => { Name => 'UTMEasting' },
433 Northing => { Name => 'UTMNorthing' },
434 Zone => { Name => 'UTMZone', Writable => 'int8s' },
435);
436
437# MIE image information
438%Image::ExifTool::MIE::Image = (
439 %tableDefaults,
440 GROUPS => { 1 => 'MIE-Image', 2 => 'Image' },
441 WRITE_GROUP => 'MIE-Image',
442 '0Type' => { Name => 'FullSizeImageType', Notes => 'JPEG if not specified' },
443 '1Name' => { Name => 'FullSizeImageName' },
444 BitDepth => { Name => 'BitDepth', Writable => 'int16u' },
445 ColorSpace => { Notes => 'standard ColorSpace values are "sRGB" and "Adobe RGB"' },
446 Components => {
447 Name => 'ComponentsConfiguration',
448 Notes => 'string composed of R, G, B, Y, Cb and Cr',
449 },
450 Compression => { Name => 'CompressionRatio', Writable => 'rational32u' },
451 ImageSize => {
452 Writable => 'int16u',
453 Count => -1,
454 Notes => '2 or 3 values, for number of XY or XYZ pixels',
455 PrintConv => '$val=~tr/ /x/;$val',
456 PrintConvInv => '$val=~tr/x/ /;$val',
457 },
458 Resolution => {
459 Writable => 'rational64u',
460 Units => [ qw(/in /cm /deg /arcmin /arcsec), '' ],
461 Count => -1,
462 Notes => q{
463 1 to 3 values. A single value for equal resolution in all directions, or
464 separate X, Y and Z values if necessary. Units are '/in' unless '/cm',
465 '/deg', '/arcmin', '/arcsec' or '' specified
466 },
467 PrintConv => '$val=~tr/ /x/;$val',
468 PrintConvInv => '$val=~tr/x/ /;$val',
469 },
470 data => {
471 Name => 'FullSizeImage',
472 Groups => { 2 => 'Preview' },
473 %binaryConv,
474 RawConv => '$self->ValidateImage(\$val,$tag)',
475 },
476);
477
478# MIE preview image
479%Image::ExifTool::MIE::Preview = (
480 %tableDefaults,
481 GROUPS => { 1 => 'MIE-Preview', 2 => 'Image' },
482 WRITE_GROUP => 'MIE-Preview',
483 '0Type' => { Name => 'PreviewImageType', Notes => 'JPEG if not specified' },
484 '1Name' => { Name => 'PreviewImageName' },
485 ImageSize => {
486 Name => 'PreviewImageSize',
487 Writable => 'int16u',
488 Count => -1,
489 Notes => '2 or 3 values, for number of XY or XYZ pixels',
490 PrintConv => '$val=~tr/ /x/;$val',
491 PrintConvInv => '$val=~tr/x/ /;$val',
492 },
493 data => {
494 Name => 'PreviewImage',
495 Groups => { 2 => 'Preview' },
496 %binaryConv,
497 RawConv => '$self->ValidateImage(\$val,$tag)',
498 },
499);
500
501# MIE thumbnail image
502%Image::ExifTool::MIE::Thumbnail = (
503 %tableDefaults,
504 GROUPS => { 1 => 'MIE-Thumbnail', 2 => 'Image' },
505 WRITE_GROUP => 'MIE-Thumbnail',
506 '0Type' => { Name => 'ThumbnailImageType', Notes => 'JPEG if not specified' },
507 '1Name' => { Name => 'ThumbnailImageName' },
508 ImageSize => {
509 Name => 'ThumbnailImageSize',
510 Writable => 'int16u',
511 Count => -1,
512 Notes => '2 or 3 values, for number of XY or XYZ pixels',
513 PrintConv => '$val=~tr/ /x/;$val',
514 PrintConvInv => '$val=~tr/x/ /;$val',
515 },
516 data => {
517 Name => 'ThumbnailImage',
518 Groups => { 2 => 'Preview' },
519 %binaryConv,
520 RawConv => '$self->ValidateImage(\$val,$tag)',
521 },
522);
523
524# MIE audio information
525%Image::ExifTool::MIE::Audio = (
526 %tableDefaults,
527 GROUPS => { 1 => 'MIE-Audio', 2 => 'Audio' },
528 WRITE_GROUP => 'MIE-Audio',
529 NOTES => q{
530 For the Audio group (and any other group containing a 'data' element), tags
531 refer to the contained data if present, otherwise they refer to the main
532 SubfileData. The C<0Type> and C<1Name> elements should exist only if C<data>
533 is present.
534 },
535 '0Type' => { Name => 'RelatedAudioFileType', Notes => 'MP3 if not specified' },
536 '1Name' => { Name => 'RelatedAudioFileName' },
537 SampleBits => { Writable => 'int16u' },
538 Channels => { Writable => 'int8u' },
539 Compression => { Name => 'AudioCompression' },
540 Duration => { Writable => 'rational64u', PrintConv => 'ConvertDuration($val)' },
541 SampleRate => { Writable => 'int32u' },
542 data => { Name => 'RelatedAudioFile', %binaryConv },
543);
544
545# MIE video information
546%Image::ExifTool::MIE::Video = (
547 %tableDefaults,
548 GROUPS => { 1 => 'MIE-Video', 2 => 'Video' },
549 WRITE_GROUP => 'MIE-Video',
550 '0Type' => { Name => 'RelatedVideoFileType', Notes => 'MOV if not specified' },
551 '1Name' => { Name => 'RelatedVideoFileName' },
552 Codec => { },
553 Duration => { Writable => 'rational64u', PrintConv => 'ConvertDuration($val)' },
554 data => { Name => 'RelatedVideoFile', %binaryConv },
555);
556
557# MIE camera information
558%Image::ExifTool::MIE::Camera = (
559 %tableDefaults,
560 GROUPS => { 1 => 'MIE-Camera', 2 => 'Camera' },
561 WRITE_GROUP => 'MIE-Camera',
562 Brightness => { Writable => 'int8s' },
563 ColorTemperature=> { Writable => 'int32u' },
564 ColorBalance => {
565 Writable => 'rational64u',
566 Count => 3,
567 Notes => 'RGB scaling factors',
568 },
569 Contrast => { Writable => 'int8s' },
570 DigitalZoom => { Writable => 'rational64u' },
571 ExposureComp => { Name => 'ExposureCompensation', Writable => 'rational64s' },
572 ExposureMode => { },
573 ExposureTime => {
574 Writable => 'rational64u',
575 PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
576 PrintConvInv => '$val',
577 },
578 Flash => {
579 SubDirectory => {
580 TagTable => 'Image::ExifTool::MIE::Flash',
581 DirName => 'MIE-Flash',
582 },
583 },
584 FirmwareVersion => { },
585 FocusMode => { },
586 ISO => { Writable => 'int16u' },
587 ISOSetting => {
588 Writable => 'int16u',
589 Notes => '0 = Auto, otherwise manual ISO speed setting',
590 },
591 ImageNumber => { Writable => 'int32u' },
592 ImageQuality => { Notes => 'Economy, Normal, Fine, Super Fine or Raw' },
593 ImageStabilization => { Writable => 'int8u', %offOn },
594 Lens => {
595 SubDirectory => {
596 TagTable => 'Image::ExifTool::MIE::Lens',
597 DirName => 'MIE-Lens',
598 },
599 },
600 Make => { },
601 MeasuredEV => { Writable => 'rational64s' },
602 Model => { },
603 OwnerName => { },
604 Orientation => {
605 SubDirectory => {
606 TagTable => 'Image::ExifTool::MIE::Orient',
607 DirName => 'MIE-Orient',
608 },
609 },
610 Saturation => { Writable => 'int8s' },
611 SensorSize => {
612 Writable => 'rational64u',
613 Count => 2,
614 Notes => 'width and height of active sensor area in mm',
615 },
616 SerialNumber => { },
617 Sharpness => { Writable => 'int8s' },
618 ShootingMode => { },
619);
620
621# Camera orientation information
622%Image::ExifTool::MIE::Orient = (
623 %tableDefaults,
624 GROUPS => { 1 => 'MIE-Orient', 2 => 'Camera' },
625 WRITE_GROUP => 'MIE-Orient',
626 NOTES => 'These tags describe the camera orientation.',
627 Azimuth => {
628 Writable => 'rational64s',
629 Units => [ qw(deg deg{mag}) ],
630 Notes => q{'deg' CW from true north unless 'deg{mag}' specified},
631 },
632 Declination => { Writable => 'rational64s' },
633 Elevation => { Writable => 'rational64s' },
634 RightAscension => { Writable => 'rational64s' },
635 Rotation => {
636 Writable => 'rational64s',
637 Notes => 'CW rotation angle of camera about lens axis',
638 },
639);
640
641# MIE camera lens information
642%Image::ExifTool::MIE::Lens = (
643 %tableDefaults,
644 GROUPS => { 1 => 'MIE-Lens', 2 => 'Camera' },
645 WRITE_GROUP => 'MIE-Lens',
646 NOTES => q{
647 All recorded lens parameters (focal length, aperture, etc) include the
648 effects of the extender if present.
649 },
650 Extender => {
651 SubDirectory => {
652 TagTable => 'Image::ExifTool::MIE::Extender',
653 DirName => 'MIE-Extender',
654 },
655 },
656 FNumber => { Writable => 'rational64u' },
657 FocalLength => { Writable => 'rational64u', Notes => 'all focal lengths in mm' },
658 FocusDistance => {
659 Writable => 'rational64u',
660 Units => [ qw(m ft) ],
661 Notes => q{'m' unless 'ft' specified},
662 },
663 Make => { Name => 'LensMake' },
664 MaxAperture => { Writable => 'rational64u' },
665 MaxApertureAtMaxFocal => { Writable => 'rational64u' },
666 MaxFocalLength => { Writable => 'rational64u' },
667 MinAperture => { Writable => 'rational64u' },
668 MinFocalLength => { Writable => 'rational64u' },
669 Model => { Name => 'LensModel' },
670 OpticalZoom => { Writable => 'rational64u' },
671 SerialNumber => { Name => 'LensSerialNumber' },
672);
673
674# MIE lens extender information
675%Image::ExifTool::MIE::Extender = (
676 %tableDefaults,
677 GROUPS => { 1 => 'MIE-Extender', 2 => 'Camera' },
678 WRITE_GROUP => 'MIE-Extender',
679 Magnification => { Name => 'ExtenderMagnification', Writable => 'rational64s' },
680 Make => { Name => 'ExtenderMake' },
681 Model => { Name => 'ExtenderModel' },
682 SerialNumber => { Name => 'ExtenderSerialNumber' },
683);
684
685# MIE camera flash information
686%Image::ExifTool::MIE::Flash = (
687 %tableDefaults,
688 GROUPS => { 1 => 'MIE-Flash', 2 => 'Camera' },
689 WRITE_GROUP => 'MIE-Flash',
690 ExposureComp => { Name => 'FlashExposureComp', Writable => 'rational64s' },
691 Fired => { Name => 'FlashFired', Writable => 'int8u', PrintConv => \%noYes },
692 GuideNumber => { Name => 'FlashGuideNumber' },
693 Make => { Name => 'FlashMake' },
694 Mode => { Name => 'FlashMode' },
695 Model => { Name => 'FlashModel' },
696 SerialNumber => { Name => 'FlashSerialNumber' },
697 Type => { Name => 'FlashType', Notes => '"Internal" or "External"' },
698);
699
700# MIE maker notes information
701%Image::ExifTool::MIE::MakerNotes = (
702 %tableDefaults,
703 GROUPS => { 1 => 'MIE-MakerNotes' },
704 WRITE_GROUP => 'MIE-MakerNotes',
705 NOTES => q{
706 MIE maker notes are contained within separate groups for each manufacturer
707 to avoid name conflicts.
708 },
709 Canon => {
710 SubDirectory => {
711 TagTable => 'Image::ExifTool::MIE::Canon',
712 DirName => 'MIE-Canon',
713 },
714 },
715 Casio => { SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
716 FujiFilm => { SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
717 Kodak => { SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
718 KonicaMinolta=>{ SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
719 Nikon => { SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
720 Olympus => { SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
721 Panasonic => { SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
722 Pentax => { SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
723 Ricoh => { SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
724 Sigma => { SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
725 Sony => { SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
726);
727
728# MIE Canon-specific information
729%Image::ExifTool::MIE::Canon = (
730 %tableDefaults,
731 GROUPS => { 1 => 'MIE-Canon' },
732 WRITE_GROUP => 'MIE-Canon',
733 VRD => {
734 Name => 'CanonVRD',
735 SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::Main' },
736 },
737);
738
739%Image::ExifTool::MIE::Unknown = (
740 PROCESS_PROC => \&ProcessMIE,
741 GROUPS => { 1 => 'MIE-Unknown' },
742);
743
744#------------------------------------------------------------------------------
745# Add user-defined MIE groups to %mieMap
746# Inputs: none; Returns: nothing, but sets $doneMieMap flag
747sub UpdateMieMap()
748{
749 $doneMieMap = 1; # set flag so we only do this once
750 return unless %Image::ExifTool::UserDefined;
751 my ($tableName, @tables, %doneTable, $tagID);
752 # get list of top-level MIE tables with user-defined tags
753 foreach $tableName (keys %Image::ExifTool::UserDefined) {
754 next unless $tableName =~ /^Image::ExifTool::MIE::/;
755 my $userTable = $Image::ExifTool::UserDefined{$tableName};
756 my $tagTablePtr = GetTagTable($tableName) or next;
757 # copy the WRITE_GROUP from the actual table
758 $$userTable{WRITE_GROUP} = $$tagTablePtr{WRITE_GROUP};
759 # add to list of tables to process
760 $doneTable{$tableName} = 1;
761 push @tables, [$tableName, $userTable];
762 }
763 # recursively add all user-defined groups to MIE map
764 while (@tables) {
765 my ($tableName, $tagTablePtr) = @{shift @tables};
766 my $parent = $$tagTablePtr{WRITE_GROUP};
767 $parent or warn("No WRITE_GROUP for $tableName\n"), next;
768 $mieMap{$parent} or warn("$parent is not in MIE map\n"), next;
769 foreach $tagID (TagTableKeys($tagTablePtr)) {
770 my $tagInfo = $$tagTablePtr{$tagID};
771 next unless ref $tagInfo eq 'HASH' and $$tagInfo{SubDirectory};
772 my $subTableName = $tagInfo->{SubDirectory}->{TagTable};
773 my $subTablePtr = GetTagTable($subTableName) or next;
774 # only care about MIE tables
775 next unless $$subTablePtr{PROCESS_PROC} and
776 $$subTablePtr{PROCESS_PROC} eq \&ProcessMIE;
777 my $group = $$subTablePtr{WRITE_GROUP};
778 $group or warn("No WRITE_GROUP for $subTableName\n"), next;
779 if ($mieMap{$group} and $mieMap{$group} ne $parent) {
780 warn("$group already has different parent ($mieMap{$group})\n"), next;
781 }
782 $mieMap{$group} = $parent; # add to map
783 # process tables within this one too
784 $doneTable{$subTableName} and next;
785 $doneTable{$subTableName} = 1;
786 push @tables, [$subTableName, $subTablePtr];
787 }
788 }
789}
790
791#------------------------------------------------------------------------------
792# Get localized version of tagInfo hash
793# Inputs: 0) tagInfo hash ref, 1) locale code (eg. "en_CA")
794# Returns: new tagInfo hash ref, or undef if invalid
795sub GetLangInfo($$)
796{
797 my ($tagInfo, $langCode) = @_;
798 # check for properly formatted language code
799 return undef unless $langCode =~ /^[a-z]{2}([-_])[A-Z]{2}$/;
800 # use '_' as a separator, but recognize '_' or '-'
801 $langCode =~ tr/-/_/ if $1 eq '-';
802 # can only set locale on string types
803 return undef if $$tagInfo{Writable} and $$tagInfo{Writable} ne 'string';
804 return Image::ExifTool::GetLangInfo($tagInfo, $langCode);
805}
806
807#------------------------------------------------------------------------------
808# return true if we have Zlib::Compress
809# Inputs: 0) ExifTool object ref, 1) verb for what you want to do with the info
810# Returns: 1 if Zlib available, 0 otherwise
811sub HasZlib($$)
812{
813 unless (defined $hasZlib) {
814 $hasZlib = eval { require Compress::Zlib };
815 unless ($hasZlib) {
816 $hasZlib = 0;
817 $_[0]->Warn("Install Compress::Zlib to $_[1] compressed information");
818 }
819 }
820 return $hasZlib;
821}
822
823#------------------------------------------------------------------------------
824# Get format code for MIE group element with current byte order
825# Inputs: 0) [optional] true to convert result to chr()
826# Returns: format code
827sub MIEGroupFormat(;$)
828{
829 my $chr = shift;
830 my $format = GetByteOrder() eq 'MM' ? 0x10 : 0x18;
831 return $chr ? chr($format) : $format;
832}
833
834#------------------------------------------------------------------------------
835# ReadValue() with added support for UTF formats (utf8, utf16 and utf32)
836# Inputs: 0) data reference, 1) value offset, 2) format string,
837# 3) number of values (or undef to use all data)
838# 4) valid data length relative to offset, 5) returned rational ref
839# Returns: converted value, or undefined if data isn't there
840# or list of values in list context
841# Notes: all string formats are converted to UTF8
842sub ReadMIEValue($$$$$;$)
843{
844 my ($dataPt, $offset, $format, $count, $size, $ratPt) = @_;
845 my $val;
846 if ($format =~ /^(utf(8|16|32)|string)/) {
847 if ($1 eq 'utf8' or $1 eq 'string') {
848 # read the 8-bit string
849 $val = substr($$dataPt, $offset, $size);
850 # (as of ExifTool 7.62, leave string values unconverted)
851 } else {
852 # convert to UTF8
853 my $fmt;
854 if (GetByteOrder() eq 'MM') {
855 $fmt = ($1 eq 'utf16') ? 'n' : 'N';
856 } else {
857 $fmt = ($1 eq 'utf16') ? 'v' : 'V';
858 }
859 my @unpk = unpack("x$offset$fmt$size",$$dataPt);
860 if ($] >= 5.006001) {
861 $val = pack('C0U*', @unpk);
862 } else {
863 $val = Image::ExifTool::PackUTF8(@unpk);
864 }
865 }
866 # truncate at null unless this is a list
867 # (strings shouldn't have a null, but just in case)
868 $val =~ s/\0.*//s unless $format =~ /_list$/;
869 } else {
870 $format = 'undef' if $format eq 'free'; # read 'free' as 'undef'
871 return ReadValue($dataPt, $offset, $format, $count, $size, $ratPt);
872 }
873 return $val;
874}
875
876#------------------------------------------------------------------------------
877# validate raw values for writing
878# Inputs: 0) ExifTool object ref, 1) tagInfo hash ref, 2) raw value ref
879# Returns: error string or undef (and possibly changes value) on success
880sub CheckMIE($$$)
881{
882 my ($et, $tagInfo, $valPtr) = @_;
883 my $format = $$tagInfo{Writable} || $tagInfo->{Table}->{WRITABLE};
884 my $err;
885
886 return 'No writable format' if not $format or $format eq '1';
887 # handle units if supported by this tag
888 my $ulist = $$tagInfo{Units};
889 if ($ulist and $$valPtr =~ /(.*)\((.*)\)$/) {
890 my ($val, $units) = ($1, $2);
891 ($units) = grep /^$units$/i, @$ulist;
892 defined $units or return 'Allowed units: (' . join('|', @$ulist) . ')';
893 $err = Image::ExifTool::CheckValue(\$val, $format, $$tagInfo{Count});
894 # add units back onto value
895 $$valPtr = "$val($units)" unless $err;
896 } elsif ($format !~ /^(utf|string|undef)/ and $$valPtr =~ /\)$/) {
897 return 'Units not supported';
898 } else {
899 if ($format eq 'string' and $$et{OPTIONS}{Charset} ne 'UTF8' and
900 $$valPtr =~ /[\x80-\xff]/)
901 {
902 # convert from Charset to UTF-8
903 $$valPtr = $et->Encode($$valPtr,'UTF8');
904 }
905 $err = Image::ExifTool::CheckValue($valPtr, $format, $$tagInfo{Count});
906 }
907 return $err;
908}
909
910#------------------------------------------------------------------------------
911# Rewrite a MIE directory
912# Inputs: 0) ExifTool object reference, 1) DirInfo reference, 2) tag table ptr
913# Returns: undef on success, otherwise error message (empty message if nothing to write)
914sub WriteMIEGroup($$$)
915{
916 my ($et, $dirInfo, $tagTablePtr) = @_;
917 my $outfile = $$dirInfo{OutFile};
918 my $dirName = $$dirInfo{DirName};
919 my $toWrite = $$dirInfo{ToWrite} || '';
920 my $raf = $$dirInfo{RAF};
921 my $verbose = $et->Options('Verbose');
922 my $optCompress = $et->Options('Compress');
923 my $out = $et->Options('TextOut');
924 my ($msg, $err, $ok, $sync, $delGroup);
925 my $tag = '';
926 my $deletedTag = '';
927
928 # count each MIE directory found and make name for this specific instance
929 my ($grp1, %isWriting);
930 my $cnt = $$et{MIE_COUNT};
931 my $grp = $tagTablePtr->{GROUPS}->{1};
932 my $n = $$cnt{'MIE-Main'} || 0;
933 if ($grp eq 'MIE-Main') {
934 $$cnt{$grp} = ++$n;
935 ($grp1 = $grp) =~ s/MIE-/MIE$n-/;
936 } else {
937 ($grp1 = $grp) =~ s/MIE-/MIE$n-/;
938 my $m = $$cnt{$grp1} = ($$cnt{$grp1} || 0) + 1;
939 $isWriting{"$grp$m"} = 1; # eg. 'MIE-Doc2'
940 $isWriting{$grp1} = 1; # eg. 'MIE1-Doc'
941 $grp1 .= $m;
942 }
943 # build lookup for all valid group names for this MIE group
944 $isWriting{$grp} = 1; # eg. 'MIE-Doc'
945 $isWriting{$grp1} = 1; # eg. 'MIE1-Doc2'
946 $isWriting{"MIE$n"} = 1; # eg. 'MIE1'
947
948 # determine if we are deleting this group
949 if (%{$$et{DEL_GROUP}}) {
950 $delGroup = 1 if $$et{DEL_GROUP}{MIE} or
951 $$et{DEL_GROUP}{$grp} or
952 $$et{DEL_GROUP}{$grp1} or
953 $$et{DEL_GROUP}{"MIE$n"};
954 }
955
956 # prepare lookups and lists for writing
957 my $newTags = $et->GetNewTagInfoHash($tagTablePtr);
958 my ($addDirs, $editDirs) = $et->GetAddDirHash($tagTablePtr, $dirName);
959 my @editTags = sort keys %$newTags, keys %$editDirs;
960 $verbose and print $out $raf ? 'Writing' : 'Creating', " $grp1:\n";
961
962 # loop through elements in MIE group
963 MieElement: for (;;) {
964 my ($format, $tagLen, $valLen, $units, $oldHdr, $buff);
965 my $lastTag = $tag;
966 if ($raf) {
967 # read first 4 bytes of element header
968 my $n = $raf->Read($oldHdr, 4);
969 if ($n != 4) {
970 last if $n or defined $sync;
971 undef $raf; # all done reading
972 $ok = 1;
973 }
974 }
975 if ($raf) {
976 ($sync, $format, $tagLen, $valLen) = unpack('aC3', $oldHdr);
977 $sync eq '~' or $msg = 'Invalid sync byte', last;
978
979 # read tag name
980 if ($tagLen) {
981 $raf->Read($tag, $tagLen) == $tagLen or last;
982 $oldHdr .= $tag; # add tag to element header
983 $et->Warn("MIE tag '${tag}' out of sequence") if $tag lt $lastTag;
984 # separate units from tag name if they exist
985 $units = $1 if $tag =~ s/\((.*)\)$//;
986 } else {
987 $tag = '';
988 }
989
990 # get multi-byte value length if necessary
991 if ($valLen > 252) {
992 # calculate number of bytes in extended DataLength
993 my $n = 1 << (256 - $valLen);
994 $raf->Read($buff, $n) == $n or last;
995 $oldHdr .= $buff; # add to old header
996 my $fmt = 'int' . ($n * 8) . 'u';
997 $valLen = ReadValue(\$buff, 0, $fmt, 1, $n);
998 if ($valLen > 0x7fffffff) {
999 $msg = "Can't write $tag (DataLength > 2GB not yet supported)";
1000 last;
1001 }
1002 }
1003 # don't rewrite free bytes or information in deleted groups
1004 if ($format == 0x80 or ($delGroup and $tagLen and ($format & 0xf0) != 0x10)) {
1005 $raf->Seek($valLen, 1) or $msg = 'Seek error', last;
1006 if ($verbose > 1) {
1007 my $free = ($format == 0x80) ? ' free' : '';
1008 print $out " - $grp1:$tag ($valLen$free bytes)\n";
1009 }
1010 ++$$et{CHANGED} if $delGroup;
1011 next;
1012 }
1013 } else {
1014 # no more elements to read
1015 $tagLen = $valLen = 0;
1016 $tag = '';
1017 }
1018#
1019# write necessary new tags and process directories
1020#
1021 while (@editTags) {
1022 last if $tagLen and $editTags[0] gt $tag;
1023 # we are writing the new tag now
1024 my ($newVal, $writable, $oldVal, $newFormat, $compress);
1025 my $newTag = shift @editTags;
1026 my $newInfo = $$editDirs{$newTag};
1027 if ($newInfo) {
1028 # create the new subdirectory or rewrite existing non-MIE directory
1029 my $subTablePtr = GetTagTable($newInfo->{SubDirectory}->{TagTable});
1030 unless ($subTablePtr) {
1031 $et->Warn("No tag table for $newTag $$newInfo{Name}");
1032 next;
1033 }
1034 my %subdirInfo;
1035 my $isMieGroup = ($$subTablePtr{WRITE_PROC} and
1036 $$subTablePtr{WRITE_PROC} eq \&ProcessMIE);
1037
1038 if ($newTag eq $tag) {
1039 # make sure that either both or neither old and new tags are MIE groups
1040 if ($isMieGroup xor ($format & 0xf3) == 0x10) {
1041 $et->Warn("Tag '${tag}' not expected type");
1042 next; # don't write our new tag
1043 }
1044 # uncompress existing directory into $oldVal since we are editing it
1045 if ($format & 0x04) {
1046 last unless HasZlib($et, 'edit');
1047 $raf->Read($oldVal, $valLen) == $valLen or last MieElement;
1048 my $stat;
1049 my $inflate = Compress::Zlib::inflateInit();
1050 $inflate and ($oldVal, $stat) = $inflate->inflate($oldVal);
1051 unless ($inflate and $stat == Compress::Zlib::Z_STREAM_END()) {
1052 $msg = "Error inflating $tag";
1053 last MieElement;
1054 }
1055 $compress = 1;
1056 $valLen = length $oldVal; # uncompressed value length
1057 }
1058 } else {
1059 # don't create this directory unless necessary
1060 next unless $$addDirs{$newTag};
1061 }
1062
1063 if ($isMieGroup) {
1064 my $hdr;
1065 if ($newTag eq $tag) {
1066 # rewrite existing directory later unless it was compressed
1067 last unless $compress;
1068 # rewrite directory to '$newVal'
1069 $newVal = '';
1070 %subdirInfo = (
1071 OutFile => \$newVal,
1072 RAF => new File::RandomAccess(\$oldVal),
1073 );
1074 } elsif ($optCompress and not $$dirInfo{IsCompressed}) {
1075 # write to memory so we can compress the new MIE group
1076 $compress = 1;
1077 %subdirInfo = (
1078 OutFile => \$newVal,
1079 );
1080 } else {
1081 $hdr = '~' . MIEGroupFormat(1) . chr(length($newTag)) .
1082 "\0" . $newTag;
1083 %subdirInfo = (
1084 OutFile => $outfile,
1085 ToWrite => $toWrite . $hdr,
1086 );
1087 }
1088 $subdirInfo{DirName} = $newInfo->{SubDirectory}->{DirName} || $newTag;
1089 $subdirInfo{Parent} = $dirName;
1090 # don't compress elements of an already compressed group
1091 $subdirInfo{IsCompressed} = $$dirInfo{IsCompressed} || $compress;
1092 $msg = WriteMIEGroup($et, \%subdirInfo, $subTablePtr);
1093 last MieElement if $msg;
1094 # message is defined but empty if nothing was written
1095 if (defined $msg) {
1096 undef $msg; # not a problem if nothing was written
1097 next;
1098 } elsif (not $compress) {
1099 # group was written already
1100 $toWrite = '';
1101 next;
1102 } elsif (length($newVal) <= 4) { # terminator only?
1103 $verbose and print $out "Deleted compressed $grp1 (empty)\n";
1104 next MieElement if $newTag eq $tag; # deleting the directory
1105 next; # not creating the new directory
1106 }
1107 $writable = 'undef';
1108 $newFormat = MIEGroupFormat();
1109 } else {
1110 if ($newTag eq $tag) {
1111 unless ($compress) {
1112 # read and edit existing directory
1113 $raf->Read($oldVal, $valLen) == $valLen or last MieElement;
1114 }
1115 %subdirInfo = (
1116 DataPt => \$oldVal,
1117 DataLen => $valLen,
1118 DirName => $$newInfo{Name},
1119 DataPos => $$dirInfo{IsCompressed} ? undef : $raf->Tell() - $valLen,
1120 DirStart=> 0,
1121 DirLen => $valLen,
1122 );
1123 # write Compact subdirectories if we will compress the data
1124 if (($compress or $optCompress or $$dirInfo{IsCompressed}) and
1125 eval { require Compress::Zlib })
1126 {
1127 $subdirInfo{Compact} = 1;
1128 $subdirInfo{ReadOnly} = 1; # because XMP is not writable in place
1129 }
1130 }
1131 $subdirInfo{Parent} = $dirName;
1132 my $writeProc = $newInfo->{SubDirectory}->{WriteProc};
1133 # reset processed lookup to avoid errors in case of multiple EXIF blocks
1134 $$et{PROCESSED} = { };
1135 $newVal = $et->WriteDirectory(\%subdirInfo, $subTablePtr, $writeProc);
1136 if (defined $newVal) {
1137 if ($newVal eq '') {
1138 next MieElement if $newTag eq $tag; # deleting the directory
1139 next; # not creating the new directory
1140 }
1141 } else {
1142 next unless defined $oldVal;
1143 $newVal = $oldVal; # just copy over the old directory
1144 }
1145 $writable = 'undef';
1146 $newFormat = 0x00; # all other directories are 'undef' format
1147 }
1148 } else {
1149
1150 # get the new tag information
1151 $newInfo = $$newTags{$newTag};
1152 my $nvHash = $et->GetNewValueHash($newInfo);
1153 my @newVals;
1154
1155 # write information only to specified group
1156 my $writeGroup = $$nvHash{WriteGroup};
1157 last unless $isWriting{$writeGroup};
1158
1159 # if tag existed, must decide if we want to overwrite the value
1160 if ($newTag eq $tag) {
1161 my $isOverwriting;
1162 my $isList = $$newInfo{List};
1163 if ($isList) {
1164 last if $$nvHash{CreateOnly};
1165 $isOverwriting = -1; # force processing list elements individually
1166 } else {
1167 $isOverwriting = $et->IsOverwriting($nvHash);
1168 last unless $isOverwriting;
1169 }
1170 my ($val, $cmpVal);
1171 if ($isOverwriting < 0 or $verbose > 1) {
1172 # check to be sure we can uncompress the value if necessary
1173 HasZlib($et, 'edit') or last if $format & 0x04;
1174 # read the old value
1175 $raf->Read($oldVal, $valLen) == $valLen or last MieElement;
1176 # uncompress if necessary
1177 if ($format & 0x04) {
1178 my $stat;
1179 my $inflate = Compress::Zlib::inflateInit();
1180 # must save original compressed value in case we decide
1181 # not to overwrite it later
1182 $cmpVal = $oldVal;
1183 $inflate and ($oldVal, $stat) = $inflate->inflate($oldVal);
1184 unless ($inflate and $stat == Compress::Zlib::Z_STREAM_END()) {
1185 $msg = "Error inflating $tag";
1186 last MieElement;
1187 }
1188 $valLen = length $oldVal; # update value length
1189 }
1190 # convert according to specified format
1191 my $formatStr = $mieFormat{$format & 0xfb} || 'undef';
1192 $val = ReadMIEValue(\$oldVal, 0, $formatStr, undef, $valLen);
1193 if ($isOverwriting < 0 and defined $val) {
1194 # handle list values individually
1195 if ($isList) {
1196 my (@vals, $v);
1197 if ($formatStr =~ /_list$/) {
1198 @vals = split "\0", $val;
1199 } else {
1200 @vals = $val;
1201 }
1202 # keep any list items that we aren't overwriting
1203 foreach $v (@vals) {
1204 next if $et->IsOverwriting($nvHash, $v);
1205 push @newVals, $v;
1206 }
1207 } else {
1208 # test to see if we really want to overwrite the value
1209 $isOverwriting = $et->IsOverwriting($nvHash, $val);
1210 }
1211 }
1212 }
1213 if ($isOverwriting) {
1214 # skip the old value if we didn't read it already
1215 unless (defined $oldVal) {
1216 $raf->Seek($valLen, 1) or $msg = 'Seek error';
1217 }
1218 if ($verbose > 1) {
1219 $val .= "($units)" if defined $units;
1220 $et->VerboseValue("- $grp1:$$newInfo{Name}", $val);
1221 }
1222 $deletedTag = $tag; # remember that we deleted this tag
1223 ++$$et{CHANGED}; # we deleted the old value
1224 } else {
1225 if (defined $oldVal) {
1226 # write original compressed value
1227 $oldVal = $cmpVal if defined $cmpVal;
1228 } else {
1229 $raf->Read($oldVal, $valLen) == $valLen or last MieElement;
1230 }
1231 # write the old value now
1232 Write($outfile, $toWrite, $oldHdr, $oldVal) or $err = 1;
1233 $toWrite = '';
1234 next MieElement;
1235 }
1236 unless (@newVals) {
1237 # unshift the new tag info to write it later
1238 unshift @editTags, $newTag;
1239 next MieElement; # get next element from file
1240 }
1241 } else {
1242 # write new value if creating, or if List and list existed, or
1243 # if tag was previously deleted
1244 next unless $$nvHash{IsCreating} or
1245 ($newTag eq $lastTag and ($$newInfo{List} or $deletedTag eq $lastTag));
1246 }
1247 # get the new value to write (undef to delete)
1248 push @newVals, $et->GetNewValue($nvHash);
1249 next unless @newVals;
1250 $writable = $$newInfo{Writable} || $$tagTablePtr{WRITABLE};
1251 if ($writable eq 'string') {
1252 # join multiple values into a single string
1253 $newVal = join "\0", @newVals;
1254 # write string as UTF-8,16 or 32 if value contains valid UTF-8 codes
1255 require Image::ExifTool::XMP;
1256 my $isUTF8 = Image::ExifTool::XMP::IsUTF8(\$newVal);
1257 if ($isUTF8 > 0) {
1258 $writable = 'utf8';
1259 # write UTF-16 or UTF-32 if it is more compact
1260 my $to = $isUTF8 > 1 ? 'UCS4' : 'UCS2';
1261 my $tmp = Image::ExifTool::Decode(undef,$newVal,'UTF8',undef,$to);
1262 if (length $tmp < length $newVal) {
1263 $newVal = $tmp;
1264 $writable = ($isUTF8 > 1) ? 'utf32' : 'utf16';
1265 }
1266 }
1267 # write as a list if we have multiple values
1268 $writable .= '_list' if @newVals > 1;
1269 } else {
1270 # should only be one element in the list
1271 $newVal = shift @newVals;
1272 }
1273 $newFormat = $mieCode{$writable};
1274 unless (defined $newFormat) {
1275 $msg = "Bad format '${writable}' for $$newInfo{Name}";
1276 next MieElement;
1277 }
1278 }
1279
1280 # write the new or edited element
1281 while (defined $newFormat) {
1282 my $valPt = \$newVal;
1283 # remove units from value and add to tag name if supported by this tag
1284 if ($$newInfo{Units}) {
1285 my $val2;
1286 if ($$valPt =~ /(.*)\((.*)\)$/) {
1287 $val2 = $1;
1288 $newTag .= "($2)";
1289 } else {
1290 $val2 = $$valPt;
1291 # add default units
1292 my $ustr = '(' . $newInfo->{Units}->[0] . ')';
1293 $newTag .= $ustr;
1294 $$valPt .= $ustr;
1295 }
1296 $valPt = \$val2;
1297 }
1298 # convert value if necessary
1299 if ($writable !~ /^(utf|string|undef)/) {
1300 my $val3 = WriteValue($$valPt, $writable, $$newInfo{Count});
1301 defined $val3 or $et->Warn("Error writing $newTag"), last;
1302 $valPt = \$val3;
1303 }
1304 my $len = length $$valPt;
1305 # compress value before writing if required
1306 if (($compress or $optCompress) and not $$dirInfo{IsCompressed} and
1307 HasZlib($et, 'write'))
1308 {
1309 my $deflate = Compress::Zlib::deflateInit();
1310 my $val4;
1311 if ($deflate) {
1312 $val4 = $deflate->deflate($$valPt);
1313 $val4 .= $deflate->flush() if defined $val4;
1314 }
1315 if (defined $val4) {
1316 my $len4 = length $val4;
1317 my $saved = $len - $len4;
1318 # only use compressed data if it is smaller
1319 if ($saved > 0) {
1320 $verbose and print $out " [$newTag compression saved $saved bytes]\n";
1321 $newFormat |= 0x04; # set compressed bit
1322 $len = $len4; # set length
1323 $valPt = \$val4; # set value pointer
1324 } elsif ($verbose) {
1325 print $out " [$newTag compression saved $saved bytes -- written uncompressed]\n";
1326 }
1327 } else {
1328 $et->Warn("Error deflating $newTag (written uncompressed)");
1329 }
1330 }
1331 # calculate the DataLength code
1332 my $extLen;
1333 if ($len < 253) {
1334 $extLen = '';
1335 } elsif ($len < 65536) {
1336 $extLen = Set16u($len);
1337 $len = 255;
1338 } elsif ($len <= 0x7fffffff) {
1339 $extLen = Set32u($len);
1340 $len = 254;
1341 } else {
1342 $et->Warn("Can't write $newTag (DataLength > 2GB not yet supported)");
1343 last; # don't write this tag
1344 }
1345 # write this element (with leading MIE group element if not done already)
1346 my $hdr = $toWrite . '~' . chr($newFormat) . chr(length $newTag);
1347 Write($outfile, $hdr, chr($len), $newTag, $extLen, $$valPt) or $err = 1;
1348 $toWrite = '';
1349 # we changed a tag unless just editing a subdirectory
1350 unless ($$editDirs{$newTag}) {
1351 $et->VerboseValue("+ $grp1:$$newInfo{Name}", $newVal);
1352 ++$$et{CHANGED};
1353 }
1354 last; # didn't want to loop anyway
1355 }
1356 next MieElement if defined $oldVal;
1357 }
1358#
1359# rewrite existing element or descend into uncompressed MIE group
1360#
1361 # all done this MIE group if we reached the terminator element
1362 unless ($tagLen) {
1363 # skip over existing terminator data (if any)
1364 last if $valLen and not $raf->Seek($valLen, 1);
1365 $ok = 1;
1366 # write group terminator if necessary
1367 unless ($toWrite) {
1368 # write end-of-group terminator element
1369 my $term = "~\0\0\0";
1370 unless ($$dirInfo{Parent}) {
1371 # write extended terminator for file-level group
1372 my $len = ref $outfile eq 'SCALAR' ? length($$outfile) : tell $outfile;
1373 $len += 10; # include length of terminator itself
1374 if ($len and $len <= 0x7fffffff) {
1375 $term = "~\0\0\x06" . Set32u($len) . MIEGroupFormat(1) . "\x04";
1376 }
1377 }
1378 Write($outfile, $term) or $err = 1;
1379 }
1380 last;
1381 }
1382
1383 # descend into existing uncompressed MIE group
1384 if ($format == 0x10 or $format == 0x18) {
1385 my ($subTablePtr, $dirName);
1386 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
1387 if ($tagInfo and $$tagInfo{SubDirectory}) {
1388 $dirName = $tagInfo->{SubDirectory}->{DirName};
1389 my $subTable = $tagInfo->{SubDirectory}->{TagTable};
1390 $subTablePtr = $subTable ? GetTagTable($subTable) : $tagTablePtr;
1391 } else {
1392 $subTablePtr = GetTagTable('Image::ExifTool::MIE::Unknown');
1393 }
1394 my $hdr = '~' . chr($format) . chr(length $tag) . "\0" . $tag;
1395 my %subdirInfo = (
1396 DirName => $dirName || $tag,
1397 RAF => $raf,
1398 ToWrite => $toWrite . $hdr,
1399 OutFile => $outfile,
1400 Parent => $dirName,
1401 IsCompressed => $$dirInfo{IsCompressed},
1402 );
1403 my $oldOrder = GetByteOrder();
1404 SetByteOrder($format & 0x08 ? 'II' : 'MM');
1405 $msg = WriteMIEGroup($et, \%subdirInfo, $subTablePtr);
1406 SetByteOrder($oldOrder);
1407 last if $msg;
1408 if (defined $msg) {
1409 undef $msg; # no problem if nothing written
1410 } else {
1411 $toWrite = '';
1412 }
1413 next;
1414 }
1415 # just copy existing element
1416 my $oldVal;
1417 $raf->Read($oldVal, $valLen) == $valLen or last;
1418 if ($toWrite) {
1419 Write($outfile, $toWrite) or $err = 1;
1420 $toWrite = '';
1421 }
1422 Write($outfile, $oldHdr, $oldVal) or $err = 1;
1423 }
1424 # return error message
1425 if ($err) {
1426 $msg = 'Error writing file';
1427 } elsif (not $ok and not $msg) {
1428 $msg = 'Unexpected end of file';
1429 } elsif (not $msg and $toWrite) {
1430 $msg = ''; # flag for nothing written
1431 $verbose and print $out "Deleted $grp1 (empty)\n";
1432 }
1433 return $msg;
1434}
1435
1436#------------------------------------------------------------------------------
1437# Process MIE directory
1438# Inputs: 0) ExifTool object reference, 1) DirInfo reference, 2) tag table ref
1439# Returns: undef on success, or error message if there was a problem
1440# Notes: file pointer is positioned at the MIE end on entry
1441sub ProcessMIEGroup($$$)
1442{
1443 my ($et, $dirInfo, $tagTablePtr) = @_;
1444 my $raf = $$dirInfo{RAF};
1445 my $verbose = $et->Options('Verbose');
1446 my $out = $et->Options('TextOut');
1447 my $notUTF8 = ($$et{OPTIONS}{Charset} ne 'UTF8');
1448 my ($msg, $buff, $ok, $oldIndent, $mime);
1449 my $lastTag = '';
1450
1451 # get group 1 names: $grp doesn't have numbers (eg. 'MIE-Doc'),
1452 # and $grp1 does (eg. 'MIE1-Doc1')
1453 my $cnt = $$et{MIE_COUNT};
1454 my $grp1 = $tagTablePtr->{GROUPS}->{1};
1455 my $n = $$cnt{'MIE-Main'} || 0;
1456 if ($grp1 eq 'MIE-Main') {
1457 $$cnt{$grp1} = ++$n;
1458 $grp1 =~ s/MIE-/MIE$n-/ if $n > 1;
1459 } else {
1460 $grp1 =~ s/MIE-/MIE$n-/ if $n > 1;
1461 $$cnt{$grp1} = ($$cnt{$grp1} || 0) + 1;
1462 $grp1 .= $$cnt{$grp1} if $$cnt{$grp1} > 1;
1463 }
1464 # set group1 name for all tags extracted from this group
1465 $$et{SET_GROUP1} = $grp1;
1466
1467 if ($verbose) {
1468 $oldIndent = $$et{INDENT};
1469 $$et{INDENT} .= '| ';
1470 $et->VerboseDir($grp1);
1471 }
1472 my $wasCompressed = $$dirInfo{WasCompressed};
1473
1474 # process all MIE elements
1475 for (;;) {
1476 $raf->Read($buff, 4) == 4 or last;
1477 my ($sync, $format, $tagLen, $valLen) = unpack('aC3', $buff);
1478 $sync eq '~' or $msg = 'Invalid sync byte', last;
1479
1480 # read tag name
1481 my ($tag, $units);
1482 if ($tagLen) {
1483 $raf->Read($tag, $tagLen) == $tagLen or last;
1484 $et->Warn("MIE tag '${tag}' out of sequence") if $tag lt $lastTag;
1485 $lastTag = $tag;
1486 # separate units from tag name if they exist
1487 $units = $1 if $tag =~ s/\((.*)\)$//;
1488 } else {
1489 $tag = '';
1490 }
1491
1492 # get multi-byte value length if necessary
1493 if ($valLen > 252) {
1494 my $n = 1 << (256 - $valLen);
1495 $raf->Read($buff, $n) == $n or last;
1496 my $fmt = 'int' . ($n * 8) . 'u';
1497 $valLen = ReadValue(\$buff, 0, $fmt, 1, $n);
1498 if ($valLen > 0x7fffffff) {
1499 $msg = "Can't read $tag (DataLength > 2GB not yet supported)";
1500 last;
1501 }
1502 }
1503
1504 # all done if we reached the group terminator
1505 unless ($tagLen) {
1506 # skip over terminator data block
1507 $ok = 1 unless $valLen and not $raf->Seek($valLen, 1);
1508 last;
1509 }
1510
1511 # get tag information hash unless this is free space
1512 my ($tagInfo, $value);
1513 while ($format != 0x80) {
1514 $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
1515 last if $tagInfo;
1516 # extract tags with locale code
1517 if ($tag =~ /\W/) {
1518 if ($tag =~ /^(\w+)-([a-z]{2}_[A-Z]{2})$/) {
1519 my ($baseTag, $langCode) = ($1, $2);
1520 $tagInfo = $et->GetTagInfo($tagTablePtr, $baseTag);
1521 $tagInfo = GetLangInfo($tagInfo, $langCode) if $tagInfo;
1522 last if $tagInfo;
1523 } else {
1524 $et->Warn('Invalid MIE tag name');
1525 last;
1526 }
1527 }
1528 # extract unknown tags if specified
1529 $tagInfo = {
1530 Name => $tag,
1531 Writable => 0,
1532 PrintConv => 'length($val) > 60 ? substr($val,0,55) . "[...]" : $val',
1533 };
1534 AddTagToTable($tagTablePtr, $tag, $tagInfo);
1535 last;
1536 }
1537
1538 # read value and uncompress if necessary
1539 my $formatStr = $mieFormat{$format & 0xfb} || 'undef';
1540 if ($tagInfo or ($formatStr eq 'MIE' and $format & 0x04)) {
1541 $raf->Read($value, $valLen) == $valLen or last;
1542 if ($format & 0x04) {
1543 if ($verbose) {
1544 print $out "$$et{INDENT}\[Tag '${tag}' $valLen bytes compressed]\n";
1545 }
1546 next unless HasZlib($et, 'decode');
1547 my $stat;
1548 my $inflate = Compress::Zlib::inflateInit();
1549 $inflate and ($value, $stat) = $inflate->inflate($value);
1550 unless ($inflate and $stat == Compress::Zlib::Z_STREAM_END()) {
1551 $et->Warn("Error inflating $tag");
1552 next;
1553 }
1554 $valLen = length $value;
1555 $wasCompressed = 1;
1556 }
1557 }
1558
1559 # process this tag
1560 if ($formatStr eq 'MIE') {
1561 # process MIE directory
1562 my ($subTablePtr, $dirName);
1563 if ($tagInfo and $$tagInfo{SubDirectory}) {
1564 $dirName = $tagInfo->{SubDirectory}->{DirName};
1565 my $subTable = $tagInfo->{SubDirectory}->{TagTable};
1566 $subTablePtr = $subTable ? GetTagTable($subTable) : $tagTablePtr;
1567 } else {
1568 $subTablePtr = GetTagTable('Image::ExifTool::MIE::Unknown');
1569 }
1570 if ($verbose) {
1571 my $order = ', byte order ' . GetByteOrder();
1572 $et->VerboseInfo($tag, $tagInfo, Size => $valLen, Extra => $order);
1573 }
1574 my %subdirInfo = (
1575 DirName => $dirName || $tag,
1576 RAF => $raf,
1577 Parent => $$dirInfo{DirName},
1578 WasCompressed => $wasCompressed,
1579 );
1580 # read from uncompressed data instead if necessary
1581 $subdirInfo{RAF} = new File::RandomAccess(\$value) if $valLen;
1582
1583 my $oldOrder = GetByteOrder();
1584 SetByteOrder($format & 0x08 ? 'II' : 'MM');
1585 $msg = ProcessMIEGroup($et, \%subdirInfo, $subTablePtr);
1586 SetByteOrder($oldOrder);
1587 $$et{SET_GROUP1} = $grp1; # restore this group1 name
1588 last if $msg;
1589 } else {
1590 # process MIE data format types
1591 if ($tagInfo) {
1592 my $rational;
1593 # extract tag value
1594 my $val = ReadMIEValue(\$value, 0, $formatStr, undef, $valLen, \$rational);
1595 unless (defined $val) {
1596 $et->Warn("Error reading $tag value");
1597 $val = '<err>';
1598 }
1599 # save type or mime type
1600 $mime = $val if $tag eq '0Type' or $tag eq '2MIME';
1601 if ($verbose) {
1602 my $count;
1603 my $s = Image::ExifTool::FormatSize($formatStr);
1604 if ($s and $formatStr !~ /^(utf|string|undef)/) {
1605 $count = $valLen / $s;
1606 }
1607 $et->VerboseInfo($lastTag, $tagInfo,
1608 DataPt => \$value,
1609 DataPos => $wasCompressed ? undef : $raf->Tell() - $valLen,
1610 Size => $valLen,
1611 Format => $formatStr,
1612 Value => $val,
1613 Count => $count,
1614 );
1615 }
1616 if ($$tagInfo{SubDirectory}) {
1617 my $subTablePtr = GetTagTable($tagInfo->{SubDirectory}->{TagTable});
1618 my %subdirInfo = (
1619 DirName => $$tagInfo{Name},
1620 DataPt => \$value,
1621 DataLen => $valLen,
1622 DirStart=> 0,
1623 DirLen => $valLen,
1624 Parent => $$dirInfo{DirName},
1625 WasCompressed => $wasCompressed,
1626 );
1627 # set DataPos and Base for uncompressed information only
1628 unless ($wasCompressed) {
1629 $subdirInfo{DataPos} = 0; # (relative to Base)
1630 $subdirInfo{Base} = $raf->Tell() - $valLen;
1631 }
1632 # reset PROCESSED lookup for each MIE directory
1633 # (there is no possibility of double-processing a MIE directory)
1634 $$et{PROCESSED} = { };
1635 my $processProc = $tagInfo->{SubDirectory}->{ProcessProc};
1636 delete $$et{SET_GROUP1};
1637 delete $$et{NO_LIST};
1638 $et->ProcessDirectory(\%subdirInfo, $subTablePtr, $processProc);
1639 $$et{SET_GROUP1} = $grp1;
1640 $$et{NO_LIST} = 1;
1641 } else {
1642 # convert to specified character set if necessary
1643 if ($notUTF8 and $formatStr =~ /^(utf|string)/) {
1644 $val = $et->Decode($val, 'UTF8');
1645 }
1646 if ($formatStr =~ /_list$/) {
1647 # split list value into separate strings
1648 my @vals = split "\0", $val;
1649 $val = \@vals;
1650 }
1651 if (defined $units) {
1652 $val = "@$val" if ref $val; # convert string list to number list
1653 # add units to value if specified
1654 $val .= "($units)" if defined $units;
1655 }
1656 my $key = $et->FoundTag($tagInfo, $val);
1657 $$et{RATIONAL}{$key} = $rational if defined $rational and defined $key;
1658 }
1659 } else {
1660 # skip over unknown information or free bytes
1661 $raf->Seek($valLen, 1) or $msg = 'Seek error', last;
1662 $verbose and $et->VerboseInfo($tag, undef, Size => $valLen);
1663 }
1664 }
1665 }
1666 # modify MIME type if necessary
1667 $mime and not $$dirInfo{Parent} and $et->ModifyMimeType($mime);
1668
1669 $ok or $msg or $msg = 'Unexpected end of file';
1670 $verbose and $$et{INDENT} = $oldIndent;
1671 return $msg;
1672}
1673
1674#------------------------------------------------------------------------------
1675# Read/write a MIE file
1676# Inputs: 0) ExifTool object reference, 1) DirInfo reference
1677# Returns: 1 on success, 0 if this wasn't a valid MIE file, or -1 on write error
1678# - process as a trailer if "Trailer" flag set in dirInfo
1679sub ProcessMIE($$)
1680{
1681 my ($et, $dirInfo) = @_;
1682 return 1 unless defined $et;
1683 my $raf = $$dirInfo{RAF};
1684 my $outfile = $$dirInfo{OutFile};
1685 my ($buff, $err, $msg, $pos, $end, $isCreating);
1686 my $numDocs = 0;
1687#
1688# process as a trailer (from end of file) if specified
1689#
1690 if ($$dirInfo{Trailer}) {
1691 my $offset = $$dirInfo{Offset} || 0; # offset from end of file
1692 $raf->Seek(-10 - $offset, 2) or return 0;
1693 for (;;) {
1694 # read and validate last 10 bytes
1695 $raf->Read($buff, 10) == 10 or last;
1696 last unless $buff =~ /~\0\0\x06.{4}(\x10|\x18)(\x04)$/s or
1697 $buff =~ /(\x10|\x18)(\x08)$/s;
1698 SetByteOrder($1 eq "\x10" ? 'MM' : 'II');
1699 my $len = ($2 eq "\x04") ? Get32u(\$buff, 4) : Get64u(\$buff, 0);
1700 my $curPos = $raf->Tell() or last;
1701 last if $len < 12 or $len > $curPos;
1702 # validate element header if 8-byte offset was used
1703 if ($2 eq "\x08") {
1704 last if $len < 14;
1705 $raf->Seek($curPos - 14, 0) and $raf->Read($buff, 4) or last;
1706 last unless $buff eq "~\0\0\x0a";
1707 }
1708 # looks like a good group, so remember start position
1709 $pos = $curPos - $len;
1710 $end = $curPos unless $end;
1711 # seek to 10 bytes from end of previous group
1712 $raf->Seek($pos - 10, 0) or last;
1713 }
1714 # seek to start of first MIE group
1715 return 0 unless defined $pos and $raf->Seek($pos, 0);
1716 # update DataPos and DirLen for ProcessTrailers()
1717 $$dirInfo{DataPos} = $pos;
1718 $$dirInfo{DirLen} = $end - $pos;
1719 if ($outfile and $$et{DEL_GROUP}{MIE}) {
1720 # delete the trailer
1721 $et->VPrint(0," Deleting MIE trailer\n");
1722 ++$$et{CHANGED};
1723 return 1;
1724 } elsif ($et->Options('Verbose') or $$et{HTML_DUMP}) {
1725 $et->DumpTrailer($dirInfo);
1726 }
1727 }
1728#
1729# loop through all documents in MIE file
1730#
1731 for (;;) {
1732 # look for "0MIE" group element
1733 my $num = $raf->Read($buff, 8);
1734 if ($num == 8) {
1735 # verify file identifier
1736 if ($buff =~ /^~(\x10|\x18)\x04(.)0MIE/s) {
1737 SetByteOrder($1 eq "\x10" ? 'MM' : 'II');
1738 my $len = ord($2);
1739 # skip extended DataLength if it exists
1740 if ($len > 252 and not $raf->Seek(1 << (256 - $len), 1)) {
1741 $msg = 'Seek error';
1742 last;
1743 }
1744 } else {
1745 return 0 unless $numDocs; # not a MIE file
1746 if ($buff =~ /^~/) {
1747 $msg = 'Non-standard file-level MIE element';
1748 } else {
1749 $msg = 'Invalid MIE file-level data';
1750 }
1751 }
1752 } elsif ($numDocs) {
1753 last unless $num; # OK, all done with file
1754 $msg = 'Truncated MIE element header';
1755 } else {
1756 return 0 if $num or not $outfile;
1757 # we have the ability to create a MIE file from scratch
1758 $buff = ''; # start from nothing
1759 # set byte order according to preferences
1760 $et->SetPreferredByteOrder();
1761 $isCreating = 1;
1762 }
1763 if ($msg) {
1764 last if $$dirInfo{Trailer}; # allow other trailers after MIE
1765 if ($outfile) {
1766 $et->Error($msg);
1767 } else {
1768 $et->Warn($msg);
1769 }
1770 last;
1771 }
1772 # this is a new MIE document -- increment document count
1773 unless ($numDocs) {
1774 # this is a valid MIE file (unless a trailer on another file)
1775 $et->SetFileType();
1776 $$et{NO_LIST} = 1; # handle lists ourself
1777 $$et{MIE_COUNT} = { };
1778 undef $hasZlib;
1779 }
1780 ++$numDocs;
1781
1782 # process the MIE groups recursively, beginning with the main MIE group
1783 my $tagTablePtr = GetTagTable('Image::ExifTool::MIE::Main');
1784
1785 my %subdirInfo = (
1786 DirName => 'MIE',
1787 RAF => $raf,
1788 OutFile => $outfile,
1789 # don't define Parent so WriteMIEGroup() writes extended terminator
1790 );
1791 if ($outfile) {
1792 # generate lookup for MIE format codes if not done already
1793 unless (%mieCode) {
1794 foreach (keys %mieFormat) {
1795 $mieCode{$mieFormat{$_}} = $_;
1796 }
1797 }
1798 # update %mieMap with user-defined MIE groups
1799 UpdateMieMap() unless $doneMieMap;
1800 # initialize write directories, with MIE tags taking priority
1801 # (note that this may re-initialize directories when writing trailer
1802 # to another type of image, but this is OK because we are done writing
1803 # the other format by the time we start writing the trailer)
1804 $et->InitWriteDirs(\%mieMap, 'MIE');
1805 $subdirInfo{ToWrite} = '~' . MIEGroupFormat(1) . "\x04\xfe0MIE\0\0\0\0";
1806 $msg = WriteMIEGroup($et, \%subdirInfo, $tagTablePtr);
1807 if ($msg) {
1808 $et->Error($msg);
1809 $err = 1;
1810 last;
1811 } elsif (defined $msg and $isCreating) {
1812 last;
1813 }
1814 } else {
1815 $msg = ProcessMIEGroup($et, \%subdirInfo, $tagTablePtr);
1816 if ($msg) {
1817 $et->Warn($msg);
1818 last;
1819 }
1820 }
1821 }
1822 delete $$et{NO_LIST};
1823 delete $$et{MIE_COUNT};
1824 delete $$et{SET_GROUP1};
1825 return $err ? -1 : 1;
1826}
1827
18281; # end
1829
1830__END__
1831
1832=head1 NAME
1833
1834Image::ExifTool::MIE - Read/write MIE meta information
1835
1836=head1 SYNOPSIS
1837
1838This module is used by Image::ExifTool
1839
1840=head1 DESCRIPTION
1841
1842This module contains routines required by Image::ExifTool to read and write
1843information in MIE files.
1844
1845=head1 WHAT IS MIE?
1846
1847MIE stands for "Meta Information Encapsulation". The MIE format is an
1848extensible, dedicated meta information format which supports storage of
1849binary as well as textual meta information. MIE can be used to encapsulate
1850meta information from many sources and bundle it together with any type of
1851file.
1852
1853=head2 Features
1854
1855Below is very subjective score card comparing the features of a number of
1856common file and meta information formats, and comparing them to MIE. The
1857following features are rated for each format with a score of 0 to 10:
1858
1859 1) Extensible (can incorporate user-defined information).
1860 2) Meaningful tag ID's (hint to meaning of unknown information).
1861 3) Sequential read/write ability (streamable).
1862 4) Hierarchical information structure.
1863 5) Easy to implement reader/writer/editor.
1864 6) Order of information well defined.
1865 7) Large data lengths supported: >64kB (+5) and >4GB (+5).
1866 8) Localized text strings.
1867 9) Multiple documents in a single file.
1868 10) Compact format doesn't squander disk space or bandwidth.
1869 11) Compressed meta information supported.
1870 12) Relocatable data elements (ie. no fixed offsets).
1871 13) Binary meta information (+7) with variable byte order (+3).
1872 14) Mandatory tags not required (an unnecessary complication).
1873 15) Append information to end of file without editing.
1874
1875 Feature number Total
1876 Format 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Score
1877 ------ --------------------------------------------- -----
1878 MIE 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 150
1879 PDF 10 10 0 10 0 0 10 0 10 10 10 0 7 10 10 97
1880 PNG 10 10 10 0 8 0 5 10 0 10 10 10 0 10 0 93
1881 XMP 10 10 10 10 2 0 10 10 10 0 0 10 0 10 0 92
1882 AIFF 0 5 10 10 10 0 5 0 0 10 0 10 7 10 0 77
1883 RIFF 0 5 10 10 10 0 5 0 0 10 0 10 7 10 0 77
1884 JPEG 10 0 10 0 10 0 0 0 0 10 0 10 7 10 0 67
1885 EPS 10 10 10 0 0 0 10 0 10 0 0 5 0 10 0 65
1886 CIFF 0 0 0 10 10 0 5 0 0 10 0 10 10 10 0 65
1887 TIFF 0 0 0 10 5 10 5 0 10 10 0 0 10 0 0 60
1888 EXIF 0 0 0 10 5 10 0 0 0 10 0 0 10 0 0 45
1889 IPTC 0 0 10 0 8 0 0 0 0 10 0 10 7 0 0 45
1890
1891By design, MIE ranks highest by a significant margin. Other formats with
1892reasonable scores are PDF, PNG and XMP, but each has significant weak
1893points. What may be surprising is that TIFF, EXIF and IPTC rank so low.
1894
1895As well as scoring high in all these features, the MIE format has the unique
1896ability to encapsulate any other type of file, and provides a non-invasive
1897method of adding meta information to a file. The meta information is
1898logically separated from the original file data, which is extremely
1899important because meta information is routinely lost when files are edited.
1900
1901Also, the MIE format supports multiple files by simple concatenation,
1902enabling all kinds of wonderful features such as linear databases, edit
1903histories or non-intrusive file updates. This ability can also be leveraged
1904to allow MIE-format trailers to be added to some other file types.
1905
1906=head1 MIE 1.1 FORMAT SPECIFICATION (2007-01-21)
1907
1908=head2 File Structure
1909
1910A MIE file consists of a series of MIE elements. A MIE element may contain
1911either data or a group of MIE elements, providing a hierarchical format for
1912storing data. Each MIE element is identified by a human-readable tag name,
1913and may store data from zero to 2^64-1 bytes in length.
1914
1915=head2 File Signature
1916
1917The first element in the MIE file must be an uncompressed MIE group element
1918with a tag name of "0MIE". This restriction allows the first 8 bytes of a
1919MIE file to be used to identify a MIE format file. The following table
1920lists the two possible initial byte sequences for a MIE-format file (the
1921first for big-endian, and the second for little-endian byte ordering):
1922
1923 Byte Number: 0 1 2 3 4 5 6 7
1924
1925 C Characters: ~ \x10 \x04 ? 0 M I E
1926 or ~ \x18 \x04 ? 0 M I E
1927
1928 Hexadecimal: 7e 10 04 ? 30 4d 49 45
1929 or 7e 18 04 ? 30 4d 49 45
1930
1931 Decimal: 126 16 4 ? 48 77 73 69
1932 or 126 24 4 ? 48 77 73 69
1933
1934Note that byte 1 may have one of the two possible values (0x10 or 0x18), and
1935byte 3 may have any value (0x00 to 0xff).
1936
1937=head2 Element Structure
1938
1939 1 byte SyncByte = 0x7e (decimal 126, character '~')
1940 1 byte FormatCode (see below)
1941 1 byte TagLength (T)
1942 1 byte DataLength (gives D if DataLength < 253)
1943 T bytes TagName (T given by TagLength)
1944 2 bytes DataLength2 [exists only if DataLength == 255 (0xff)]
1945 4 bytes DataLength4 [exists only if DataLength == 254 (0xfe)]
1946 8 bytes DataLength8 [exists only if DataLength == 253 (0xfd)]
1947 D bytes DataBlock (D given by DataLength)
1948
1949The minimum element length is 4 bytes (for a group terminator). The maximum
1950DataBlock size is 2^64-1 bytes. TagLength and DataLength are unsigned
1951integers, and the byte ordering for multi-byte DataLength fields is
1952specified by the containing MIE group element. The SyncByte is byte
1953aligned, so no padding is added to align on an N-byte boundary.
1954
1955=head3 FormatCode
1956
1957The format code is a bitmask that defines the format of the data:
1958
1959 7654 3210
1960 ++++ ---- FormatType
1961 ---- +--- TypeModifier
1962 ---- -+-- Compressed
1963 ---- --++ FormatSize
1964
1965=over 4
1966
1967=item FormatType (bitmask 0xf0):
1968
1969 0x00 - other (or unknown) data
1970 0x10 - MIE group
1971 0x20 - text string
1972 0x30 - list of null-separated text strings
1973 0x40 - integer
1974 0x50 - rational
1975 0x60 - fixed point
1976 0x70 - floating point
1977 0x80 - free space
1978
1979=item TypeModifier (bitmask 0x08):
1980
1981Modifies the meaning of certain FormatTypes (0x00-0x60):
1982
1983 0x08 - other data sensitive to MIE group byte order
1984 0x18 - MIE group with little-endian byte ordering
1985 0x28 - UTF encoded text string
1986 0x38 - UTF encoded text string list
1987 0x48 - signed integer
1988 0x58 - signed rational (denominator is always unsigned)
1989 0x68 - signed fixed-point
1990
1991=item Compressed (bitmask 0x04):
1992
1993If this bit is set, the data block is compressed using Zlib deflate. An
1994entire MIE group may be compressed, with the exception of file-level groups.
1995
1996=item FormatSize (bitmask 0x03):
1997
1998Gives the byte size of each data element:
1999
2000 0x00 - 8 bits (1 byte)
2001 0x01 - 16 bits (2 bytes)
2002 0x02 - 32 bits (4 bytes)
2003 0x03 - 64 bits (8 bytes)
2004
2005The number of bytes in a single value for this format is given by
20062**FormatSize (or 1 << FormatSize). The number of values is the data length
2007divided by this number of bytes. It is an error if the data length is not
2008an even multiple of the format size in bytes.
2009
2010=back
2011
2012The following is a list of all currently defined MIE FormatCode values for
2013uncompressed data (add 0x04 to each value for compressed data):
2014
2015 0x00 - other data (insensitive to MIE group byte order) (1)
2016 0x01 - other 16-bit data (may be byte swapped)
2017 0x02 - other 32-bit data (may be byte swapped)
2018 0x03 - other 64-bit data (may be byte swapped)
2019 0x08 - other data (sensitive to MIE group byte order) (1)
2020 0x10 - MIE group with big-endian values (1)
2021 0x18 - MIE group with little-endian values (1)
2022 0x20 - ASCII (ISO 8859-1) string (2,3)
2023 0x28 - UTF-8 string (2,3,4)
2024 0x29 - UTF-16 string (2,3,4)
2025 0x2a - UTF-32 string (2,3,4)
2026 0x30 - ASCII (ISO 8859-1) string list (3,5)
2027 0x38 - UTF-8 string list (3,4,5)
2028 0x39 - UTF-16 string list (3,4,5)
2029 0x3a - UTF-32 string list (3,4,5)
2030 0x40 - unsigned 8-bit integer
2031 0x41 - unsigned 16-bit integer
2032 0x42 - unsigned 32-bit integer
2033 0x43 - unsigned 64-bit integer (6)
2034 0x48 - signed 8-bit integer
2035 0x49 - signed 16-bit integer
2036 0x4a - signed 32-bit integer
2037 0x4b - signed 64-bit integer (6)
2038 0x52 - unsigned 32-bit rational (16-bit numerator then denominator) (7)
2039 0x53 - unsigned 64-bit rational (32-bit numerator then denominator) (7)
2040 0x5a - signed 32-bit rational (denominator is unsigned) (7)
2041 0x5b - signed 64-bit rational (denominator is unsigned) (7)
2042 0x61 - unsigned 16-bit fixed-point (high 8 bits is integer part) (8)
2043 0x62 - unsigned 32-bit fixed-point (high 16 bits is integer part) (8)
2044 0x69 - signed 16-bit fixed-point (high 8 bits is signed integer) (8)
2045 0x6a - signed 32-bit fixed-point (high 16 bits is signed integer) (8)
2046 0x72 - 32-bit IEEE float (not recommended for portability reasons)
2047 0x73 - 64-bit IEEE double (not recommended for portability reasons) (6)
2048 0x80 - free space (value data does not contain useful information)
2049
2050Notes:
2051
2052=over 4
2053
2054=item 1.
2055
2056The byte ordering specified by the MIE group TypeModifier applies to the MIE
2057group element as well as all elements within the group. Data for all
2058FormatCodes except 0x08 (other data, sensitive to byte order) may be
2059transferred between MIE groups with different byte order by byte swapping
2060the uncompressed data according to the specified data format. The following
2061list illustrates the byte-swapping pattern, based on FormatSize, for all
2062format types except rational (FormatType 0x50).
2063
2064 FormatSize Change in Byte Sequence
2065 -------------- -----------------------------------
2066 0x00 (8 bits) 0 1 2 3 4 5 6 7 --> 0 1 2 3 4 5 6 7 (no change)
2067 0x01 (16 bits) 0 1 2 3 4 5 6 7 --> 1 0 3 2 5 4 7 6
2068 0x02 (32 bits) 0 1 2 3 4 5 6 7 --> 3 2 1 0 7 6 5 4
2069 0x03 (64 bits) 0 1 2 3 4 5 6 7 --> 7 6 5 4 3 2 1 0
2070
2071Rational values consist of two integers, so they are swapped as the next
2072lower FormatSize. For example, a 32-bit rational (FormatSize 0x02, and
2073FormatCode 0x52 or 0x5a) is swapped as two 16-bit values (ie. as if it had
2074FormatSize 0x01).
2075
2076=item 2.
2077
2078The TagName of a string element may have an 6-character suffix to indicate a
2079specific locale. (eg. "Title-en_US", or "Keywords-de_DE").
2080
2081=item 3.
2082
2083Text strings are not normally null terminated, however they may be padded
2084with one or more null characters to the end of the data block to allow
2085strings to be edited within fixed-length data blocks. Newlines in the text
2086are indicated by a single LF (0x0a) character.
2087
2088=item 4.
2089
2090UTF strings must not begin with a byte order mark (BOM) since the byte order
2091and byte size are specified by the MIE format. If a BOM is found, it should
2092be treated as a zero-width non-breaking space.
2093
2094=item 5.
2095
2096A list of text strings separated by null characters. These lists must not
2097be null padded or null terminated, since this would be interpreted as
2098additional zero-length strings. For ASCII and UTF-8 strings, the null
2099character is a single zero (0x00) byte. For UTF-16 or UTF-32 strings, the
2100null character is 2 or 4 zero bytes respectively.
2101
2102=item 6.
2103
210464-bit integers and doubles are subject to the specified byte ordering for
2105both 32-bit words and bytes within these words. For instance, the high
2106order byte is always the first byte if big-endian, and the eighth byte if
2107little-endian. This means that some swapping is always necessary for these
2108values on systems where the byte order differs from the word order (eg. some
2109ARM systems), regardless of the endian-ness of the stored values.
2110
2111=item 7.
2112
2113Rational values are treated as two separate integers. The numerator always
2114comes first regardless of the byte ordering. In a signed rational value,
2115only the numerator is signed. The denominator of all rational values is
2116unsigned (eg. a signed 64-bit rational of 0x80000000/0x80000000 evaluates to
2117-1, not +1).
2118
2119=item 8.
2120
212132-bit fixed point values are converted to floating point by treating them
2122as an integer and dividing by an appropriate value. eg)
2123
2124 16-bit fixed value = 16-bit integer value / 256.0
2125 32-bit fixed value = 32-bit integer value / 65536.0
2126
2127=back
2128
2129=head3 TagLength
2130
2131Gives the length of the TagName string. Any value between 0 and 255 is
2132valid, but the TagLength of 0 is valid only for the MIE group terminator.
2133
2134=head3 DataLength
2135
2136DataLength is an unsigned byte that gives the number of bytes in the data
2137block. A value between 0 and 252 gives the data length directly, and
2138numbers from 253 to 255 are reserved for extended DataLength codes. Codes
2139of 255, 254 and 253 indicate that the element contains an additional 2, 4 or
21408 byte unsigned integer representing the data length.
2141
2142 0-252 - length of data block
2143 255 (0xff) - use DataLength2
2144 254 (0xfe) - use DataLength4
2145 253 (0xfd) - use DataLength8
2146
2147A DataLength of zero is valid for any element except a compressed MIE group.
2148A zero DataLength for an uncompressed MIE group indicates that the group
2149length is unknown. For other elements, a zero length indicates there is no
2150associated data. A terminator element must have a DataLength of 0, 6 or 10,
2151and may not use an extended DataLength.
2152
2153=head3 TagName
2154
2155The TagName string is 0 to 255 bytes long, and is composed of the ASCII
2156characters A-Z, a-z, 0-9 and underline ('_'). Also, a dash ('-') is used to
2157separate the language/country code in the TagName of a localized text
2158string, and a units string (possibly containing other ASCII characters) may
2159be appear in brackets at the end of the TagName. The TagName string is NOT
2160null terminated. A MIE element with a tag string of zero length is reserved
2161for the group terminator.
2162
2163MIE elements are sorted alphabetically by TagName within each group.
2164Multiple elements with the same TagName are allowed, even within the same
2165group.
2166
2167TagNames should be meaningful. Case is significant. Words should be
2168lowercase with an uppercase first character, and acronyms should be all
2169upper case. The underline ("_") is provided to allow separation of two
2170acronyms or two numbers, but it shouldn't be used unless necessary. No
2171separation is necessary between an acronym and a word (eg. "ISOSetting").
2172
2173All TagNames should start with an uppercase letter. An exception to this
2174rule allows tags to begin with a digit (0-9) if they must come before other
2175tags in the sort order, or a lowercase letter (a-z) if they must come after.
2176For instance, the '0Type' element begins with a digit so it comes before,
2177and the 'data' element begins with a lowercase letter so that it comes after
2178meta information tags in the main "0MIE" group.
2179
2180Tag names for localized text strings have an 6-character suffix with the
2181following format: The first character is a dash ('-'), followed by a
21822-character lower case ISO 639-1 language code, then an underline ('_'), and
2183ending with a 2-character upper case ISO 3166-1 alpha 2 country code. (eg.
2184"-en_US", "-en_GB", "-de_DE" or "-fr_FR". Note that "GB", and not "UK" is
2185the code for Great Britain, although "UK" should be recognized for
2186compatibility reasons.) The suffix is included when sorting the tags
2187alphabetically, so the default locale (with no tag-name suffix) always comes
2188first. If the country is unknown or not applicable, a country code of "XX"
2189should be used.
2190
2191Tags with numerical values may allow units of measurement to be specified.
2192The units string is stored in brackets at the end of the tag name, and is
2193composed of zero or more ASCII characters in the range 0x21 to 0x7d,
2194excluding the bracket characters 0x28 and 0x29. (eg. "Resolution(/cm)" or
2195"SpecificHeat(J/kg.K)".) See L<Image::ExifTool::MIEUnits> for details. Unit
2196strings are not localized, and may not be used in combination with localized
2197text strings.
2198
2199Sets of tags which would require a common prefix should be added in a
2200separate MIE group instead of adding the prefix to all tag names. For
2201example, instead of these TagName's:
2202
2203 ExternalFlashType
2204 ExternalFlashSerialNumber
2205 ExternalFlashFired
2206
2207one would instead designate a separate "ExternalFlash" MIE group to contain
2208the following elements:
2209
2210 Type
2211 SerialNumber
2212 Fired
2213
2214=head3 DataLength2/4/8
2215
2216These extended DataLength fields exist only if DataLength is 255, 254 or
2217253, and are respectively 2, 4 or 8 byte unsigned integers giving the data
2218block length. One of these values must be used if the data block is larger
2219than 252 bytes, but they may be used if desired for smaller blocks too
2220(although this may add a few unnecessary bytes to the MIE element).
2221
2222=head3 DataBlock
2223
2224The data value for the MIE element. The format of the data is given by the
2225FormatCode. For MIE group elements, the data includes all contained
2226elements and the group terminator.
2227
2228=head2 MIE groups
2229
2230All MIE data elements must be contained within a group. A group begins with
2231a MIE group element, and ends with a group terminator. Groups may be nested
2232in a hierarchy to arbitrary depth.
2233
2234A MIE group element is identified by a format code of 0x10 (big endian byte
2235ordering) or 0x18 (little endian). The group terminator is distinguished by
2236a zero TagLength (it is the only element allowed to have a zero TagLength),
2237and has a FormatCode of 0x00.
2238
2239The MIE group element is permitted to have a zero DataLength only if the
2240data is uncompressed. This special value indicates that the group length is
2241unknown (otherwise the minimum value for DataLength is 4, corresponding the
2242the minimum group size which includes a terminator of at least 4 bytes). If
2243DataLength is zero, all elements in the group must be parsed until the group
2244terminator is found. If non-zero, DataLength includes the length of all
2245elements contained within the group, including the group terminator. Use of
2246a non-zero DataLength is encouraged because it allows readers quickly skip
2247over entire MIE groups. For compressed groups DataLength must be non-zero,
2248and is the length of the compressed group data (which includes the
2249compressed group terminator).
2250
2251=head3 Group Terminator
2252
2253The group terminator has a FormatCode and TagLength of zero. The terminator
2254DataLength must be 0, 6 or 10 bytes, and extended DataLength codes may not
2255be used. With a zero DataLength, the byte sequence for a terminator is "7e
225600 00 00" (hex). With a DataLength of 6 or 10 bytes, the terminator data
2257block contains information about the length and byte ordering of the
2258preceding group. This additional information is recommended for file-level
2259groups, and is used in multi-document MIE files and MIE trailers to allow
2260the file to be scanned backwards from the end. (This may also allow some
2261documents to be recovered if part of the file is corrupted.) The structure
2262of this optional terminator data block is as follows:
2263
2264 4 or 8 bytes GroupLength (unsigned integer)
2265 1 byte ByteOrder (0x10 or 0x18, same as MIE group)
2266 1 byte GroupLengthSize (0x04 or 0x08)
2267
2268The ByteOrder and GroupLengthSize values give the byte ordering and size of
2269the GroupLength integer. The GroupLength value is the total length of the
2270entire MIE group ending with this terminator, including the opening MIE
2271group element and the terminator itself.
2272
2273=head3 File-level MIE groups
2274
2275File-level MIE groups may NOT be compressed.
2276
2277All elements in a MIE file are contained within a special group with a
2278TagName of "0MIE". The purpose of the "OMIE" group is to provide a unique
2279signature at the start of the file, and to encapsulate information allowing
2280files to be easily combined. The "0MIE" group must be terminated like any
2281other group, but it is recommended that the terminator of a file-level group
2282include the optional data block (defined above) to provide information about
2283the group length and byte order.
2284
2285It is valid to have more than one "0MIE" group at the file level, allowing
2286multiple documents in a single MIE file. Furthermore, the MIE structure
2287enables multi-document files to be generated by simply concatenating two or
2288more MIE files.
2289
2290=head2 Scanning Backwards through a MIE File
2291
2292The steps below give an algorithm to quickly locate the last document in a
2293MIE file:
2294
2295=over 4
2296
2297=item 1.
2298
2299Read the last 10 bytes of the file. (Note that a valid MIE file may be as
2300short as 12 bytes long, but a file this length contains only an an empty MIE
2301group.)
2302
2303=item 2.
2304
2305If the last byte of the file is zero, then it is not possible to scan
2306backward through the file, so the file must be scanned from the beginning.
2307Otherwise, proceed to the next step.
2308
2309=item 3.
2310
2311If the last byte is 4 or 8, the terminator contains information about the
2312byte ordering and length of the group. Otherwise, stop here because this
2313isn't a valid MIE file.
2314
2315=item 4.
2316
2317The next-to-last byte must be either 0x10 indicating big-endian byte
2318ordering or 0x18 for little-endian ordering, otherwise this isn't a valid
2319MIE file.
2320
2321=item 5.
2322
2323The value of the preceding 4 or 8 bytes gives the length of the complete
2324file-level MIE group (GroupLength). This length includes both the leading
2325MIE group element and the terminator element itself. The value is an
2326unsigned integer with a byte length given in step 3), and a byte order from
2327step 4). From the current file position (at the end of the data read in
2328step 1), seek backward by this number of bytes to find the start of the MIE
2329group element for this document.
2330
2331=back
2332
2333This algorithm may be repeated again beginning at this point in the file to
2334locate the next-to-last document, etc.
2335
2336The table below lists all 5 valid patterns for the last 14 bytes of a
2337file-level MIE group, with all numbers in hex. The comments indicate the
2338length and byte ordering of GroupLength (xx) if available:
2339
2340 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 7e 00 00 00 - (no GroupLength)
2341 ?? ?? ?? ?? 7e 00 00 06 xx xx xx xx 10 04 - 4 bytes, big endian
2342 ?? ?? ?? ?? 7e 00 00 06 xx xx xx xx 18 04 - 4 bytes, little endian
2343 7e 00 00 0a xx xx xx xx xx xx xx xx 10 08 - 8 bytes, big endian
2344 7e 00 00 0a xx xx xx xx xx xx xx xx 18 08 - 8 bytes, little endian
2345
2346=head2 Trailer Signature
2347
2348The MIE format may be used for trailer information appended to other types
2349of files. When this is done, a signature must appear at the end of the main
2350MIE group to uniquely identify the MIE format trailer. To achieve this, a
2351"zmie" trailer signature is written as the last element in the main "0MIE"
2352group. This element has a FormatCode of 0, a TagLength of 4, a DataLength
2353of 0, and a TagName of "zmie". With this signature, the hex byte sequence
2354"7e 00 04 00 7a 6d 69 65" appears immediately before the final group
2355terminator, and the last 22 bytes of the trailer correspond to one of the
2356following 4 patterns (where the trailer length is given by "xx", as above):
2357
2358 ?? ?? ?? ?? 7e 00 04 00 7a 6d 69 65 7e 00 00 06 xx xx xx xx 10 04
2359 ?? ?? ?? ?? 7e 00 04 00 7a 6d 69 65 7e 00 00 06 xx xx xx xx 18 04
2360 7e 00 04 00 7a 6d 69 65 7e 00 00 0a xx xx xx xx xx xx xx xx 10 08
2361 7e 00 04 00 7a 6d 69 65 7e 00 00 0a xx xx xx xx xx xx xx xx 18 08
2362
2363Note that the zero-DataLength terminator may not be used here because the
2364trailer length must be known for seeking backwards from the end of the file.
2365
2366Multiple trailers may be appended to the same file using this technique.
2367
2368=head2 MIE Data Values
2369
2370MIE data values for a given tag are usually not restricted to a specific
2371FormatCode. Any value may be represented in any appropriate format,
2372including numbers represented in string (ASCII or UTF) form.
2373
2374It is preferred that closely related values with the same format are written
2375to a single tag instead of using multiple tags. This improves localization
2376of like values and decreases MIE element overhead. For instance, instead of
2377separate ImageWidth and ImageHeight tags, a single ImageSize tag is defined.
2378
2379Tags which may take on a discrete set of values should have meaningful
2380values if possible. This improves the extensibility of the format and
2381allows a more reasonable interpretation of unrecognized values.
2382
2383=head3 Numerical Representation
2384
2385Integer and floating point numbers may be represented in binary or string
2386form. In string form, integers are a series of digits with an optional
2387leading sign (eg. "[+|-]DDDDDD"), and multiple values are separated by a
2388single space character (eg. "23 128 -32"). Floating point numbers are
2389similar but may also contain a decimal point and/or a signed exponent with a
2390leading 'e' character (eg. "[+|-]DD[.DDDDDD][e(+|-)EEE]"). The string "inf"
2391is used to represent infinity. One advantage of numerical strings is that
2392they can have an arbitrarily high precision because the possible number of
2393significant digits is virtually unlimited.
2394
2395Note that numerical values may have associated units of measurement which
2396are specified in the L</TagName> string.
2397
2398=head3 Date/Time Format
2399
2400All MIE dates are strings in the form "YYYY:mm:dd HH:MM:SS.ss+HH:MM". The
2401fractional seconds (".ss") are optional, and if included may contain any
2402number of significant digits (unlike all other fields which are a fixed
2403number of digits and must be padded with leading zeros if necessary). The
2404timezone ("+HH:MM" or "-HH:MM") is recommended but not required. If not
2405given, the local system timezone is assumed.
2406
2407=head2 MIME Type
2408
2409The basic MIME type for a MIE file is "application/x-mie", however the
2410specific MIME type depends on the type of subfile, and is obtained by adding
2411"x-mie-" to the MIME type of the subfile. For example, with a subfile of
2412type "image/jpeg", the MIE file MIME type is "image/x-mie-jpeg". But note
2413that the "x-" is not duplicated if the subfile MIME type already starts with
2414"x-". So a subfile with MIME type "image/x-raw" is contained within a MIE
2415file of type "image/x-mie-raw", not "image/x-mie-x-raw". In the case of
2416multiple documents in a MIE file, the MIME type is taken from the first
2417document. Regardless of the subfile type, all MIE-format files should have
2418a filename extension of ".MIE".
2419
2420=head2 Levels of Support
2421
2422Basic MIE reader/writer applications may choose not to provide support for
2423some advanced features of the MIE format. Features which may not be
2424supported by all software are:
2425
2426=over 4
2427
2428=item Compression
2429
2430Software not supporting compression must ignore compressed elements and
2431groups, but should be able to process the remaining information.
2432
2433=item Large data lengths
2434
2435Some software may limit the maximum size of a MIE group or element.
2436Historically, a limit of 2GB may be imposed by some systems. However,
24378-byte data lengths should be supported by all applications provided the
2438value doesn't exceed the system limit. (eg. For systems with a 2GB limit,
24398-byte data lengths should be supported if the upper 17 bits are all zero.)
2440If a data length above the system limit is encountered, it may be necessary
2441for the application to stop processing if it can not seek to the next
2442element in the file.
2443
2444=back
2445
2446=head1 EXAMPLES
2447
2448This section gives examples for working with MIE information using ExifTool.
2449
2450=head2 Encapsulating Information with Data in a MIE File
2451
2452The following command encapsulates any file recognized by ExifTool inside a
2453MIE file, and initializes MIE tags from information within the file:
2454
2455 exiftool -o new.mie -tagsfromfile FILE '-mie:all<all' \
2456 '-subfilename<filename' '-subfiletype<filetype' \
2457 '-subfilemimetype<mimetype' '-subfiledata<=FILE'
2458
2459where C<FILE> is the name of the file.
2460
2461For unrecognized files, this command may be used:
2462
2463 exiftool -o new.mie -subfilename=FILE -subfiletype=TYPE \
2464 -subfilemimetype=MIME '-subfiledata<=FILE'
2465
2466where C<TYPE> and C<MIME> represent the source file type and MIME type
2467respectively.
2468
2469=head2 Adding a MIE Trailer to a File
2470
2471The MIE format may also be used to store information in a trailer appended
2472to another type of file. Beware that trailers may not be compatible with
2473all file formats, but JPEG and TIFF are two formats where additional trailer
2474information doesn't create any problems for normal parsing of the file.
2475Also note that this technique has the disadvantage that trailer information
2476is commonly lost if the file is subsequently edited by other software.
2477
2478Creating a MIE trailer with ExifTool is a two-step process since ExifTool
2479can't currently be used to add a MIE trailer directly. The example below
2480illustrates the steps for adding a MIE trailer with a small preview image
2481(C<small.jpg>) to a destination JPEG image (C<dst.jpg>).
2482
2483Step 1) Create a MIE file with a TrailerSignature containing the desired
2484information:
2485
2486 exiftool -o new.mie -trailersignature=1 -tagsfromfile small.jpg \
2487 '-previewimagetype<filetype' '-previewimagesize<imagesize' \
2488 '-previewimagename<filename' '-previewimage<=small.jpg'
2489
2490Step 2) Append the MIE information to another file. In Unix, this can be
2491done with the 'cat' command:
2492
2493 cat new.mie >> dst.jpg
2494
2495Once added, ExifTool may be used to edit or delete a MIE trailer in a JPEG
2496or TIFF image.
2497
2498=head2 Multiple MIE Documents in a Single File
2499
2500The MIE specification allows multiple MIE documents (or trailers) to exist
2501in a single file. A file like this may be created by simply concatenating
2502MIE documents. ExifTool may be used to access information in a specific
2503document by adding a copy number to the MIE group name. For example:
2504
2505 # write the Author tag in the second MIE document
2506 exiftool -mie2:author=phil test.mie
2507
2508 # delete the first MIE document from a file
2509 exiftool -mie1:all= test.mie
2510
2511=head2 Units of Measurement
2512
2513Some MIE tags allow values to be specified in different units of
2514measurement. In the MIE file format these units are combined with the tag
2515name, but when using ExifTool they are specified in brackets after the
2516value:
2517
2518 exiftool -mie:gpsaltitude='7500(ft)' test.mie
2519
2520If no units are provided, the default units are written.
2521
2522=head2 Localized Text
2523
2524Localized text values are accessed by adding a language/country code to the
2525tag name. For example:
2526
2527 exiftool -comment-en_us='this is a comment' test.mie
2528
2529=head1 REVISIONS
2530
2531 2010-04-05 - Fixed "Format Size" Note 7 to give the correct number of bits
2532 in the example rational value
2533 2007-01-21 - Specified LF character (0x0a) for text newline sequence
2534 2007-01-19 - Specified ISO 8859-1 character set for extended ASCII codes
2535 2007-01-01 - Improved wording of Step 5 for scanning backwards in MIE file
2536 2006-12-30 - Added EXAMPLES section and note about UTF BOM
2537 2006-12-20 - MIE 1.1: Changed meaning of TypeModifier bit (0x08) for
2538 unknown data (FormatType 0x00), and documented byte swapping
2539 2006-12-14 - MIE 1.0: Added Data Values and Numerical Representations
2540 sections, and added ability to specify units in tag names
2541 2006-11-09 - Added Levels of Support section
2542 2006-11-03 - Added Trailer Signature
2543 2005-11-18 - Original specification created
2544
2545=head1 AUTHOR
2546
2547Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com)
2548
2549This library is free software; you can redistribute it and/or modify it
2550under the same terms as Perl itself. The MIE format itself is also
2551copyright Phil Harvey, and is covered by the same free-use license.
2552
2553=head1 REFERENCES
2554
2555=over 4
2556
2557=item L<https://exiftool.org/MIE1.1-20070121.pdf>
2558
2559=back
2560
2561=head1 SEE ALSO
2562
2563L<Image::ExifTool::TagNames/MIE Tags>, L<Image::ExifTool::MIEUnits>,
2564L<Image::ExifTool(3pm)|Image::ExifTool>
2565
2566=cut
2567
Note: See TracBrowser for help on using the repository browser.