File Coverage

blib/lib/Image/ExifTool/Microsoft.pm
Criterion Covered Total %
statement 116 187 62.0
branch 44 116 37.9
condition 7 35 20.0
subroutine 10 10 100.0
pod 0 6 0.0
total 177 354 50.0


line stmt bran cond sub pod time code
1             #------------------------------------------------------------------------------
2             # File: Microsoft.pm
3             #
4             # Description: Definitions for custom Microsoft tags
5             #
6             # Revisions: 2010/10/01 - P. Harvey Created
7             # 2011/10/05 - PH Added ProcessXtra()
8             # 2021/02/23 - PH Added abiltity to write Xtra tags
9             #
10             # References: 1) http://research.microsoft.com/en-us/um/redmond/groups/ivm/hdview/hdmetadataspec.htm
11             #------------------------------------------------------------------------------
12              
13             package Image::ExifTool::Microsoft;
14              
15 11     11   98 use strict;
  11         30  
  11         453  
16 11     11   69 use vars qw($VERSION);
  11         32  
  11         586  
17 11     11   85 use Image::ExifTool qw(:DataAccess :Utils);
  11         31  
  11         2834  
18 11     11   103 use Image::ExifTool::XMP;
  11         33  
  11         44635  
19              
20             $VERSION = '1.23';
21              
22             sub ProcessXtra($$$);
23             sub WriteXtra($$$);
24             sub CheckXtra($$$);
25              
26             # tags written by Microsoft HDView (ref 1)
27             %Image::ExifTool::Microsoft::Stitch = (
28             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
29             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
30             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
31             WRITABLE => 1,
32             FORMAT => 'float',
33             FIRST_ENTRY => 0,
34             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
35             NOTES => q{
36             Information found in the Microsoft custom EXIF tag 0x4748, as written by
37             Windows Live Photo Gallery.
38             },
39             0 => {
40             Name => 'PanoramicStitchVersion',
41             Format => 'int32u',
42             },
43             1 => {
44             Name => 'PanoramicStitchCameraMotion',
45             Format => 'int32u',
46             PrintConv => {
47             2 => 'Rigid Scale',
48             3 => 'Affine',
49             4 => '3D Rotation',
50             5 => 'Homography',
51             },
52             },
53             2 => {
54             Name => 'PanoramicStitchMapType',
55             Format => 'int32u',
56             PrintConv => {
57             0 => 'Perspective',
58             1 => 'Horizontal Cylindrical',
59             2 => 'Horizontal Spherical',
60             257 => 'Vertical Cylindrical',
61             258 => 'Vertical Spherical',
62             },
63             },
64             3 => 'PanoramicStitchTheta0',
65             4 => 'PanoramicStitchTheta1',
66             5 => 'PanoramicStitchPhi0',
67             6 => 'PanoramicStitchPhi1',
68             );
69              
70             # Microsoft Photo schema properties (MicrosoftPhoto) (ref PH)
71             %Image::ExifTool::Microsoft::XMP = (
72             %Image::ExifTool::XMP::xmpTableDefaults,
73             GROUPS => { 0 => 'XMP', 1 => 'XMP-microsoft', 2 => 'Image' },
74             NAMESPACE => 'MicrosoftPhoto',
75             TABLE_DESC => 'XMP Microsoft',
76             VARS => { NO_ID => 1 },
77             NOTES => q{
78             Microsoft Photo 1.0 schema XMP tags. This is likely not a complete list,
79             but represents tags which have been observed in sample images. The actual
80             namespace prefix is "MicrosoftPhoto", but ExifTool shortens this in the
81             family 1 group name.
82             },
83             CameraSerialNumber => { },
84             DateAcquired => { Groups => { 2 => 'Time' }, %Image::ExifTool::XMP::dateTimeInfo },
85             FlashManufacturer => { },
86             FlashModel => { },
87             LastKeywordIPTC => { List => 'Bag' },
88             LastKeywordXMP => { List => 'Bag' },
89             LensManufacturer => { },
90             LensModel => { Avoid => 1 },
91             Rating => {
92             Name => 'RatingPercent',
93             Notes => q{
94             XMP-xmp:Rating values of 1,2,3,4 and 5 stars correspond to RatingPercent
95             values of 1,25,50,75 and 99 respectively
96             },
97             },
98             CreatorAppId => { Name => 'CreatorAppID' },
99             CreatorOpenWithUIOptions => { },
100             ItemSubType => { },
101             );
102              
103             # Microsoft Photo 1.1 schema properties (MP1 - written as 'prefix0' by MSPhoto) (ref PH)
104             %Image::ExifTool::Microsoft::MP1 = (
105             %Image::ExifTool::XMP::xmpTableDefaults,
106             GROUPS => { 0 => 'XMP', 1 => 'XMP-MP1', 2 => 'Image' },
107             NAMESPACE => 'MP1',
108             TABLE_DESC => 'XMP Microsoft Photo',
109             VARS => { NO_ID => 1 },
110             NOTES => q{
111             Microsoft Photo 1.1 schema XMP tags which have been observed.
112             },
113             PanoramicStitchCameraMotion => {
114             PrintConv => {
115             'RigidScale' => 'Rigid Scale',
116             'Affine' => 'Affine',
117             '3DRotation' => '3D Rotation',
118             'Homography' => 'Homography',
119             },
120             },
121             PanoramicStitchMapType => {
122             PrintConv => {
123             'Perspective' => 'Perspective',
124             'Horizontal-Cylindrical' => 'Horizontal Cylindrical',
125             'Horizontal-Spherical' => 'Horizontal Spherical',
126             'Vertical-Cylindrical' => 'Vertical Cylindrical',
127             'Vertical-Spherical' => 'Vertical Spherical',
128             },
129             },
130             PanoramicStitchPhi0 => { Writable => 'real' },
131             PanoramicStitchPhi1 => { Writable => 'real' },
132             PanoramicStitchTheta0 => { Writable => 'real' },
133             PanoramicStitchTheta1 => { Writable => 'real' },
134             WhiteBalance0 => { Writable => 'real' },
135             WhiteBalance1 => { Writable => 'real' },
136             WhiteBalance2 => { Writable => 'real' },
137             Brightness => { Avoid => 1 },
138             Contrast => { Avoid => 1 },
139             CameraModelID => { Avoid => 1 },
140             ExposureCompensation => { Avoid => 1 },
141             PipelineVersion => { },
142             StreamType => { },
143             );
144              
145             # Microsoft Photo 1.2 schema properties (MP) (ref PH)
146             # (also ref http://msdn.microsoft.com/en-us/library/windows/desktop/ee719905(v=vs.85).aspx)
147             my %sRegions = (
148             STRUCT_NAME => 'Microsoft Regions',
149             NAMESPACE => 'MPReg',
150             NOTES => q{
151             Note that PersonLiveIdCID element is called PersonLiveCID according to the
152             Microsoft specification, but in practice their software actually writes
153             PersonLiveIdCID, so ExifTool uses this too.
154             },
155             Rectangle => { },
156             PersonDisplayName => { },
157             PersonEmailDigest => { },
158             PersonLiveIdCID => { }, # (see https://exiftool.org/forum/index.php?topic=4274.msg20368#msg20368)
159             PersonSourceID => { },
160             );
161             %Image::ExifTool::Microsoft::MP = (
162             %Image::ExifTool::XMP::xmpTableDefaults,
163             GROUPS => { 0 => 'XMP', 1 => 'XMP-MP', 2 => 'Image' },
164             NAMESPACE => 'MP',
165             TABLE_DESC => 'XMP Microsoft Photo',
166             VARS => { NO_ID => 1 },
167             NOTES => q{
168             Microsoft Photo 1.2 schema XMP tags which have been observed.
169             },
170             RegionInfo => {
171             Name => 'RegionInfoMP',
172             Struct => {
173             STRUCT_NAME => 'Microsoft RegionInfo',
174             NAMESPACE => 'MPRI',
175             Regions => { Struct => \%sRegions, List => 'Bag' },
176             DateRegionsValid => {
177             Writable => 'date',
178             Shift => 'Time',
179             Groups => { 2 => 'Time'},
180             PrintConv => '$self->ConvertDateTime($val)',
181             PrintConvInv => '$self->InverseDateTime($val,undef,1)',
182             },
183             },
184             },
185             # remove "MP" from tag name (was added only to avoid conflict with XMP-mwg-rs:RegionInfo)
186             RegionInfoRegions => { Flat => 1, Name => 'RegionInfoRegions' },
187             RegionInfoDateRegionsValid => { Flat => 1, Name => 'RegionInfoDateRegionsValid' },
188             # shorten flattened Regions tag names to make them easier to use
189             RegionInfoRegionsRectangle => { Flat => 1, Name => 'RegionRectangle' },
190             RegionInfoRegionsPersonDisplayName => { Flat => 1, Name => 'RegionPersonDisplayName' },
191             RegionInfoRegionsPersonEmailDigest => { Flat => 1, Name => 'RegionPersonEmailDigest' },
192             RegionInfoRegionsPersonLiveIdCID => { Flat => 1, Name => 'RegionPersonLiveIdCID' },
193             RegionInfoRegionsPersonSourceID => { Flat => 1, Name => 'RegionPersonSourceID' },
194             );
195              
196             # Xtra tags written in MP4 files written by Microsoft Windows Media Player
197             # (ref http://msdn.microsoft.com/en-us/library/windows/desktop/dd562330(v=VS.85).aspx)
198             # Note: These tags are closely related to tags in Image::ExifTool::ASF::ExtendedDescr
199             # and Image::ExifTool::WTV::Metadata
200             %Image::ExifTool::Microsoft::Xtra = (
201             PROCESS_PROC => \&ProcessXtra,
202             WRITE_PROC => \&WriteXtra,
203             CHECK_PROC => \&CheckXtra,
204             WRITE_GROUP => 'Microsoft',
205             AVOID => 1,
206             GROUPS => { 0 => 'QuickTime', 2 => 'Video' },
207             VARS => { NO_ID => 1 },
208             NOTES => q{
209             Tags found in the Microsoft "Xtra" atom of QuickTime videos. Tag ID's are
210             not shown because some are unruly GUID's. Currently most of these tags are
211             not writable because the Microsoft documentation is poor and samples were
212             not available, but more tags may be made writable in the future if samples
213             are provided. Note that writable tags in this table are are flagged to
214             "Avoid", which means that other more common tags will be written instead if
215             possible unless the Microsoft group is specified explicitly.
216             },
217             Abstract => { },
218             AcquisitionTime => { Groups => { 2 => 'Time' } },
219             AcquisitionTimeDay => { Groups => { 2 => 'Time' } },
220             AcquisitionTimeMonth => { Groups => { 2 => 'Time' } },
221             AcquisitionTimeYear => { Groups => { 2 => 'Time' } },
222             AcquisitionTimeYearMonth => { Groups => { 2 => 'Time' } },
223             AcquisitionTimeYearMonthDay => { Groups => { 2 => 'Time' } },
224             AlbumArtistSortOrder => { },
225             AlbumID => { },
226             AlbumIDAlbumArtist => { },
227             AlbumTitleSortOrder => { },
228             AlternateSourceURL => { },
229             AudioBitrate => { },
230             AudioFormat => { },
231             Author => { Groups => { 2 => 'Author' } },
232             AuthorSortOrder => { },
233             AverageLevel => { },
234             Bitrate => { },
235             BuyNow => { },
236             BuyTickets => { },
237             CallLetters => { },
238             CameraManufacturer => { },
239             CameraModel => { },
240             CDTrackEnabled => { },
241             Channels => { },
242             chapterNum => { },
243             Comment => { },
244             ContentDistributorDuration => { },
245             Copyright => { Groups => { 2 => 'Author' } },
246             Count => { },
247             CurrentBitrate => { },
248             Description => { },
249             DisplayArtist => { },
250             DLNAServerUDN => { },
251             DLNASourceURI => { },
252             DRMKeyID => { },
253             DRMIndividualizedVersion => { },
254             DTCPIPHost => { },
255             DTCPIPPort => { },
256             Duration => { },
257             DVDID => { },
258             Event => { },
259             FileSize => { },
260             FileType => { },
261             FourCC => { },
262             FormatTag => { },
263             FrameRate => { },
264             Frequency => { },
265             IsNetworkFeed => { },
266             Is_Protected => 'IsProtected',
267             IsVBR => { },
268             LeadPerformer => { },
269             LibraryID => { },
270             LibraryName => { },
271             Location => { },
272             MediaContentTypes => { },
273             MediaType => { },
274             ModifiedBy => { },
275             MoreInfo => { },
276             PartOfSet => { },
277             PeakValue => { },
278             PixelAspectRatioX => { },
279             PixelAspectRatioY => { },
280             PlaylistIndex => { },
281             Provider => { },
282             ProviderLogoURL => { },
283             ProviderURL => { },
284             RadioBand => { },
285             RadioFormat => { },
286             RatingOrg => { },
287             RecordingTime => { Groups => { 2 => 'Time' } },
288             RecordingTimeDay => { Groups => { 2 => 'Time' } },
289             RecordingTimeMonth => { Groups => { 2 => 'Time' } },
290             RecordingTimeYear => { Groups => { 2 => 'Time' } },
291             RecordingTimeYearMonth => { Groups => { 2 => 'Time' } },
292             RecordingTimeYearMonthDay => { Groups => { 2 => 'Time' } },
293             ReleaseDate => { Groups => { 2 => 'Time' } },
294             ReleaseDateDay => { Groups => { 2 => 'Time' } },
295             ReleaseDateMonth => { Groups => { 2 => 'Time' } },
296             ReleaseDateYear => { Groups => { 2 => 'Time' } },
297             ReleaseDateYearMonth => { Groups => { 2 => 'Time' } },
298             ReleaseDateYearMonthDay => { Groups => { 2 => 'Time' } },
299             RequestState => { },
300             ShadowFilePath => { },
301             SourceURL => { },
302             Subject => { },
303             SyncState => { },
304             Sync01 => { },
305             Sync02 => { },
306             Sync03 => { },
307             Sync04 => { },
308             Sync05 => { },
309             Sync06 => { },
310             Sync07 => { },
311             Sync08 => { },
312             Sync09 => { },
313             Sync10 => { },
314             Sync11 => { },
315             Sync12 => { },
316             Sync13 => { },
317             Sync14 => { },
318             Sync15 => { },
319             Sync16 => { },
320             SyncOnly => { },
321             Temporary => { },
322             Title => { },
323             titleNum => { },
324             TitleSortOrder => { },
325             TotalDuration => { },
326             TrackingID => { },
327             UserCustom1 => { },
328             UserCustom2 => { },
329             UserEffectiveRating => { },
330             UserLastPlayedTime => { },
331             UserPlayCount => { },
332             UserPlaycountAfternoon => { },
333             UserPlaycountEvening => { },
334             UserPlaycountMorning => { },
335             UserPlaycountNight => { },
336             UserPlaycountWeekday => { },
337             UserPlaycountWeekend => { },
338             UserRating => { },
339             UserServiceRating => { },
340             VideoBitrate => { },
341             VideoFormat => { },
342             'WM/AlbumArtist' => { Name => 'AlbumArtist', Writable => 'Unicode' }, # (NC)
343             'WM/AlbumCoverURL' => { Name => 'AlbumCoverURL', Writable => 'Unicode' }, # (NC)
344             'WM/AlbumTitle' => { Name => 'AlbumTitle', Writable => 'Unicode' }, # (NC)
345             'WM/BeatsPerMinute' => 'BeatsPerMinute',
346             'WM/Category' => { Name => 'Category', Writable => 'Unicode', List => 1 },
347             'WM/Composer' => { Name => 'Composer', Writable => 'Unicode' }, # (NC)
348             'WM/Conductor' => { Name => 'Conductor', Writable => 'Unicode', List => 1 },
349             'WM/ContentDistributor' => { Name => 'ContentDistributor', Writable => 'Unicode' },
350             'WM/ContentDistributorType' => 'ContentDistributorType',
351             'WM/ContentGroupDescription'=> 'ContentGroupDescription',
352             'WM/Director' => { Name => 'Director', Writable => 'Unicode', List => 1 },
353             'WM/EncodingTime' => {
354             Name => 'EncodingTime',
355             Groups => { 2 => 'Time' },
356             Shift => 'Time',
357             Writable => 'date',
358             PrintConv => '$self->ConvertDateTime($val)',
359             PrintConvInv => '$self->InverseDateTime($val)',
360             },
361             'WM/Genre' => 'Genre',
362             'WM/GenreID' => 'GenreID',
363             'WM/InitialKey' => { Name => 'InitialKey', Writable => 'Unicode' },
364             'WM/Language' => 'Language',
365             'WM/Lyrics' => 'Lyrics',
366             'WM/MCDI' => 'MCDI',
367             'WM/MediaClassPrimaryID' => {
368             Name => 'MediaClassPrimaryID',
369             Writable => 'GUID',
370             PrintConv => { #http://msdn.microsoft.com/en-us/library/windows/desktop/dd757960(v=vs.85).aspx
371             'D1607DBC-E323-4BE2-86A1-48A42A28441E' => 'Music',
372             'DB9830BD-3AB3-4FAB-8A37-1A995F7FF74B' => 'Video',
373             '01CD0F29-DA4E-4157-897B-6275D50C4F11' => 'Audio (not music)',
374             'FCF24A76-9A57-4036-990D-E35DD8B244E1' => 'Other (not audio or video)',
375             },
376             },
377             'WM/MediaClassSecondaryID' => {
378             Name => 'MediaClassSecondaryID',
379             Writable => 'GUID',
380             PrintConv => { #http://msdn.microsoft.com/en-us/library/windows/desktop/dd757960(v=vs.85).aspx
381             'E0236BEB-C281-4EDE-A36D-7AF76A3D45B5' => 'Audio Book',
382             '3A172A13-2BD9-4831-835B-114F6A95943F' => 'Spoken Word',
383             '6677DB9B-E5A0-4063-A1AD-ACEB52840CF1' => 'Audio News',
384             '1B824A67-3F80-4E3E-9CDE-F7361B0F5F1B' => 'Talk Show',
385             '1FE2E091-4E1E-40CE-B22D-348C732E0B10' => 'Video News',
386             'D6DE1D88-C77C-4593-BFBC-9C61E8C373E3' => 'Web-based Video',
387             '00033368-5009-4AC3-A820-5D2D09A4E7C1' => 'Sound Clip from Game',
388             'F24FF731-96FC-4D0F-A2F5-5A3483682B1A' => 'Song from Game',
389             'E3E689E2-BA8C-4330-96DF-A0EEEFFA6876' => 'Music Video',
390             'B76628F4-300D-443D-9CB5-01C285109DAF' => 'Home Movie',
391             'A9B87FC9-BD47-4BF0-AC4F-655B89F7D868' => 'Feature Film',
392             'BA7F258A-62F7-47A9-B21F-4651C42A000E' => 'TV Show',
393             '44051B5B-B103-4B5C-92AB-93060A9463F0' => 'Corporate Video',
394             '0B710218-8C0C-475E-AF73-4C41C0C8F8CE' => 'Home Video from Pictures',
395             '00000000-0000-0000-0000-000000000000' => 'Unknown Content', #PH
396             },
397             },
398             'WM/MediaOriginalBroadcastDateTime' => {
399             Name => 'MediaOriginalBroadcastDateTime',
400             Groups => { 2 => 'Time' },
401             PrintConv => '$self->ConvertDateTime($val)',
402             },
403             'WM/MediaOriginalChannel' => 'MediaOriginalChannel',
404             'WM/MediaStationName' => 'MediaStationName',
405             'WM/Mood' => { Name => 'Mood', Writable => 'Unicode' },
406             'WM/OriginalAlbumTitle' => { Name => 'OriginalAlbumTitle', Writable => 'Unicode' }, # (NC)
407             'WM/OriginalArtist' => { Name => 'OriginalArtist', Writable => 'Unicode' }, # (NC)
408             'WM/OriginalLyricist' => { Name => 'OriginalLyricist', Writable => 'Unicode' }, # (NC)
409             'WM/ParentalRating' => { Name => 'ParentalRating', Writable => 'Unicode' },
410             'WM/PartOfSet' => 'PartOfSet',
411             'WM/Period' => { Name => 'Period', Writable => 'Unicode' },
412             'WM/Producer' => { Name => 'Producer', Writable => 'Unicode', List => 1 },
413             'WM/ProtectionType' => 'ProtectionType',
414             'WM/Provider' => { Name => 'Provider', Writable => 'Unicode' }, # (NC)
415             'WM/ProviderRating' => 'ProviderRating',
416             'WM/ProviderStyle' => 'ProviderStyle',
417             'WM/Publisher' => { Name => 'Publisher', Writable => 'Unicode' }, # (multiple entries separated by semicolon)
418             'WM/SharedUserRating' => { Name => 'SharedUserRating', Writable => 'int64u' },
419             'WM/SubscriptionContentID' => 'SubscriptionContentID',
420             'WM/SubTitle' => { Name => 'Subtitle', Writable => 'Unicode' },
421             'WM/SubTitleDescription' => 'SubtitleDescription',
422             'WM/TrackNumber' => 'TrackNumber',
423             'WM/UniqueFileIdentifier' => 'UniqueFileIdentifier',
424             'WM/VideoFrameRate' => 'VideoFrameRate',
425             'WM/VideoHeight' => 'VideoHeight',
426             'WM/VideoWidth' => 'VideoWidth',
427             'WM/WMCollectionGroupID' => 'WMCollectionGroupID',
428             'WM/WMCollectionID' => 'WMCollectionID',
429             'WM/WMContentID' => 'WMContentID',
430             'WM/WMShadowFileSourceDRMType' => 'WMShadowFileSourceDRMType',
431             'WM/WMShadowFileSourceFileType' => 'WMShadowFileSourceFileType',
432             'WM/Writer' => { Name => 'Writer', Groups => { 2 => 'Author' }, Writable => 'Unicode' }, # (NC)
433             'WM/Year' => { Name => 'Year', Groups => { 2 => 'Time' } },
434             'WM/PromotionURL' => { Name => 'PromotionURL',Writable => 'Unicode' },
435             'WM/AuthorURL' => { Name => 'AuthorURL', Groups => { 2 => 'Author' }, Writable => 'Unicode' },
436             'WM/EncodedBy', => { Name => 'EncodedBy', Writable => 'Unicode' },
437              
438             # I can't find documentation for the following tags in videos,
439             # but the tag ID's correspond to Microsoft property GUID+ID's
440             # References:
441             # http://msdn.microsoft.com/en-us/library/cc251929%28v=prot.10%29.aspx
442             # http://multi-rename-script.googlecode.com/svn-history/r4/trunk/plugins/ShellDetails/ShellDetails.ini
443             # I have observed only 1 so far:
444             '{2CBAA8F5-D81F-47CA-B17A-F8D822300131} 100' => {
445             Name => 'DateAcquired', # (seems to be when videos are downloaded from the camera)
446             Groups => { 2 => 'Time' },
447             Shift => 'Time',
448             Writable => 'vt_filetime',
449             PrintConv => '$self->ConvertDateTime($val)',
450             PrintConvInv => '$self->InverseDateTime($val,undef)',
451             },
452             # the following have not yet been observed...
453             '{B725F130-47EF-101A-A5F1-02608C9EEBAC} 10' => 'Name',
454             '{B725F130-47EF-101A-A5F1-02608C9EEBAC} 12' => 'Size',
455             '{B725F130-47EF-101A-A5F1-02608C9EEBAC} 4' => 'Type',
456             '{B725F130-47EF-101A-A5F1-02608C9EEBAC} 14' => {
457             Name => 'DateModified',
458             Groups => { 2 => 'Time' },
459             PrintConv => '$self->ConvertDateTime($val)',
460             },
461             '{B725F130-47EF-101A-A5F1-02608C9EEBAC} 15' => {
462             Name => 'DateCreated',
463             Groups => { 2 => 'Time' },
464             PrintConv => '$self->ConvertDateTime($val)',
465             },
466             '{B725F130-47EF-101A-A5F1-02608C9EEBAC} 16' => {
467             Name => 'DateAccessed',
468             Groups => { 2 => 'Time' },
469             PrintConv => '$self->ConvertDateTime($val)',
470             },
471             '{B725F130-47EF-101A-A5F1-02608C9EEBAC} 13' => 'Attributes',
472             '{D8C3986F-813B-449C-845D-87B95D674ADE} 2' => 'Status',
473             '{9B174B34-40FF-11D2-A27E-00C04FC30871} 4' => 'Owner',
474             '{F29F85E0-4FF9-1068-AB91-08002B27B3D9} 4' => {
475             Name => 'Author',
476             Groups => { 2 => 'Author' },
477             },
478             '{F29F85E0-4FF9-1068-AB91-08002B27B3D9} 2' => 'Title',
479             '{F29F85E0-4FF9-1068-AB91-08002B27B3D9} 3' => 'Subject',
480             '{D5CDD502-2E9C-101B-9397-08002B2CF9AE} 2' => 'Category',
481             '{F29F85E0-4FF9-1068-AB91-08002B27B3D9} 14' => 'Pages',
482             '{F29F85E0-4FF9-1068-AB91-08002B27B3D9} 6' => 'Comments',
483             '{64440492-4C8B-11D1-8B70-080036B11A03} 11' => {
484             Name => 'Copyright',
485             Groups => { 2 => 'Author' },
486             },
487             '{56A3372E-CE9C-11D2-9F0E-006097C686F6} 2' => 'Artist',
488             '{56A3372E-CE9C-11D2-9F0E-006097C686F6} 4' => 'AlbumTitle',
489             '{56A3372E-CE9C-11D2-9F0E-006097C686F6} 5' => {
490             Name => 'Year',
491             Groups => { 2 => 'Time' },
492             },
493             '{56A3372E-CE9C-11D2-9F0E-006097C686F6} 7' => 'TrackNumber',
494             '{56A3372E-CE9C-11D2-9F0E-006097C686F6} 11' => 'Genre',
495             '{64440490-4C8B-11D1-8B70-080036B11A03} 3' => 'Duration',
496             '{64440490-4C8B-11D1-8B70-080036B11A03} 4' => 'Bitrate',
497             '{AEAC19E4-89AE-4508-B9B7-BB867ABEE2ED} 2' => 'Protected',
498             '{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 272' => 'CameraModel',
499             '{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 36867' => {
500             Name => 'DatePictureTaken',
501             Groups => { 2 => 'Time' },
502             PrintConv => '$self->ConvertDateTime($val)',
503             },
504             '{6444048F-4C8B-11D1-8B70-080036B11A03} 13' => 'Dimensions',
505             '{6444048F-4C8B-11D1-8B70-080036B11A03} 3' => 'Untitled0',
506             '{6444048F-4C8B-11D1-8B70-080036B11A03} 4' => 'Untitled1',
507             '{6D748DE2-8D38-4CC3-AC60-F009B057C557} 2' => 'EpisodeName',
508             '{6D748DE2-8D38-4CC3-AC60-F009B057C557} 3' => 'ProgramDescription',
509             '{F29F85E0-4FF9-1068-AB91-08002B27B3D9} 12' => 'Untitled2',
510             '{64440490-4C8B-11D1-8B70-080036B11A03} 6' => 'AudioSampleSize',
511             '{64440490-4C8B-11D1-8B70-080036B11A03} 5' => 'AudioSampleRate',
512             '{64440490-4C8B-11D1-8B70-080036B11A03} 7' => 'Channels',
513             '{D5CDD502-2E9C-101B-9397-08002B2CF9AE} 15' => 'Company',
514             '{0CEF7D53-FA64-11D1-A203-0000F81FEDEE} 3' => 'Description',
515             '{0CEF7D53-FA64-11D1-A203-0000F81FEDEE} 4' => 'FileVersion',
516             '{0CEF7D53-FA64-11D1-A203-0000F81FEDEE} 7' => 'ProductName',
517             '{0CEF7D53-FA64-11D1-A203-0000F81FEDEE} 8' => 'ProductVersion',
518             '{F29F85E0-4FF9-1068-AB91-08002B27B3D9} 5' => 'Keywords',
519             '{28636AA6-953D-11D2-B5D6-00C04FD918D0} 11' => 'Type',
520             '{6D24888F-4718-4BDA-AFED-EA0FB4386CD8} 100' => 'OfflineStatus',
521             '{A94688B6-7D9F-4570-A648-E3DFC0AB2B3F} 100' => 'OfflineAvailability',
522             '{28636AA6-953D-11D2-B5D6-00C04FD918D0} 9' => 'PerceivedType',
523             '{1E3EE840-BC2B-476C-8237-2ACD1A839B22} 3' => 'Kinds',
524             '{56A3372E-CE9C-11D2-9F0E-006097C686F6} 36' => 'Conductors',
525             '{64440492-4C8B-11D1-8B70-080036B11A03} 9' => 'Rating',
526             '{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 271' => 'CameraMaker',
527             '{F29F85E0-4FF9-1068-AB91-08002B27B3D9} 18' => 'ProgramName',
528             '{293CA35A-09AA-4DD2-B180-1FE245728A52} 100' => 'Duration',
529             '{BFEE9149-E3E2-49A7-A862-C05988145CEC} 100' => 'IsOnline',
530             '{315B9C8D-80A9-4EF9-AE16-8E746DA51D70} 100' => 'IsRecurring',
531             '{F6272D18-CECC-40B1-B26A-3911717AA7BD} 100' => 'Location',
532             '{D55BAE5A-3892-417A-A649-C6AC5AAAEAB3} 100' => 'OptionalAttendeeAddresses',
533             '{09429607-582D-437F-84C3-DE93A2B24C3C} 100' => 'OptionalAttendees',
534             '{744C8242-4DF5-456C-AB9E-014EFB9021E3} 100' => 'OrganizerAddress',
535             '{AAA660F9-9865-458E-B484-01BC7FE3973E} 100' => 'OrganizerName',
536             '{72FC5BA4-24F9-4011-9F3F-ADD27AFAD818} 100' => 'ReminderTime',
537             '{0BA7D6C3-568D-4159-AB91-781A91FB71E5} 100' => 'RequiredAttendeeAddresses',
538             '{B33AF30B-F552-4584-936C-CB93E5CDA29F} 100' => 'RequiredAttendees',
539             '{00F58A38-C54B-4C40-8696-97235980EAE1} 100' => 'Resources',
540             '{5BF396D4-5EB2-466F-BDE9-2FB3F2361D6E} 100' => 'Free-busyStatus',
541             '{9B174B35-40FF-11D2-A27E-00C04FC30871} 3' => 'TotalSize',
542             '{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD} 9' => 'AccountName',
543             '{28636AA6-953D-11D2-B5D6-00C04FD918D0} 5' => 'Computer',
544             '{9AD5BADB-CEA7-4470-A03D-B84E51B9949E} 100' => 'Anniversary',
545             '{CD102C9C-5540-4A88-A6F6-64E4981C8CD1} 100' => 'AssistantsName',
546             '{9A93244D-A7AD-4FF8-9B99-45EE4CC09AF6} 100' => 'AssistantsPhone',
547             '{176DC63C-2688-4E89-8143-A347800F25E9} 47' => 'Birthday',
548             '{730FB6DD-CF7C-426B-A03F-BD166CC9EE24} 100' => 'BusinessAddress',
549             '{402B5934-EC5A-48C3-93E6-85E86A2D934E} 100' => 'BusinessCity',
550             '{B0B87314-FCF6-4FEB-8DFF-A50DA6AF561C} 100' => 'BusinessCountry-Region',
551             '{BC4E71CE-17F9-48D5-BEE9-021DF0EA5409} 100' => 'BusinessPOBox',
552             '{E1D4A09E-D758-4CD1-B6EC-34A8B5A73F80} 100' => 'BusinessPostalCode',
553             '{446F787F-10C4-41CB-A6C4-4D0343551597} 100' => 'BusinessStateOrProvince',
554             '{DDD1460F-C0BF-4553-8CE4-10433C908FB0} 100' => 'BusinessStreet',
555             '{91EFF6F3-2E27-42CA-933E-7C999FBE310B} 100' => 'BusinessFax',
556             '{56310920-2491-4919-99CE-EADB06FAFDB2} 100' => 'BusinessHomePage',
557             '{6A15E5A0-0A1E-4CD7-BB8C-D2F1B0C929BC} 100' => 'BusinessPhone',
558             '{BF53D1C3-49E0-4F7F-8567-5A821D8AC542} 100' => 'CallbackNumber',
559             '{8FDC6DEA-B929-412B-BA90-397A257465FE} 100' => 'CarPhone',
560             '{D4729704-8EF1-43EF-9024-2BD381187FD5} 100' => 'Children',
561             '{8589E481-6040-473D-B171-7FA89C2708ED} 100' => 'CompanyMainPhone',
562             '{FC9F7306-FF8F-4D49-9FB6-3FFE5C0951EC} 100' => 'Department',
563             '{F8FA7FA3-D12B-4785-8A4E-691A94F7A3E7} 100' => 'E-mailAddress',
564             '{38965063-EDC8-4268-8491-B7723172CF29} 100' => 'E-mail2',
565             '{644D37B4-E1B3-4BAD-B099-7E7C04966ACA} 100' => 'E-mail3',
566             '{84D8F337-981D-44B3-9615-C7596DBA17E3} 100' => 'E-mailList',
567             '{CC6F4F24-6083-4BD4-8754-674D0DE87AB8} 100' => 'E-mailDisplayName',
568             '{F1A24AA7-9CA7-40F6-89EC-97DEF9FFE8DB} 100' => 'FileAs',
569             '{14977844-6B49-4AAD-A714-A4513BF60460} 100' => 'FirstName',
570             '{635E9051-50A5-4BA2-B9DB-4ED056C77296} 100' => 'FullName',
571             '{3C8CEE58-D4F0-4CF9-B756-4E5D24447BCD} 100' => 'Gender',
572             '{176DC63C-2688-4E89-8143-A347800F25E9} 70' => 'GivenName',
573             '{5DC2253F-5E11-4ADF-9CFE-910DD01E3E70} 100' => 'Hobbies',
574             '{98F98354-617A-46B8-8560-5B1B64BF1F89} 100' => 'HomeAddress',
575             '{176DC63C-2688-4E89-8143-A347800F25E9} 65' => 'HomeCity',
576             '{08A65AA1-F4C9-43DD-9DDF-A33D8E7EAD85} 100' => 'HomeCountry-Region',
577             '{7B9F6399-0A3F-4B12-89BD-4ADC51C918AF} 100' => 'HomePOBox',
578             '{8AFCC170-8A46-4B53-9EEE-90BAE7151E62} 100' => 'HomePostalCode',
579             '{C89A23D0-7D6D-4EB8-87D4-776A82D493E5} 100' => 'HomeStateOrProvince',
580             '{0ADEF160-DB3F-4308-9A21-06237B16FA2A} 100' => 'HomeStreet',
581             '{660E04D6-81AB-4977-A09F-82313113AB26} 100' => 'HomeFax',
582             '{176DC63C-2688-4E89-8143-A347800F25E9} 20' => 'HomePhone',
583             '{D68DBD8A-3374-4B81-9972-3EC30682DB3D} 100' => 'IMAddresses',
584             '{F3D8F40D-50CB-44A2-9718-40CB9119495D} 100' => 'Initials',
585             '{176DC63C-2688-4E89-8143-A347800F25E9} 6' => 'JobTitle',
586             '{97B0AD89-DF49-49CC-834E-660974FD755B} 100' => 'Label',
587             '{8F367200-C270-457C-B1D4-E07C5BCD90C7} 100' => 'LastName',
588             '{C0AC206A-827E-4650-95AE-77E2BB74FCC9} 100' => 'MailingAddress',
589             '{176DC63C-2688-4E89-8143-A347800F25E9} 71' => 'MiddleName',
590             '{176DC63C-2688-4E89-8143-A347800F25E9} 35' => 'CellPhone',
591             '{176DC63C-2688-4E89-8143-A347800F25E9} 74' => 'Nickname',
592             '{176DC63C-2688-4E89-8143-A347800F25E9} 7' => 'OfficeLocation',
593             '{508161FA-313B-43D5-83A1-C1ACCF68622C} 100' => 'OtherAddress',
594             '{6E682923-7F7B-4F0C-A337-CFCA296687BF} 100' => 'OtherCity',
595             '{8F167568-0AAE-4322-8ED9-6055B7B0E398} 100' => 'OtherCountry-Region',
596             '{8B26EA41-058F-43F6-AECC-4035681CE977} 100' => 'OtherPOBox',
597             '{95C656C1-2ABF-4148-9ED3-9EC602E3B7CD} 100' => 'OtherPostalCode',
598             '{71B377D6-E570-425F-A170-809FAE73E54E} 100' => 'OtherStateOrProvince',
599             '{FF962609-B7D6-4999-862D-95180D529AEA} 100' => 'OtherStreet',
600             '{D6304E01-F8F5-4F45-8B15-D024A6296789} 100' => 'Pager',
601             '{176DC63C-2688-4E89-8143-A347800F25E9} 69' => 'PersonalTitle',
602             '{C8EA94F0-A9E3-4969-A94B-9C62A95324E0} 100' => 'City',
603             '{E53D799D-0F3F-466E-B2FF-74634A3CB7A4} 100' => 'Country-Region',
604             '{DE5EF3C7-46E1-484E-9999-62C5308394C1} 100' => 'POBox',
605             '{18BBD425-ECFD-46EF-B612-7B4A6034EDA0} 100' => 'PostalCode',
606             '{F1176DFE-7138-4640-8B4C-AE375DC70A6D} 100' => 'StateOrProvince',
607             '{63C25B20-96BE-488F-8788-C09C407AD812} 100' => 'Street',
608             '{176DC63C-2688-4E89-8143-A347800F25E9} 48' => 'PrimaryE-mail',
609             '{176DC63C-2688-4E89-8143-A347800F25E9} 25' => 'PrimaryPhone',
610             '{7268AF55-1CE4-4F6E-A41F-B6E4EF10E4A9} 100' => 'Profession',
611             '{9D2408B6-3167-422B-82B0-F583B7A7CFE3} 100' => 'Spouse',
612             '{176DC63C-2688-4E89-8143-A347800F25E9} 73' => 'Suffix',
613             '{AAF16BAC-2B55-45E6-9F6D-415EB94910DF} 100' => 'TTY-TTDPhone',
614             '{C554493C-C1F7-40C1-A76C-EF8C0614003E} 100' => 'Telex',
615             '{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD} 18' => 'Webpage',
616             '{D5CDD502-2E9C-101B-9397-08002B2CF9AE} 27' => 'Status',
617             '{D5CDD502-2E9C-101B-9397-08002B2CF9AE} 26' => 'ContentType',
618             '{43F8D7B7-A444-4F87-9383-52271C9B915C} 100' => {
619             Name => 'DateArchived',
620             Groups => { 2 => 'Time' },
621             PrintConv => '$self->ConvertDateTime($val)',
622             },
623             '{72FAB781-ACDA-43E5-B155-B2434F85E678} 100' => {
624             Name => 'DateCompleted',
625             Groups => { 2 => 'Time' },
626             PrintConv => '$self->ConvertDateTime($val)',
627             },
628             '{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 18258' => {
629             Name => 'DateImported',
630             Groups => { 2 => 'Time' },
631             PrintConv => '$self->ConvertDateTime($val)',
632             },
633             '{276D7BB0-5B34-4FB0-AA4B-158ED12A1809} 100' => 'ClientID',
634             '{F334115E-DA1B-4509-9B3D-119504DC7ABB} 100' => 'Contributors',
635             '{F29F85E0-4FF9-1068-AB91-08002B27B3D9} 11' => 'LastPrinted',
636             '{F29F85E0-4FF9-1068-AB91-08002B27B3D9} 13' => {
637             Name => 'DateLastSaved',
638             Groups => { 2 => 'Time' },
639             PrintConv => '$self->ConvertDateTime($val)',
640             },
641             '{1E005EE6-BF27-428B-B01C-79676ACD2870} 100' => 'Division',
642             '{E08805C8-E395-40DF-80D2-54F0D6C43154} 100' => 'DocumentID',
643             '{D5CDD502-2E9C-101B-9397-08002B2CF9AE} 7' => 'Slides',
644             '{F29F85E0-4FF9-1068-AB91-08002B27B3D9} 10' => 'TotalEditingTime',
645             '{F29F85E0-4FF9-1068-AB91-08002B27B3D9} 15' => 'WordCount',
646             '{3F8472B5-E0AF-4DB2-8071-C53FE76AE7CE} 100' => 'DueDate',
647             '{C75FAA05-96FD-49E7-9CB4-9F601082D553} 100' => 'EndDate',
648             '{28636AA6-953D-11D2-B5D6-00C04FD918D0} 12' => 'FileCount',
649             '{41CF5AE0-F75A-4806-BD87-59C7D9248EB9} 100' => 'WindowsFileName',
650             '{67DF94DE-0CA7-4D6F-B792-053A3E4F03CF} 100' => 'FlagColor',
651             '{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD} 12' => 'FlagStatus',
652             '{9B174B35-40FF-11D2-A27E-00C04FC30871} 2' => 'SpaceFree',
653             '{6444048F-4C8B-11D1-8B70-080036B11A03} 7' => 'BitDepth',
654             '{6444048F-4C8B-11D1-8B70-080036B11A03} 5' => 'HorizontalResolution',
655             '{6444048F-4C8B-11D1-8B70-080036B11A03} 6' => 'VerticalResolution',
656             '{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD} 11' => 'Importance',
657             '{F23F425C-71A1-4FA8-922F-678EA4A60408} 100' => 'IsAttachment',
658             '{5CDA5FC8-33EE-4FF3-9094-AE7BD8868C4D} 100' => 'IsDeleted',
659             '{5DA84765-E3FF-4278-86B0-A27967FBDD03} 100' => 'HasFlag',
660             '{A6F360D2-55F9-48DE-B909-620E090A647C} 100' => 'IsCompleted',
661             '{346C8BD1-2E6A-4C45-89A4-61B78E8E700F} 100' => 'Incomplete',
662             '{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD} 10' => 'ReadStatus',
663             '{EF884C5B-2BFE-41BB-AAE5-76EEDF4F9902} 100' => 'Shared',
664             '{D0A04F0A-462A-48A4-BB2F-3706E88DBD7D} 100' => {
665             Name => 'Creator',
666             Groups => { 2 => 'Author' },
667             },
668             '{F7DB74B4-4287-4103-AFBA-F1B13DCD75CF} 100' => {
669             Name => 'Date',
670             Groups => { 2 => 'Time' },
671             PrintConv => '$self->ConvertDateTime($val)',
672             },
673             '{B725F130-47EF-101A-A5F1-02608C9EEBAC} 2' => 'FolderName',
674             '{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD} 6' => 'FolderPath',
675             '{DABD30ED-0043-4789-A7F8-D013A4736622} 100' => 'Folder',
676             '{D4D0AA16-9948-41A4-AA85-D97FF9646993} 100' => 'Participants',
677             '{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD} 7' => 'Path',
678             '{DEA7C82C-1D89-4A66-9427-A4E3DEBABCB1} 100' => 'ContactNames',
679             '{95BEB1FC-326D-4644-B396-CD3ED90E6DDF} 100' => 'EntryType',
680             '{D5CDD502-2E9C-101B-9397-08002B2CF9AE} 28' => 'Language',
681             '{5CBF2787-48CF-4208-B90E-EE5E5D420294} 23' => {
682             Name => 'DateVisited',
683             Groups => { 2 => 'Time' },
684             PrintConv => '$self->ConvertDateTime($val)',
685             },
686             '{5CBF2787-48CF-4208-B90E-EE5E5D420294} 21' => 'Description',
687             '{B9B4B3FC-2B51-4A42-B5D8-324146AFCF25} 3' => 'LinkStatus',
688             '{B9B4B3FC-2B51-4A42-B5D8-324146AFCF25} 2' => 'LinkTarget',
689             '{5CBF2787-48CF-4208-B90E-EE5E5D420294} 2' => 'URL',
690             '{2E4B640D-5019-46D8-8881-55414CC5CAA0} 100' => 'MediaCreated',
691             '{DE41CC29-6971-4290-B472-F59F2E2F31E2} 100' => {
692             Name => 'DateReleased',
693             Groups => { 2 => 'Time' },
694             PrintConv => '$self->ConvertDateTime($val)',
695             },
696             '{64440492-4C8B-11D1-8B70-080036B11A03} 36' => 'EncodedBy',
697             '{64440492-4C8B-11D1-8B70-080036B11A03} 22' => 'Producers',
698             '{64440492-4C8B-11D1-8B70-080036B11A03} 30' => 'Publisher',
699             '{56A3372E-CE9C-11D2-9F0E-006097C686F6} 38' => 'Subtitle',
700             '{64440492-4C8B-11D1-8B70-080036B11A03} 34' => 'UserWebURL',
701             '{64440492-4C8B-11D1-8B70-080036B11A03} 23' => 'Writers',
702             '{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD} 21' => 'Attachments',
703             '{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD} 2' => 'BccAddresses',
704             '{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD} 3' => 'BccNames',
705             '{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD} 4' => 'CcAddresses',
706             '{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD} 5' => 'CcNames',
707             '{DC8F80BD-AF1E-4289-85B6-3DFC1B493992} 100' => 'ConversationID',
708             '{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD} 20' => {
709             Name => 'DateReceived',
710             Groups => { 2 => 'Time' },
711             PrintConv => '$self->ConvertDateTime($val)',
712             },
713             '{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD} 19' => {
714             Name => 'DateSent',
715             Groups => { 2 => 'Time' },
716             PrintConv => '$self->ConvertDateTime($val)',
717             },
718             '{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD} 13' => 'FromAddresses',
719             '{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD} 14' => 'FromNames',
720             '{9C1FCF74-2D97-41BA-B4AE-CB2E3661A6E4} 8' => 'HasAttachments',
721             '{0BE1C8E7-1981-4676-AE14-FDD78F05A6E7} 100' => 'SenderAddress',
722             '{0DA41CFA-D224-4A18-AE2F-596158DB4B3A} 100' => 'SenderName',
723             '{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD} 15' => 'Store',
724             '{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD} 16' => 'ToAddresses',
725             '{BCCC8A3C-8CEF-42E5-9B1C-C69079398BC7} 100' => 'ToDoTitle',
726             '{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD} 17' => 'ToNames',
727             '{FDF84370-031A-4ADD-9E91-0D775F1C6605} 100' => 'Mileage',
728             '{56A3372E-CE9C-11D2-9F0E-006097C686F6} 13' => 'AlbumArtist',
729             '{56A3372E-CE9C-11D2-9F0E-006097C686F6} 35' => 'Beats-per-minute',
730             '{64440492-4C8B-11D1-8B70-080036B11A03} 19' => 'Composers',
731             '{56A3372E-CE9C-11D2-9F0E-006097C686F6} 34' => 'InitialKey',
732             '{56A3372E-CE9C-11D2-9F0E-006097C686F6} 39' => 'Mood',
733             '{56A3372E-CE9C-11D2-9F0E-006097C686F6} 37' => 'PartOfSet',
734             '{64440492-4C8B-11D1-8B70-080036B11A03} 31' => 'Period',
735             '{4776CAFA-BCE4-4CB1-A23E-265E76D8EB11} 100' => 'Color',
736             '{64440492-4C8B-11D1-8B70-080036B11A03} 21' => 'ParentalRating',
737             '{10984E0A-F9F2-4321-B7EF-BAF195AF4319} 100' => 'ParentalRatingReason',
738             '{9B174B35-40FF-11D2-A27E-00C04FC30871} 5' => 'SpaceUsed',
739             '{D35F743A-EB2E-47F2-A286-844132CB1427} 100' => 'ExifVersion',
740             '{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 18248' => 'Event',
741             '{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 37380' => 'ExposureBias',
742             '{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 34850' => 'ExposureProgram',
743             '{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 33434' => 'ExposureTime',
744             '{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 33437' => 'F-stop',
745             '{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 37385' => 'FlashMode',
746             '{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 37386' => 'FocalLength',
747             '{A0E74609-B84D-4F49-B860-462BD9971F98} 100' => 'FocalLength35mm',
748             '{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 34855' => 'ISOSpeed',
749             '{E6DDCAF7-29C5-4F0A-9A68-D19412EC7090} 100' => 'LensMaker',
750             '{E1277516-2B5F-4869-89B1-2E585BD38B7A} 100' => 'LensModel',
751             '{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 37384' => 'LightSource',
752             '{08F6D7C2-E3F2-44FC-AF1E-5AA5C81A2D3E} 100' => 'MaxAperture',
753             '{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 37383' => 'MeteringMode',
754             '{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 274' => 'Orientation',
755             '{6D217F6D-3F6A-4825-B470-5F03CA2FBE9B} 100' => 'ProgramMode',
756             '{49237325-A95A-4F67-B211-816B2D45D2E0} 100' => 'Saturation',
757             '{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 37382' => 'SubjectDistance',
758             '{EE3D3D8A-5381-4CFA-B13B-AAF66B5F4EC9} 100' => 'WhiteBalance',
759             '{9C1FCF74-2D97-41BA-B4AE-CB2E3661A6E4} 5' => 'Priority',
760             '{39A7F922-477C-48DE-8BC8-B28441E342E3} 100' => 'Project',
761             '{6D748DE2-8D38-4CC3-AC60-F009B057C557} 7' => 'ChannelNumber',
762             '{6D748DE2-8D38-4CC3-AC60-F009B057C557} 12' => 'ClosedCaptioning',
763             '{6D748DE2-8D38-4CC3-AC60-F009B057C557} 13' => 'Rerun',
764             '{6D748DE2-8D38-4CC3-AC60-F009B057C557} 14' => 'SAP',
765             '{4684FE97-8765-4842-9C13-F006447B178C} 100' => 'BroadcastDate',
766             '{A5477F61-7A82-4ECA-9DDE-98B69B2479B3} 100' => 'RecordingTime',
767             '{6D748DE2-8D38-4CC3-AC60-F009B057C557} 5' => 'StationCallSign',
768             '{1B5439E7-EBA1-4AF8-BDD7-7AF1D4549493} 100' => 'StationName',
769             '{560C36C0-503A-11CF-BAA1-00004C752A9A} 2' => 'AutoSummary',
770             '{560C36C0-503A-11CF-BAA1-00004C752A9A} 3' => 'Summary',
771             '{49691C90-7E17-101A-A91C-08002B2ECDA9} 3' => 'SearchRanking',
772             '{F8D3F6AC-4874-42CB-BE59-AB454B30716A} 100' => 'Sensitivity',
773             '{EF884C5B-2BFE-41BB-AAE5-76EEDF4F9902} 200' => 'SharedWith',
774             '{668CDFA5-7A1B-4323-AE4B-E527393A1D81} 100' => 'Source',
775             '{48FD6EC8-8A12-4CDF-A03E-4EC5A511EDDE} 100' => 'StartDate',
776             '{D37D52C6-261C-4303-82B3-08B926AC6F12} 100' => 'BillingInformation',
777             '{084D8A0A-E6D5-40DE-BF1F-C8820E7C877C} 100' => 'Complete',
778             '{08C7CC5F-60F2-4494-AD75-55E3E0B5ADD0} 100' => 'TaskOwner',
779             '{28636AA6-953D-11D2-B5D6-00C04FD918D0} 14' => 'TotalFileSize',
780             '{0CEF7D53-FA64-11D1-A203-0000F81FEDEE} 9' => 'LegalTrademarks',
781             '{64440491-4C8B-11D1-8B70-080036B11A03} 10' => 'VideoCompression',
782             '{64440492-4C8B-11D1-8B70-080036B11A03} 20' => 'Directors',
783             '{64440491-4C8B-11D1-8B70-080036B11A03} 8' => 'DataRate',
784             '{64440491-4C8B-11D1-8B70-080036B11A03} 4' => 'FrameHeight',
785             '{64440491-4C8B-11D1-8B70-080036B11A03} 6' => 'FrameRate',
786             '{64440491-4C8B-11D1-8B70-080036B11A03} 3' => 'FrameWidth',
787             '{64440491-4C8B-11D1-8B70-080036B11A03} 43' => 'TotalBitrate',
788             );
789              
790             #------------------------------------------------------------------------------
791             # check new value for Xtra tag
792             # Inputs: 0) ExifTool object ref, 1) tagInfo hash ref, 2) raw value ref
793             # Returns: error string, or undef on success
794             sub CheckXtra($$$)
795             {
796 17     17 0 61 my ($et, $tagInfo, $valPt) = @_;
797 17         46 my $format = $$tagInfo{Writable};
798 17 50       68 return 'Unknown format' unless $format;
799 17 100       113 if ($format =~ /^int/) {
    50          
800 1 50       10 return 'Not an integer' unless Image::ExifTool::IsInt($$valPt);
801             } elsif ($format ne 'Unicode') {
802 0         0 my @vals = ($$valPt);
803 0 0       0 return 'Invalid format' unless WriteXtraValue($et, $tagInfo, \@vals);
804             }
805 17         58 return undef;
806             }
807              
808             #------------------------------------------------------------------------------
809             # Decode value(s) in Microsoft Xtra tag
810             # Inputs: 0) ExifTool object ref, 1) value data
811             # Returns: Scalar context: decoded value, List context: 0) decoded value, 1) format string
812             sub ReadXtraValue($$)
813             {
814 2     2 0 8 my ($et, $data) = @_;
815 2         6 my ($format, $i, @vals);
816            
817 2 50       9 return undef if length($data) < 10;
818              
819             # (version flags according to the reference, but looks more like a count - PH)
820 2         6 my $count = Get32u(\$data, 0);
821             # point to start of first value (after 4-byte count, 4-byte length and 2-byte type)
822 2         5 my $valPos = 10;
823 2         4 for ($i=0; ;) {
824             # (stored value includes size of $valLen and $valType, so subtract 6)
825 3         9 my $valLen = Get32u(\$data, $valPos - 6) - 6;
826 3 50       12 last if $valPos + $valLen > length($data);
827 3         8 my $valType = Get16u(\$data, $valPos - 2);
828 3         9 my $val = substr($data, $valPos, $valLen);
829             # Note: all dumb Microsoft values are little-endian inside a big-endian-format file
830 3         9 SetByteOrder('II');
831 3 100 33     14 if ($valType == 8) {
    50 0        
    0 0        
    0 0        
    0          
832 2         6 $format = 'Unicode';
833 2         7 $val = $et->Decode($val, 'UCS2');
834             } elsif ($valType == 19 and $valLen == 8) {
835 1         3 $format = 'int64u';
836 1         11 $val = Get64u(\$val, 0);
837             } elsif ($valType == 21 and $valLen == 8) {
838 0         0 $format = 'date';
839 0         0 $val = Get64u(\$val, 0);
840             # convert time from 100 ns intervals since Jan 1, 1601
841 0 0       0 $val = $val * 1e-7 - 11644473600 if $val;
842             # (the Nikon S100 uses UTC timezone, same as ASF - PH)
843 0         0 $val = Image::ExifTool::ConvertUnixTime($val, 1);
844             } elsif ($valType == 72 and $valLen == 16) {
845 0         0 $format = 'GUID';
846 0         0 $val = uc unpack('H*',pack('NnnNN',unpack('VvvNN',$val)));
847 0         0 $val =~ s/(.{8})(.{4})(.{4})(.{4})/$1-$2-$3-$4-/;
848             } elsif ($valType == 65 and $valLen > 4) { #PH (empirical)
849 0         0 $format = 'variant';
850 0         0 require Image::ExifTool::FlashPix;
851 0         0 my $vPos = 0; # (necessary because ReadFPXValue updates this)
852             # read entry as a VT_VARIANT (use FlashPix module for this)
853 0         0 $val = Image::ExifTool::FlashPix::ReadFPXValue($et, \$val, $vPos,
854             Image::ExifTool::FlashPix::VT_VARIANT(), $valLen, 1);
855             } else {
856 0         0 $format = "Unknown($valType)";
857             }
858 3         11 SetByteOrder('MM'); # back to native QuickTime byte ordering
859 3         8 push @vals, $val;
860 3 100       12 last if ++$i >= $count;
861 1         3 $valPos += $valLen + 6; # step to next value
862 1 50       5 last if $valPos > length($data);
863             }
864 2 50       12 return wantarray ? (\@vals, $format) : \@vals;
865             }
866              
867             #------------------------------------------------------------------------------
868             # Write a Microsoft Xtra value
869             # Inputs: 0) ExifTool object ref, 1) tagInfo ref, 2) reference to list of values
870             # Returns: new value binary data (or empty string)
871             sub WriteXtraValue($$$)
872             {
873 2     2 0 6 my ($et, $tagInfo, $vals) = @_;
874 2         6 my $format = $$tagInfo{Writable};
875 2         4 my $buff = '';
876 2         4 my $count = 0;
877 2         4 my $val;
878 2         5 foreach $val (@$vals) {
879 3         11 SetByteOrder('II');
880 3         6 my ($type, $dat);
881 3 100       11 if ($format eq 'Unicode') {
    50          
    0          
    0          
    0          
882 2         11 $dat = $et->Encode($val,'UCS2','II') . "\0\0"; # (must be null terminated)
883 2         16 $type = 8;
884             } elsif ($format eq 'int64u') {
885 1 50       5 if (Image::ExifTool::IsInt($val)) {
886 1         7 $dat = Set64u($val);
887 1         4 $type = 19;
888             }
889             } elsif ($format eq 'date') {
890 0         0 $dat = Image::ExifTool::GetUnixTime($val, 1); # (convert to UTC, NC)
891 0 0       0 if ($dat) {
892             # 100ns intervals since Jan 1, 1601
893 0         0 $dat = Set64u(($dat + 11644473600) * 1e7);
894 0         0 $type = 21;
895             }
896             } elsif ($format eq 'vt_filetime') { # 'date' value inside a VT_VARIANT
897 0         0 $dat = Image::ExifTool::GetUnixTime($val); # (leave as local time, NC)
898 0 0       0 if ($dat) {
899             # 100ns intervals since Jan 1, 1601
900 0         0 $dat = Set32u(64) . Set64u(($dat + 11644473600) * 1e7);
901 0         0 $type = 65;
902             }
903             } elsif ($format eq 'GUID') {
904 0         0 ($dat = $val) =~ tr/-//d;
905 0 0       0 if (length($dat) == 32) {
906 0         0 $dat = pack('VvvNN',unpack('NnnNN',pack('H*', $dat)));
907 0         0 $type = 72;
908             }
909             } else {
910 0         0 $et->WarnOnce("Error converting value for Microsoft:$$tagInfo{Name}");
911             }
912 3         10 SetByteOrder('MM');
913 3 50       9 if (defined $type) {
914 3         7 ++$count;
915 3         8 $buff .= Set32u(length($dat)+6) . Set16u($type) . $dat;
916             }
917             }
918 2 50       9 return $count ? Set32u($count) . $buff : '';
919             }
920              
921             #------------------------------------------------------------------------------
922             # Add new values to list
923             # Inputs: 0) ExifTool ref, 1) new value list ref, 2) nvHash ref
924             # Returns: true if something was added
925             sub AddNewValues($$$)
926             {
927 2     2 0 7 my ($et, $vals, $nvHash) = @_;
928 2 50       11 my @newVals = $et->GetNewValue($nvHash) or return undef;
929 2 50       9 if ($$et{OPTIONS}{Verbose} > 1) {
930 0         0 $et->VPrint(1, " + Microsoft:$$nvHash{TagInfo}{Name} = $_\n") foreach @newVals;
931             }
932 2         7 push @$vals, @newVals;
933 2         7 return 1;
934             }
935              
936             #------------------------------------------------------------------------------
937             # Write tags to a Microsoft Xtra MP4 atom
938             # Inputs: 0) ExifTool object ref, 1) source dirInfo ref, 2) tag table ref
939             # Returns: Microsoft Xtra data block (may be empty if no Xtra data) or undef on error
940             sub WriteXtra($$$)
941             {
942 19     19 0 63 my ($et, $dirInfo, $tagTablePtr) = @_;
943 19 100       126 $et or return 1; # allow dummy access
944              
945 1   33     10 my $delGroup = ($$et{DEL_GROUP} and $$et{DEL_GROUP}{Microsoft});
946 1         7 my $newTags = $et->GetNewTagInfoHash($tagTablePtr);
947              
948 1 50 33     10 return undef unless $delGroup or %$newTags; # don't rewrite if nothing to do
949              
950 1         4 my $dataPt = $$dirInfo{DataPt};
951 1         3 my $dataLen = length $$dataPt;
952 1         3 my $newData = '';
953 1         2 my $pos = 0;
954 1         4 my ($err, %done, $changed, $tag);
955              
956 1 50       6 if ($delGroup) {
957 0 0       0 $changed = 1 if $dataLen;
958 0         0 my $empty = '';
959 0         0 $dataPt = $empty;
960 0         0 $dataLen = 0;
961             }
962 1         3 for (;;) {
963 1 50       5 last if $pos + 4 > $dataLen;
964 0         0 my $size = Get32u($dataPt, $pos); # (includes $size word)
965 0 0 0     0 ($size < 8 or $pos + $size > $dataLen) and $err=1, last;
966 0         0 my $tagLen = Get32u($dataPt, $pos + 4);
967 0 0       0 $tagLen + 18 > $size and $err=1, last;
968 0         0 $tag = substr($$dataPt, $pos + 8, $tagLen);
969 0         0 my @newVals;
970 0         0 while ($$newTags{$tag}) {
971 0         0 my $nvHash = $et->GetNewValueHash($$newTags{$tag});
972 0 0       0 $$nvHash{CreateOnly} and delete($$newTags{$tag}), last; # don't edit this tag
973 0         0 my $valPos = $pos + 8 + $tagLen;
974 0         0 my $valLen = $size - 8 - $tagLen;
975 0         0 my $val = ReadXtraValue($et, substr($$dataPt, $valPos, $valLen));
976 0         0 foreach $val (@$val) {
977 0         0 my $overwrite = $et->IsOverwriting($nvHash, $val);
978 0 0       0 $overwrite or push(@newVals, $val), next;
979 0         0 $et->VPrint(1, " - Microsoft:$$newTags{$tag}{Name} = $val\n");
980 0 0       0 next if $done{$tag};
981 0         0 $done{$tag} = 1;
982 0         0 AddNewValues($et, \@newVals, $nvHash);
983             }
984             # add to the end of the list if this was a List-type tag and we didn't delete anything
985 0 0 0     0 if (not $done{$tag} and $$newTags{$tag}{List}) {
986 0 0       0 AddNewValues($et, \@newVals, $nvHash) or last;
987 0         0 $done{$tag} = 1;
988             }
989 0         0 last; # (it was a cheap goto)
990             }
991 0 0       0 if ($done{$tag}) {
992 0         0 $changed = 1;
993             # write changed values
994 0         0 my $buff = WriteXtraValue($et, $$newTags{$tag}, \@newVals);
995 0 0       0 if (length $buff) {
996 0         0 $newData .= Set32u(8+length($tag)+length($buff)) . Set32u(length($tag)) . $tag . $buff;
997             }
998             } else {
999             # nothing changed; just copy over
1000 0         0 $newData .= substr($$dataPt, $pos, $size);
1001             }
1002 0         0 $pos += $size; # step to next entry
1003             }
1004 1 50       5 if ($err) {
1005 0         0 $et->Warn('Microsoft Xtra format error');
1006 0         0 return undef;
1007             }
1008             # add any new tags
1009 1         7 foreach $tag (sort keys %$newTags) {
1010 2 50       7 next if $done{$tag};
1011 2         10 my $nvHash = $et->GetNewValueHash($$newTags{$tag});
1012 2 50 33     15 next unless $$nvHash{IsCreating} and not $$nvHash{EditOnly};
1013 2         5 my @newVals;
1014 2 50       8 AddNewValues($et, \@newVals, $nvHash) or next;
1015 2         11 my $buff = WriteXtraValue($et, $$newTags{$tag}, \@newVals);
1016 2 50       8 if (length $buff) {
1017 2         7 $newData .= Set32u(8+length($tag)+length($buff)) . Set32u(length($tag)) . $tag . $buff;
1018 2         9 $changed = 1;
1019             }
1020             }
1021 1 50       6 if ($changed) {
1022 1         3 ++$$et{CHANGED};
1023             } else {
1024 0         0 undef $newData;
1025             }
1026 1         6 return $newData;
1027             }
1028              
1029             #------------------------------------------------------------------------------
1030             # Extract information from Xtra MP4 atom
1031             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
1032             # Returns: 1 on success
1033             # Reference: http://code.google.com/p/mp4v2/ [since removed from trunk]
1034             sub ProcessXtra($$$)
1035             {
1036 1     1 0 4 my ($et, $dirInfo, $tagTablePtr) = @_;
1037 1         5 my $dataPt = $$dirInfo{DataPt};
1038 1   50     5 my $dataPos = $$dirInfo{Base} || 0;
1039 1         3 my $dataLen = $$dirInfo{DataLen};
1040 1         2 my $pos = 0;
1041 1         7 $et->VerboseDir('Xtra', 0, $dataLen);
1042 1         2 for (;;) {
1043 3 100       12 last if $pos + 4 > $dataLen;
1044 2         9 my $size = Get32u($dataPt, $pos); # (includes $size word)
1045 2 50 33     15 last if $size < 8 or $pos + $size > $dataLen;
1046 2         6 my $tagLen = Get32u($dataPt, $pos + 4);
1047 2 50       8 last if $tagLen + 18 > $size;
1048 2         6 my $valLen = $size - 8 - $tagLen;
1049 2 50 33     13 if ($tagLen > 0 and $valLen > 0) {
1050 2         8 my $tag = substr($$dataPt, $pos + 8, $tagLen);
1051 2         4 my $valPos = $pos + 8 + $tagLen;
1052 2         10 my ($val, $format) = ReadXtraValue($et, substr($$dataPt, $valPos, $valLen));
1053 2 50       10 last unless defined $val;
1054 2 100       8 $val = $$val[0] if @$val == 1;
1055 2         9 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
1056 2 50       8 unless ($tagInfo) {
1057             # generate tag information for unrecognized tags
1058 0         0 my $name = $tag;
1059 0         0 $name =~ s{^WM/}{};
1060             # $name =~ tr/-_A-Za-z0-9//dc;
1061 0 0       0 if ($name =~ /^[-\w]+$/) {
1062 0         0 $tagInfo = { Name => ucfirst($name) };
1063 0         0 AddTagToTable($tagTablePtr, $tag, $tagInfo);
1064 0         0 $et->VPrint(0, $$et{INDENT}, "[adding Microsoft:$tag]\n");
1065             }
1066             }
1067 2 100       7 my $count = ref $val ? scalar @$val : 1;
1068 2         12 $et->HandleTag($tagTablePtr, $tag, $val,
1069             TagInfo => $tagInfo,
1070             DataPt => $dataPt,
1071             DataPos => $dataPos,
1072             Start => $valPos,
1073             Size => $valLen,
1074             Format => $format,
1075             Extra => " count=$count",
1076             );
1077             }
1078 2         5 $pos += $size; # step to next entry
1079             }
1080 1         3 return 1;
1081             }
1082              
1083             1; # end
1084              
1085             __END__