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