exiftool_vendored 10.65.0 → 11.41.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of exiftool_vendored might be problematic. Click here for more details.

Files changed (205) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +818 -19
  3. data/bin/MANIFEST +38 -0
  4. data/bin/META.json +1 -1
  5. data/bin/META.yml +1 -1
  6. data/bin/README +48 -44
  7. data/bin/arg_files/exif2xmp.args +4 -1
  8. data/bin/arg_files/gps2xmp.args +4 -1
  9. data/bin/arg_files/iptcCore.args +8 -0
  10. data/bin/arg_files/xmp2exif.args +4 -1
  11. data/bin/arg_files/xmp2gps.args +4 -1
  12. data/bin/config_files/dji.config +131 -0
  13. data/bin/config_files/example.config +6 -2
  14. data/bin/config_files/gps2utm.config +256 -256
  15. data/bin/config_files/nksc.config +146 -0
  16. data/bin/config_files/picasa_faces.config +382 -382
  17. data/bin/exiftool +688 -408
  18. data/bin/fmt_files/gpx.fmt +10 -6
  19. data/bin/fmt_files/gpx_wpt.fmt +10 -6
  20. data/bin/fmt_files/kml.fmt +8 -5
  21. data/bin/lib/File/RandomAccess.pm +48 -8
  22. data/bin/lib/File/RandomAccess.pod +21 -2
  23. data/bin/lib/Image/ExifTool.pm +645 -256
  24. data/bin/lib/Image/ExifTool.pod +219 -164
  25. data/bin/lib/Image/ExifTool/AES.pm +1 -1
  26. data/bin/lib/Image/ExifTool/AFCP.pm +3 -8
  27. data/bin/lib/Image/ExifTool/AIFF.pm +12 -4
  28. data/bin/lib/Image/ExifTool/APE.pm +1 -1
  29. data/bin/lib/Image/ExifTool/APP12.pm +1 -1
  30. data/bin/lib/Image/ExifTool/ASF.pm +19 -6
  31. data/bin/lib/Image/ExifTool/Apple.pm +13 -5
  32. data/bin/lib/Image/ExifTool/Audible.pm +1 -1
  33. data/bin/lib/Image/ExifTool/BMP.pm +1 -1
  34. data/bin/lib/Image/ExifTool/BPG.pm +17 -15
  35. data/bin/lib/Image/ExifTool/BZZ.pm +1 -1
  36. data/bin/lib/Image/ExifTool/BigTIFF.pm +30 -15
  37. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +103 -52
  38. data/bin/lib/Image/ExifTool/Canon.pm +684 -112
  39. data/bin/lib/Image/ExifTool/CanonCustom.pm +119 -9
  40. data/bin/lib/Image/ExifTool/CanonRaw.pm +1 -1
  41. data/bin/lib/Image/ExifTool/CanonVRD.pm +13 -26
  42. data/bin/lib/Image/ExifTool/CaptureOne.pm +1 -1
  43. data/bin/lib/Image/ExifTool/Casio.pm +1 -1
  44. data/bin/lib/Image/ExifTool/Charset.pm +1 -1
  45. data/bin/lib/Image/ExifTool/DICOM.pm +12 -5
  46. data/bin/lib/Image/ExifTool/DJI.pm +51 -3
  47. data/bin/lib/Image/ExifTool/DNG.pm +15 -8
  48. data/bin/lib/Image/ExifTool/DPX.pm +1 -1
  49. data/bin/lib/Image/ExifTool/DV.pm +1 -1
  50. data/bin/lib/Image/ExifTool/DarwinCore.pm +63 -23
  51. data/bin/lib/Image/ExifTool/DjVu.pm +4 -2
  52. data/bin/lib/Image/ExifTool/EXE.pm +30 -6
  53. data/bin/lib/Image/ExifTool/Exif.pm +351 -109
  54. data/bin/lib/Image/ExifTool/FITS.pm +148 -0
  55. data/bin/lib/Image/ExifTool/FLAC.pm +2 -2
  56. data/bin/lib/Image/ExifTool/FLIF.pm +1 -1
  57. data/bin/lib/Image/ExifTool/FLIR.pm +109 -13
  58. data/bin/lib/Image/ExifTool/Fixup.pm +1 -1
  59. data/bin/lib/Image/ExifTool/Flash.pm +3 -3
  60. data/bin/lib/Image/ExifTool/FlashPix.pm +433 -9
  61. data/bin/lib/Image/ExifTool/Font.pm +2 -2
  62. data/bin/lib/Image/ExifTool/FotoStation.pm +1 -1
  63. data/bin/lib/Image/ExifTool/FujiFilm.pm +336 -16
  64. data/bin/lib/Image/ExifTool/GE.pm +1 -1
  65. data/bin/lib/Image/ExifTool/GIF.pm +5 -7
  66. data/bin/lib/Image/ExifTool/GIMP.pm +39 -3
  67. data/bin/lib/Image/ExifTool/GPS.pm +48 -22
  68. data/bin/lib/Image/ExifTool/GeoTiff.pm +23 -23
  69. data/bin/lib/Image/ExifTool/Geotag.pm +80 -45
  70. data/bin/lib/Image/ExifTool/GoPro.pm +709 -0
  71. data/bin/lib/Image/ExifTool/H264.pm +40 -18
  72. data/bin/lib/Image/ExifTool/HP.pm +1 -1
  73. data/bin/lib/Image/ExifTool/HTML.pm +19 -12
  74. data/bin/lib/Image/ExifTool/HtmlDump.pm +37 -26
  75. data/bin/lib/Image/ExifTool/ICC_Profile.pm +297 -23
  76. data/bin/lib/Image/ExifTool/ID3.pm +12 -7
  77. data/bin/lib/Image/ExifTool/IPTC.pm +48 -19
  78. data/bin/lib/Image/ExifTool/ISO.pm +1 -1
  79. data/bin/lib/Image/ExifTool/ITC.pm +1 -1
  80. data/bin/lib/Image/ExifTool/Import.pm +13 -9
  81. data/bin/lib/Image/ExifTool/InDesign.pm +3 -5
  82. data/bin/lib/Image/ExifTool/JPEG.pm +22 -11
  83. data/bin/lib/Image/ExifTool/JPEGDigest.pm +1 -1
  84. data/bin/lib/Image/ExifTool/JSON.pm +3 -3
  85. data/bin/lib/Image/ExifTool/JVC.pm +1 -1
  86. data/bin/lib/Image/ExifTool/Jpeg2000.pm +2 -2
  87. data/bin/lib/Image/ExifTool/Kodak.pm +1233 -58
  88. data/bin/lib/Image/ExifTool/KyoceraRaw.pm +1 -1
  89. data/bin/lib/Image/ExifTool/LNK.pm +1 -1
  90. data/bin/lib/Image/ExifTool/Lang/cs.pm +1 -1
  91. data/bin/lib/Image/ExifTool/Lang/de.pm +33 -24
  92. data/bin/lib/Image/ExifTool/Lang/en_ca.pm +64 -2
  93. data/bin/lib/Image/ExifTool/Lang/en_gb.pm +64 -2
  94. data/bin/lib/Image/ExifTool/Lang/es.pm +8 -4
  95. data/bin/lib/Image/ExifTool/Lang/fi.pm +46 -4
  96. data/bin/lib/Image/ExifTool/Lang/fr.pm +5 -3
  97. data/bin/lib/Image/ExifTool/Lang/it.pm +6 -3
  98. data/bin/lib/Image/ExifTool/Lang/ja.pm +15 -3
  99. data/bin/lib/Image/ExifTool/Lang/ko.pm +5 -2
  100. data/bin/lib/Image/ExifTool/Lang/nl.pm +6 -3
  101. data/bin/lib/Image/ExifTool/Lang/pl.pm +2 -2
  102. data/bin/lib/Image/ExifTool/Lang/ru.pm +1 -1
  103. data/bin/lib/Image/ExifTool/Lang/sv.pm +1 -1
  104. data/bin/lib/Image/ExifTool/Lang/tr.pm +4 -2
  105. data/bin/lib/Image/ExifTool/Lang/zh_cn.pm +1 -1
  106. data/bin/lib/Image/ExifTool/Lang/zh_tw.pm +1 -1
  107. data/bin/lib/Image/ExifTool/Leaf.pm +1 -1
  108. data/bin/lib/Image/ExifTool/Lytro.pm +4 -8
  109. data/bin/lib/Image/ExifTool/M2TS.pm +10 -9
  110. data/bin/lib/Image/ExifTool/MIE.pm +12 -8
  111. data/bin/lib/Image/ExifTool/MIEUnits.pod +1 -1
  112. data/bin/lib/Image/ExifTool/MIFF.pm +1 -1
  113. data/bin/lib/Image/ExifTool/MNG.pm +1 -1
  114. data/bin/lib/Image/ExifTool/MOI.pm +1 -1
  115. data/bin/lib/Image/ExifTool/MPC.pm +1 -1
  116. data/bin/lib/Image/ExifTool/MPEG.pm +2 -3
  117. data/bin/lib/Image/ExifTool/MPF.pm +6 -6
  118. data/bin/lib/Image/ExifTool/MWG.pm +4 -4
  119. data/bin/lib/Image/ExifTool/MXF.pm +2 -2
  120. data/bin/lib/Image/ExifTool/MacOS.pm +184 -34
  121. data/bin/lib/Image/ExifTool/MakerNotes.pm +101 -18
  122. data/bin/lib/Image/ExifTool/Matroska.pm +1 -1
  123. data/bin/lib/Image/ExifTool/Microsoft.pm +5 -3
  124. data/bin/lib/Image/ExifTool/Minolta.pm +89 -62
  125. data/bin/lib/Image/ExifTool/MinoltaRaw.pm +1 -1
  126. data/bin/lib/Image/ExifTool/Motorola.pm +1 -1
  127. data/bin/lib/Image/ExifTool/Nikon.pm +1511 -380
  128. data/bin/lib/Image/ExifTool/NikonCapture.pm +1 -1
  129. data/bin/lib/Image/ExifTool/NikonCustom.pm +2758 -2935
  130. data/bin/lib/Image/ExifTool/Nintendo.pm +1 -1
  131. data/bin/lib/Image/ExifTool/OOXML.pm +1 -1
  132. data/bin/lib/Image/ExifTool/Ogg.pm +1 -1
  133. data/bin/lib/Image/ExifTool/Olympus.pm +47 -8
  134. data/bin/lib/Image/ExifTool/OpenEXR.pm +1 -1
  135. data/bin/lib/Image/ExifTool/Opus.pm +1 -1
  136. data/bin/lib/Image/ExifTool/PCX.pm +138 -0
  137. data/bin/lib/Image/ExifTool/PDF.pm +58 -42
  138. data/bin/lib/Image/ExifTool/PGF.pm +1 -1
  139. data/bin/lib/Image/ExifTool/PICT.pm +1 -1
  140. data/bin/lib/Image/ExifTool/PLIST.pm +12 -5
  141. data/bin/lib/Image/ExifTool/PLUS.pm +1 -1
  142. data/bin/lib/Image/ExifTool/PNG.pm +108 -10
  143. data/bin/lib/Image/ExifTool/PPM.pm +3 -3
  144. data/bin/lib/Image/ExifTool/PSP.pm +1 -1
  145. data/bin/lib/Image/ExifTool/Palm.pm +1 -1
  146. data/bin/lib/Image/ExifTool/Panasonic.pm +299 -31
  147. data/bin/lib/Image/ExifTool/PanasonicRaw.pm +201 -19
  148. data/bin/lib/Image/ExifTool/Pentax.pm +164 -143
  149. data/bin/lib/Image/ExifTool/PhaseOne.pm +12 -5
  150. data/bin/lib/Image/ExifTool/PhotoCD.pm +9 -10
  151. data/bin/lib/Image/ExifTool/PhotoMechanic.pm +1 -1
  152. data/bin/lib/Image/ExifTool/Photoshop.pm +230 -60
  153. data/bin/lib/Image/ExifTool/PostScript.pm +29 -4
  154. data/bin/lib/Image/ExifTool/PrintIM.pm +1 -1
  155. data/bin/lib/Image/ExifTool/Qualcomm.pm +2 -2
  156. data/bin/lib/Image/ExifTool/QuickTime.pm +1539 -279
  157. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +1857 -0
  158. data/bin/lib/Image/ExifTool/README +84 -46
  159. data/bin/lib/Image/ExifTool/RIFF.pm +116 -23
  160. data/bin/lib/Image/ExifTool/RSRC.pm +1 -1
  161. data/bin/lib/Image/ExifTool/RTF.pm +6 -4
  162. data/bin/lib/Image/ExifTool/Radiance.pm +1 -1
  163. data/bin/lib/Image/ExifTool/Rawzor.pm +3 -2
  164. data/bin/lib/Image/ExifTool/Real.pm +1 -1
  165. data/bin/lib/Image/ExifTool/Reconyx.pm +261 -7
  166. data/bin/lib/Image/ExifTool/Red.pm +325 -0
  167. data/bin/lib/Image/ExifTool/Ricoh.pm +3 -7
  168. data/bin/lib/Image/ExifTool/Samsung.pm +95 -25
  169. data/bin/lib/Image/ExifTool/Sanyo.pm +1 -1
  170. data/bin/lib/Image/ExifTool/Scalado.pm +1 -1
  171. data/bin/lib/Image/ExifTool/Shift.pl +26 -12
  172. data/bin/lib/Image/ExifTool/Shortcuts.pm +9 -2
  173. data/bin/lib/Image/ExifTool/Sigma.pm +36 -30
  174. data/bin/lib/Image/ExifTool/SigmaRaw.pm +3 -8
  175. data/bin/lib/Image/ExifTool/Sony.pm +531 -177
  176. data/bin/lib/Image/ExifTool/SonyIDC.pm +63 -3
  177. data/bin/lib/Image/ExifTool/Stim.pm +2 -2
  178. data/bin/lib/Image/ExifTool/TagInfoXML.pm +23 -23
  179. data/bin/lib/Image/ExifTool/TagLookup.pm +6352 -5062
  180. data/bin/lib/Image/ExifTool/TagNames.pod +3024 -565
  181. data/bin/lib/Image/ExifTool/Theora.pm +1 -1
  182. data/bin/lib/Image/ExifTool/Torrent.pm +2 -2
  183. data/bin/lib/Image/ExifTool/Unknown.pm +1 -1
  184. data/bin/lib/Image/ExifTool/VCard.pm +47 -9
  185. data/bin/lib/Image/ExifTool/Validate.pm +391 -99
  186. data/bin/lib/Image/ExifTool/Vorbis.pm +1 -1
  187. data/bin/lib/Image/ExifTool/WTV.pm +319 -0
  188. data/bin/lib/Image/ExifTool/WriteCanonRaw.pl +1 -1
  189. data/bin/lib/Image/ExifTool/WriteExif.pl +91 -18
  190. data/bin/lib/Image/ExifTool/WriteIPTC.pl +6 -6
  191. data/bin/lib/Image/ExifTool/WritePDF.pl +13 -12
  192. data/bin/lib/Image/ExifTool/WritePNG.pl +1 -1
  193. data/bin/lib/Image/ExifTool/WritePhotoshop.pl +1 -1
  194. data/bin/lib/Image/ExifTool/WritePostScript.pl +2 -2
  195. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +764 -121
  196. data/bin/lib/Image/ExifTool/WriteXMP.pl +176 -67
  197. data/bin/lib/Image/ExifTool/Writer.pl +490 -246
  198. data/bin/lib/Image/ExifTool/XMP.pm +216 -76
  199. data/bin/lib/Image/ExifTool/XMP2.pl +54 -10
  200. data/bin/lib/Image/ExifTool/XMPStruct.pl +14 -11
  201. data/bin/lib/Image/ExifTool/ZIP.pm +60 -15
  202. data/bin/lib/Image/ExifTool/iWork.pm +12 -5
  203. data/bin/perl-Image-ExifTool.spec +46 -44
  204. data/lib/exiftool_vendored/version.rb +1 -1
  205. metadata +14 -4
@@ -25,6 +25,7 @@
25
25
  # 10) http://www.adobe.com/devnet/xmp/pdfs/XMPSpecificationPart2.pdf (Oct 2008)
26
26
  # 11) http://www.extensis.com/en/support/kb_article.jsp?articleNumber=6102211
27
27
  # 12) http://www.cipa.jp/std/documents/e/DC-010-2012_E.pdf
28
+ # 13) http://www.cipa.jp/std/documents/e/DC-010-2017_E.pdf
28
29
  #
29
30
  # Notes: - Property qualifiers are handled as if they were separate
30
31
  # properties (with no associated namespace).
@@ -48,7 +49,7 @@ use Image::ExifTool::Exif;
48
49
  use Image::ExifTool::GPS;
49
50
  require Exporter;
50
51
 
51
- $VERSION = '3.07';
52
+ $VERSION = '3.22';
52
53
  @ISA = qw(Exporter);
53
54
  @EXPORT_OK = qw(EscapeXML UnescapeXML);
54
55
 
@@ -61,7 +62,8 @@ sub EncodeBase64($;$);
61
62
  sub SaveBlankInfo($$$;$);
62
63
  sub ProcessBlankInfo($$$;$);
63
64
  sub ValidateXMP($;$);
64
- sub UnescapeChar($$);
65
+ sub ValidateProperty($$);
66
+ sub UnescapeChar($$;$);
65
67
  sub AddFlattenedTags($;$$);
66
68
  sub FormatXMPDate($);
67
69
  sub ConvertRational($);
@@ -173,8 +175,10 @@ my %xmpNS = (
173
175
  GPano => 'http://ns.google.com/photos/1.0/panorama/',
174
176
  GSpherical=> 'http://ns.google.com/videos/1.0/spherical/',
175
177
  GDepth => 'http://ns.google.com/photos/1.0/depthmap/',
178
+ GFocus => 'http://ns.google.com/photos/1.0/focus/',
176
179
  dwc => 'http://rs.tdwg.org/dwc/index.htm',
177
180
  GettyImagesGIFT => 'http://xmp.gettyimages.com/gift/1.0/',
181
+ LImage => 'http://ns.leiainc.com/photos/1.0/image/',
178
182
  );
179
183
 
180
184
  # build reverse namespace lookup
@@ -203,6 +207,7 @@ my %uri2ns;
203
207
  # NOTE: Do NOT put "Groups" here because Groups hash must not be common!
204
208
  Writable => 'date',
205
209
  Shift => 'Time',
210
+ Validate => 'ValidateXMPDate($val)',
206
211
  PrintConv => '$self->ConvertDateTime($val)',
207
212
  PrintConvInv => '$self->InverseDateTime($val,undef,1)',
208
213
  );
@@ -737,6 +742,10 @@ my %sRetouchArea = (
737
742
  Name => 'GDepth',
738
743
  SubDirectory => { TagTable => 'Image::ExifTool::XMP::GDepth' },
739
744
  },
745
+ GFocus => {
746
+ Name => 'GFocus',
747
+ SubDirectory => { TagTable => 'Image::ExifTool::XMP::GFocus' },
748
+ },
740
749
  dwc => {
741
750
  Name => 'dwc',
742
751
  SubDirectory => { TagTable => 'Image::ExifTool::DarwinCore::Main' },
@@ -749,6 +758,10 @@ my %sRetouchArea = (
749
758
  Name => 'drone-dji',
750
759
  SubDirectory => { TagTable => 'Image::ExifTool::DJI::XMP' },
751
760
  },
761
+ LImage => {
762
+ Name => 'LImage',
763
+ SubDirectory => { TagTable => 'Image::ExifTool::XMP::LImage' },
764
+ },
752
765
  );
753
766
 
754
767
  # hack to allow XML containing Dublin Core metadata to be handled like XMP (eg. EPUB - see ZIP.pm)
@@ -1439,6 +1452,7 @@ my %sPantryItem = (
1439
1452
  PerspectiveX => { Writable => 'real' },
1440
1453
  PerspectiveY => { Writable => 'real' },
1441
1454
  UprightFourSegmentsCount => { Writable => 'integer' },
1455
+ AutoTone => { Writable => 'boolean' },
1442
1456
  );
1443
1457
 
1444
1458
  # Tiff namespace properties (tiff)
@@ -1450,7 +1464,7 @@ my %sPantryItem = (
1450
1464
  TABLE_DESC => 'XMP TIFF',
1451
1465
  NOTES => q{
1452
1466
  EXIF namespace for TIFF tags. See
1453
- L<http://www.cipa.jp/std/documents/e/DC-010-2012_E.pdf> for the
1467
+ L<http://www.cipa.jp/std/documents/e/DC-010-2017_E.pdf> for the
1454
1468
  specification.
1455
1469
  },
1456
1470
  ImageWidth => { Writable => 'integer' },
@@ -1541,7 +1555,7 @@ my %sPantryItem = (
1541
1555
  PRIORITY => 0, # not as reliable as actual EXIF tags
1542
1556
  NOTES => q{
1543
1557
  EXIF namespace for EXIF tags. See
1544
- L<http://www.cipa.jp/std/documents/e/DC-010-2012_E.pdf> for the
1558
+ L<http://www.cipa.jp/std/documents/e/DC-010-2017_E.pdf> for the
1545
1559
  specification.
1546
1560
  },
1547
1561
  ExifVersion => { },
@@ -1994,8 +2008,8 @@ my %sPantryItem = (
1994
2008
  NAMESPACE => 'exifEX',
1995
2009
  PRIORITY => 0, # not as reliable as actual EXIF tags
1996
2010
  NOTES => q{
1997
- EXIF tags added by the EXIF 2.3 for XMP specification (see
1998
- L<http://www.cipa.jp/std/documents/e/DC-010-2012_E.pdf>).
2011
+ EXIF tags added by the EXIF 2.31 for XMP specification (see
2012
+ L<http://www.cipa.jp/std/documents/e/DC-010-2017_E.pdf>).
1999
2013
  },
2000
2014
  Gamma => { Writable => 'rational' },
2001
2015
  PhotographicSensitivity => { Writable => 'integer' },
@@ -2063,6 +2077,13 @@ my %sPantryItem = (
2063
2077
  THM => 'THM - DCF thumbnail file',
2064
2078
  },
2065
2079
  },
2080
+ # new in Exif 2.31
2081
+ Temperature => { Writable => 'rational', Name => 'AmbientTemperature' },
2082
+ Humidity => { Writable => 'rational' },
2083
+ Pressure => { Writable => 'rational' },
2084
+ WaterDepth => { Writable => 'rational' },
2085
+ Acceleration => { Writable => 'rational' },
2086
+ CameraElevationAngle=> { Writable => 'rational' },
2066
2087
  );
2067
2088
 
2068
2089
  # Auxiliary namespace properties (aux) - not fully documented (ref PH)
@@ -2198,27 +2219,43 @@ my %sPantryItem = (
2198
2219
  # (used to set EXIF GPS position from XMP tags)
2199
2220
  GPSLatitudeRef => {
2200
2221
  Require => 'XMP:GPSLatitude',
2222
+ Inhibit => 'GPSLatitudeRef',
2201
2223
  ValueConv => q{
2202
2224
  IsFloat($val[0]) and return $val[0] < 0 ? "S" : "N";
2203
2225
  $val[0] =~ /^.*([NS])/;
2204
2226
  return $1;
2205
2227
  },
2206
- PrintConv => {
2207
- N => 'North',
2208
- S => 'South',
2209
- },
2228
+ PrintConv => { N => 'North', S => 'South' },
2210
2229
  },
2211
2230
  GPSLongitudeRef => {
2212
2231
  Require => 'XMP:GPSLongitude',
2232
+ Inhibit => 'GPSLongitudeRef',
2213
2233
  ValueConv => q{
2214
2234
  IsFloat($val[0]) and return $val[0] < 0 ? "W" : "E";
2215
2235
  $val[0] =~ /^.*([EW])/;
2216
2236
  return $1;
2217
2237
  },
2218
- PrintConv => {
2219
- E => 'East',
2220
- W => 'West',
2238
+ PrintConv => { E => 'East', W => 'West' },
2239
+ },
2240
+ GPSDestLatitudeRef => {
2241
+ Require => 'XMP:GPSDestLatitude',
2242
+ Inhibit => 'GPSDestLatitudeRef',
2243
+ ValueConv => q{
2244
+ IsFloat($val[0]) and return $val[0] < 0 ? "S" : "N";
2245
+ $val[0] =~ /^.*([NS])/;
2246
+ return $1;
2247
+ },
2248
+ PrintConv => { N => 'North', S => 'South' },
2249
+ },
2250
+ GPSDestLongitudeRef => {
2251
+ Require => 'XMP:GPSDestLongitude',
2252
+ Inhibit => 'GPSDestLongitudeRef',
2253
+ ValueConv => q{
2254
+ IsFloat($val[0]) and return $val[0] < 0 ? "W" : "E";
2255
+ $val[0] =~ /^.*([EW])/;
2256
+ return $1;
2221
2257
  },
2258
+ PrintConv => { E => 'East', W => 'West' },
2222
2259
  },
2223
2260
  LensID => {
2224
2261
  Notes => 'attempt to convert numerical XMP-aux:LensID stored by Adobe applications',
@@ -2301,13 +2338,14 @@ sub EscapeXML($)
2301
2338
  # Unescape XML character references (entities and numerical)
2302
2339
  # Inputs: 0) string to be unescaped
2303
2340
  # 1) optional hash reference to convert entity names to numbers
2341
+ # 2) optional character encoding
2304
2342
  # Returns: unescaped string
2305
2343
  my %charNum = ('quot'=>34, 'amp'=>38, 'apos'=>39, 'lt'=>60, 'gt'=>62);
2306
- sub UnescapeXML($;$)
2344
+ sub UnescapeXML($;$$)
2307
2345
  {
2308
- my ($str, $conv) = @_;
2346
+ my ($str, $conv, $enc) = @_;
2309
2347
  $conv = \%charNum unless $conv;
2310
- $str =~ s/&(#?\w+);/UnescapeChar($1,$conv)/sge;
2348
+ $str =~ s/&(#?\w+);/UnescapeChar($1,$conv,$enc)/sge;
2311
2349
  return $str;
2312
2350
  }
2313
2351
 
@@ -2345,10 +2383,11 @@ sub FullUnescapeXML($)
2345
2383
  # Convert XML character reference to UTF-8
2346
2384
  # Inputs: 0) XML character reference stripped of the '&' and ';' (eg. 'quot', '#34', '#x22')
2347
2385
  # 1) hash reference for looking up character numbers by name
2386
+ # 2) optional character encoding (default 'UTF8')
2348
2387
  # Returns: UTF-8 equivalent (or original character on conversion error)
2349
- sub UnescapeChar($$)
2388
+ sub UnescapeChar($$;$)
2350
2389
  {
2351
- my ($ch, $conv) = @_;
2390
+ my ($ch, $conv, $enc) = @_;
2352
2391
  my $val = $$conv{$ch};
2353
2392
  unless (defined $val) {
2354
2393
  if ($ch =~ /^#x([0-9a-fA-F]+)$/) {
@@ -2360,8 +2399,9 @@ sub UnescapeChar($$)
2360
2399
  }
2361
2400
  }
2362
2401
  return chr($val) if $val < 0x80; # simple ASCII
2363
- return pack('C0U', $val) if $] >= 5.006001;
2364
- return Image::ExifTool::PackUTF8($val);
2402
+ $val = $] >= 5.006001 ? pack('C0U', $val) : Image::ExifTool::PackUTF8($val);
2403
+ $val = Image::ExifTool::Decode(undef, $val, 'UTF8', undef, $enc) if $enc and $enc ne 'UTF8';
2404
+ return $val;
2365
2405
  }
2366
2406
 
2367
2407
  #------------------------------------------------------------------------------
@@ -2395,7 +2435,17 @@ sub IsUTF8($)
2395
2435
  # were required in the UTF-8 character
2396
2436
  $rtnVal = 2;
2397
2437
  }
2398
- return -1 unless $$strPt =~ /\G[\x80-\xbf]{$n}/g;
2438
+ return -1 unless $$strPt =~ /\G([\x80-\xbf]{$n})/g;
2439
+ # the following is ref https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c
2440
+ if ($n == 2) {
2441
+ return -1 if ($ch == 0xe0 and (ord($1) & 0xe0) == 0x80) or
2442
+ ($ch == 0xed and (ord($1) & 0xe0) == 0xa0) or
2443
+ ($ch == 0xef and ord($1) == 0xbf and
2444
+ (ord(substr $1, 1) & 0xfe) == 0xbe);
2445
+ } else {
2446
+ return -1 if ($ch == 0xf0 and (ord($1) & 0xf0) == 0x80) or
2447
+ ($ch == 0xf4 and ord($1) > 0x8f) or $ch > 0xf4;
2448
+ }
2399
2449
  last unless $$strPt =~ /([\x80-\xff])/g;
2400
2450
  }
2401
2451
  return $rtnVal;
@@ -2418,7 +2468,18 @@ sub FixUTF8($;$)
2418
2468
  # (see comments in IsUTF8() above)
2419
2469
  if ($ch >= 0xc2 and $ch < 0xf8) {
2420
2470
  my $n = $ch < 0xe0 ? 1 : ($ch < 0xf0 ? 2 : 3);
2421
- next if $$strPt =~ /\G[\x80-\xbf]{$n}/g;
2471
+ if ($$strPt =~ /\G([\x80-\xbf]{$n})/g) {
2472
+ next if $n == 1;
2473
+ if ($n == 2) {
2474
+ next unless ($ch == 0xe0 and (ord($1) & 0xe0) == 0x80) or
2475
+ ($ch == 0xed and (ord($1) & 0xe0) == 0xa0) or
2476
+ ($ch == 0xef and ord($1) == 0xbf and
2477
+ (ord(substr $1, 1) & 0xfe) == 0xbe);
2478
+ } else {
2479
+ next unless ($ch == 0xf0 and (ord($1) & 0xf0) == 0x80) or
2480
+ ($ch == 0xf4 and ord($1) > 0x8f) or $ch > 0xf4;
2481
+ }
2482
+ }
2422
2483
  }
2423
2484
  # replace bad character
2424
2485
  $bad = '?' unless defined $bad;
@@ -2480,6 +2541,7 @@ sub GetXMPTagID($;$$)
2480
2541
  my ($ns, $nm) = ($prop =~ /(.*?):(.*)/) ? ($1, $2) : ('', $prop);
2481
2542
  if ($ignoreNamespace{$ns} or $ignoreProp{$prop}) {
2482
2543
  # special case: don't ignore rdf numbered items
2544
+ # (not technically allowed in XMP, but used in RDF/XML)
2483
2545
  unless ($prop =~ /^rdf:(_\d+)$/) {
2484
2546
  # save list index if necessary for structures
2485
2547
  if ($structProps and @$structProps and $prop =~ /^rdf:li (\d+)$/) {
@@ -2544,7 +2606,7 @@ sub RegisterNamespace($)
2544
2606
  while (@ns) {
2545
2607
  $ns = pop @ns;
2546
2608
  if ($nsURI{$ns} and $nsURI{$ns} ne $$nsRef{$ns}) {
2547
- warn "User-defined namespace prefix '$ns' conflicts with existing namespace\n";
2609
+ warn "User-defined namespace prefix '${ns}' conflicts with existing namespace\n";
2548
2610
  }
2549
2611
  $nsURI{$ns} = $$nsRef{$ns};
2550
2612
  $uri2ns{$$nsRef{$ns}} = $ns;
@@ -3106,6 +3168,26 @@ NoLoop:
3106
3168
  my $key = $et->FoundTag($tagInfo, $val) or return 0;
3107
3169
  # save original components of rational numbers (used when copying)
3108
3170
  $$et{RATIONAL}{$key} = $rational if defined $rational;
3171
+ # allow read-only subdirectories (eg. embedded base64 XMP/IPTC in NKSC files)
3172
+ if ($$tagInfo{SubDirectory} and not $$et{IsWriting}) {
3173
+ my $subdir = $$tagInfo{SubDirectory};
3174
+ my $dataPt = ref $$et{VALUE}{$key} ? $$et{VALUE}{$key} : \$$et{VALUE}{$key};
3175
+ # process subdirectory information
3176
+ my %dirInfo = (
3177
+ DirName => $$subdir{DirName} || $$tagInfo{Name},
3178
+ DataPt => $dataPt,
3179
+ DirLen => length $$dataPt,
3180
+ IsExtended => 1, # (hack to avoid Duplicate warning for embedded XMP)
3181
+ );
3182
+ my $oldOrder = GetByteOrder();
3183
+ SetByteOrder($$subdir{ByteOrder}) if $$subdir{ByteOrder};
3184
+ my $oldNS = $$et{definedNS};
3185
+ delete $$et{definedNS};
3186
+ my $subTablePtr = GetTagTable($$subdir{TagTable}) || $tagTablePtr;
3187
+ $et->ProcessDirectory(\%dirInfo, $subTablePtr, $$subdir{ProcessProc});
3188
+ SetByteOrder($oldOrder);
3189
+ $$et{definedNS} = $oldNS;
3190
+ }
3109
3191
  # save structure/list information if necessary
3110
3192
  if (@structProps and (@structProps > 1 or defined $structProps[0][1]) and
3111
3193
  not $$et{NO_STRUCT})
@@ -3137,11 +3219,13 @@ NoLoop:
3137
3219
  # Returns: Number of contained XMP elements
3138
3220
  sub ParseXMPElement($$$;$$$$)
3139
3221
  {
3140
- my ($et, $tagTablePtr, $dataPt, $start, $end, $propListPt, $blankInfo) = @_;
3222
+ local $_;
3223
+ my ($et, $tagTablePtr, $dataPt, $start, $end, $propList, $blankInfo) = @_;
3141
3224
  my ($count, $nItems) = (0, 0);
3142
3225
  my $isWriting = $$et{XMP_CAPTURE};
3143
3226
  my $isSVG = $$et{XMP_IS_SVG};
3144
3227
  my $saveNS; # save xlatNS lookup if changed for the scope of this element
3228
+ my (%definedNS, %usedNS); # namespaces defined and used in this scope
3145
3229
 
3146
3230
  # get our parse procs
3147
3231
  my ($attrProc, $foundProc);
@@ -3153,7 +3237,7 @@ sub ParseXMPElement($$$;$$$$)
3153
3237
  }
3154
3238
  $start or $start = 0;
3155
3239
  $end or $end = length $$dataPt;
3156
- $propListPt or $propListPt = [ ];
3240
+ $propList or $propList = [ ];
3157
3241
 
3158
3242
  my $processBlankInfo;
3159
3243
  # create empty blank node information hash if necessary
@@ -3225,6 +3309,8 @@ sub ParseXMPElement($$$;$$$$)
3225
3309
  if ($1 eq 'xmlns') {
3226
3310
  my $ns = substr($attr, 6);
3227
3311
  my $stdNS = $uri2ns{$val};
3312
+ # keep track of namespace prefixes defined in this scope (for Validate)
3313
+ $$et{definedNS}{$ns} = $definedNS{$ns} = 1 unless $$et{definedNS}{$ns};
3228
3314
  unless ($stdNS) {
3229
3315
  my $try = $val;
3230
3316
  # patch for Nikon NX2 URI bug for Microsoft PhotoInfo namespace
@@ -3280,26 +3366,36 @@ sub ParseXMPElement($$$;$$$$)
3280
3366
  # use the new namespace prefix
3281
3367
  $$xlatNS{$ns} = $newNS;
3282
3368
  $attr = 'xmlns:' . $newNS;
3369
+ # must go through previous attributes and change prefixes if necessary
3370
+ foreach (@attrs) {
3371
+ next unless /(.*?):/ and $1 eq $ns and $1 ne $newNS;
3372
+ my $newAttr = $newNS . substr($_, length($ns));
3373
+ $attrs{$newAttr} = $attrs{$_};
3374
+ delete $attrs{$_};
3375
+ $_ = $newAttr;
3376
+ }
3283
3377
  } else {
3284
3378
  delete $$xlatNS{$ns};
3285
3379
  }
3286
3380
  }
3287
- } elsif ($$xlatNS{$1}) {
3288
- $attr = $$xlatNS{$1} . substr($attr, length($1));
3381
+ } else {
3382
+ $attr = $$xlatNS{$1} . substr($attr, length($1)) if $$xlatNS{$1};
3383
+ $usedNS{$1} = 1;
3289
3384
  }
3290
3385
  }
3291
3386
  push @attrs, $attr; # preserve order
3292
3387
  $attrs{$attr} = $val;
3293
3388
  }
3294
- # tame wild namespace prefixes (patch for Microsoft stupidity)
3295
- if ($prop =~ /(.*?):/ and $$xlatNS{$1}) {
3296
- $prop = $$xlatNS{$1} . substr($prop, length($1));
3389
+ if ($prop =~ /(.*?):/) {
3390
+ $usedNS{$1} = 1;
3391
+ # tame wild namespace prefixes (patch for Microsoft stupidity)
3392
+ $prop = $$xlatNS{$1} . substr($prop, length($1)) if $$xlatNS{$1};
3297
3393
  }
3298
3394
 
3299
3395
  if ($prop eq 'rdf:li') {
3300
3396
  # impose a reasonable maximum on the number of items in a list
3301
3397
  if ($nItems == 1000) {
3302
- my ($tg,$ns) = GetXMPTagID($propListPt);
3398
+ my ($tg,$ns) = GetXMPTagID($propList);
3303
3399
  if ($isWriting) {
3304
3400
  $et->Warn("Excessive number of items for $ns:$tg. Processing may be slow", 1);
3305
3401
  } elsif (not $$et{OPTIONS}{IgnoreMinorErrors}) {
@@ -3318,17 +3414,18 @@ sub ParseXMPElement($$$;$$$$)
3318
3414
  $prop .= ' ' . length($nItems) . $nItems;
3319
3415
  # reset LIST_TAGS at the start of the outtermost list
3320
3416
  # (avoids accumulating incorrectly-written elements in a correctly-written list)
3321
- if (not $nItems and not grep /^rdf:li /, @$propListPt) {
3417
+ if (not $nItems and not grep /^rdf:li /, @$propList) {
3322
3418
  $$et{LIST_TAGS} = { };
3323
3419
  }
3324
3420
  ++$nItems;
3325
3421
  } elsif ($prop eq 'rdf:Description') {
3326
3422
  # remove unnecessary rdf:Description elements since parseType='Resource'
3327
3423
  # is more efficient (also necessary to make property path consistent)
3328
- $parseResource = 1 if grep /^rdf:Description$/, @$propListPt;
3424
+ $parseResource = 1 if grep /^rdf:Description$/, @$propList;
3329
3425
  } elsif ($prop eq 'xmp:xmpmeta') {
3330
3426
  # patch MicrosoftPhoto unconformity
3331
3427
  $prop = 'x:xmpmeta';
3428
+ $et->Warn('Wrong namespace for xmpmeta') if $$et{XmpValidate};
3332
3429
  }
3333
3430
 
3334
3431
  # hook for special parsing of attributes
@@ -3350,19 +3447,19 @@ sub ParseXMPElement($$$;$$$$)
3350
3447
  }
3351
3448
 
3352
3449
  # push this property name onto our hierarchy list
3353
- push @$propListPt, $prop unless $parseResource;
3450
+ push @$propList, $prop unless $parseResource;
3354
3451
 
3355
3452
  if ($isSVG) {
3356
3453
  # ignore everything but top level SVG tags and metadata unless Unknown set
3357
3454
  unless ($$et{OPTIONS}{Unknown} > 1 or $$et{OPTIONS}{Verbose}) {
3358
- if (@$propListPt > 1 and $$propListPt[1] !~ /\b(metadata|desc|title)$/) {
3359
- pop @$propListPt;
3455
+ if (@$propList > 1 and $$propList[1] !~ /\b(metadata|desc|title)$/) {
3456
+ pop @$propList;
3360
3457
  next;
3361
3458
  }
3362
3459
  }
3363
3460
  if ($prop eq 'svg' or $prop eq 'metadata') {
3364
3461
  # add svg namespace prefix if missing to ignore these entries in the tag name
3365
- $$propListPt[-1] = "svg:$prop";
3462
+ $$propList[-1] = "svg:$prop";
3366
3463
  }
3367
3464
  }
3368
3465
 
@@ -3387,6 +3484,21 @@ sub ParseXMPElement($$$;$$$$)
3387
3484
  $ns = '';
3388
3485
  $name = $propName;
3389
3486
  }
3487
+ if ($propName eq 'rdf:about') {
3488
+ if (not $$et{XmpAbout}) {
3489
+ $$et{XmpAbout} = $attrs{$shortName};
3490
+ } elsif ($$et{XmpAbout} ne $attrs{$shortName}) {
3491
+ if ($isWriting) {
3492
+ my $str = "Different 'rdf:about' attributes not handled";
3493
+ unless ($$et{WARNED_ONCE}{$str}) {
3494
+ $et->Error($str, 1);
3495
+ $$et{WARNED_ONCE}{$str} = 1;
3496
+ }
3497
+ } elsif ($$et{XmpValidate}) {
3498
+ $et->WarnOnce("Different 'rdf:about' attributes");
3499
+ }
3500
+ }
3501
+ }
3390
3502
  if ($isWriting) {
3391
3503
  # keep track of our namespaces when writing
3392
3504
  if ($ns eq 'xmlns') {
@@ -3398,14 +3510,6 @@ sub ParseXMPElement($$$;$$$$)
3398
3510
  delete $attrs{$shortName}; # (handled by namespace logic)
3399
3511
  next;
3400
3512
  } elsif ($recognizedAttrs{$propName}) {
3401
- # save UUID to use same ID when writing
3402
- if ($propName eq 'rdf:about') {
3403
- if (not $$et{XMP_ABOUT}) {
3404
- $$et{XMP_ABOUT} = $attrs{$shortName};
3405
- } elsif ($$et{XMP_ABOUT} ne $attrs{$shortName}) {
3406
- $et->Error("Different 'rdf:about' attributes not handled", 1);
3407
- }
3408
- }
3409
3513
  next;
3410
3514
  }
3411
3515
  }
@@ -3423,25 +3527,26 @@ sub ParseXMPElement($$$;$$$$)
3423
3527
  next;
3424
3528
  }
3425
3529
  delete $attrs{$shortName}; # don't re-use this attribute
3426
- push @$propListPt, $propName;
3530
+ push @$propList, $propName;
3427
3531
  # save this shorthand XMP property
3428
3532
  if (defined $nodeID) {
3429
- SaveBlankInfo($blankInfo, $propListPt, $shortVal);
3533
+ SaveBlankInfo($blankInfo, $propList, $shortVal);
3430
3534
  } elsif ($isWriting) {
3431
- CaptureXMP($et, $propListPt, $shortVal);
3535
+ CaptureXMP($et, $propList, $shortVal);
3432
3536
  } else {
3433
- &$foundProc($et, $tagTablePtr, $propListPt, $shortVal);
3537
+ ValidateProperty($et, $propList) if $$et{XmpValidate};
3538
+ &$foundProc($et, $tagTablePtr, $propList, $shortVal);
3434
3539
  }
3435
- pop @$propListPt;
3540
+ pop @$propList;
3436
3541
  $shorthand = 1;
3437
3542
  }
3438
3543
  if ($isWriting) {
3439
3544
  if (ParseXMPElement($et, $tagTablePtr, $dataPt, $valStart, $valEnd,
3440
- $propListPt, $blankInfo))
3545
+ $propList, $blankInfo))
3441
3546
  {
3442
3547
  # (no value since we found more properties within this one)
3443
3548
  # set an error on any ignored attributes here, because they will be lost
3444
- $$et{XMP_ERROR} = "Can't handle XMP attribute '$ignored'" if $ignored;
3549
+ $$et{XMP_ERROR} = "Can't handle XMP attribute '${ignored}'" if $ignored;
3445
3550
  } elsif (not $shorthand or $valEnd != $valStart) {
3446
3551
  $val = substr($$dataPt, $valStart, $valEnd - $valStart);
3447
3552
  # remove comments and whitespace from rdf:Description only
@@ -3449,16 +3554,16 @@ sub ParseXMPElement($$$;$$$$)
3449
3554
  $val =~ s/<!--.*?-->//g; $val =~ s/^\s+//; $val =~ s/\s+$//;
3450
3555
  }
3451
3556
  if (defined $nodeID) {
3452
- SaveBlankInfo($blankInfo, $propListPt, $val, \%attrs);
3557
+ SaveBlankInfo($blankInfo, $propList, $val, \%attrs);
3453
3558
  } else {
3454
- CaptureXMP($et, $propListPt, $val, \%attrs);
3559
+ CaptureXMP($et, $propList, $val, \%attrs);
3455
3560
  }
3456
3561
  }
3457
3562
  } else {
3458
3563
  # look for additional elements contained within this one
3459
3564
  if ($valStart == $valEnd or
3460
3565
  !ParseXMPElement($et, $tagTablePtr, $dataPt, $valStart, $valEnd,
3461
- $propListPt, $blankInfo))
3566
+ $propList, $blankInfo))
3462
3567
  {
3463
3568
  my $wasEmpty;
3464
3569
  unless (defined $val) {
@@ -3467,10 +3572,10 @@ sub ParseXMPElement($$$;$$$$)
3467
3572
  if ($prop eq 'rdf:Description' and $val) {
3468
3573
  $val =~ s/<!--.*?-->//g; $val =~ s/^\s+//; $val =~ s/\s+$//;
3469
3574
  }
3470
- # if element value is empty, take value from 'resource' attribute
3471
- # (preferentially) or 'about' attribute (if no 'resource')
3472
- if ($val eq '' and ($attrs =~ /\bresource=(['"])(.*?)\1/ or
3473
- $attrs =~ /\babout=(['"])(.*?)\1/))
3575
+ # if element value is empty, take value from RDF 'value' or 'resource' attribute
3576
+ # (preferentially) or 'about' attribute (if no 'value' or 'resource')
3577
+ if ($val eq '' and ($attrs =~ /\brdf:(?:value|resource)=(['"])(.*?)\1/ or
3578
+ $attrs =~ /\brdf:about=(['"])(.*?)\1/))
3474
3579
  {
3475
3580
  $val = $2;
3476
3581
  $wasEmpty = 1;
@@ -3479,22 +3584,41 @@ sub ParseXMPElement($$$;$$$$)
3479
3584
  # there are no contained elements, so this must be a simple property value
3480
3585
  # (unless we already extracted shorthand values from this element)
3481
3586
  if (length $val or not $shorthand) {
3482
- my $lastProp = $$propListPt[-1];
3587
+ my $lastProp = $$propList[-1];
3483
3588
  if (defined $nodeID) {
3484
- SaveBlankInfo($blankInfo, $propListPt, $val);
3589
+ SaveBlankInfo($blankInfo, $propList, $val);
3485
3590
  } elsif ($lastProp eq 'rdf:type' and $wasEmpty) {
3486
3591
  # do not extract empty structure types (for now)
3487
3592
  } elsif ($lastProp =~ /^et:(desc|prt|val)$/ and ($count or $1 eq 'desc')) {
3488
3593
  # ignore et:desc, and et:val if preceded by et:prt
3489
3594
  --$count;
3490
3595
  } else {
3491
- &$foundProc($et, $tagTablePtr, $propListPt, $val, \%attrs);
3596
+ ValidateProperty($et, $propList) if $$et{XmpValidate};
3597
+ &$foundProc($et, $tagTablePtr, $propList, $val, \%attrs);
3492
3598
  }
3493
3599
  }
3494
3600
  }
3495
3601
  }
3496
- pop @$propListPt unless $parseResource;
3602
+ pop @$propList unless $parseResource;
3497
3603
  ++$count;
3604
+
3605
+ # validate namespace prefixes used at this level if necessary
3606
+ if ($$et{XmpValidate}) {
3607
+ foreach (sort keys %usedNS) {
3608
+ next if $$et{definedNS}{$_} or $_ eq 'xml';
3609
+ if (defined $$et{definedNS}{$_}) {
3610
+ $et->Warn("XMP namespace $_ is used out of scope");
3611
+ } else {
3612
+ $et->Warn("Undefined XMP namespace: $_");
3613
+ }
3614
+ $$et{definedNS}{$_} = -1; # (don't warn again for this namespace)
3615
+ }
3616
+ # reset namespaces that went out of scope
3617
+ $$et{definedNS}{$_} = 0 foreach keys %definedNS;
3618
+ undef %usedNS;
3619
+ undef %definedNS;
3620
+ }
3621
+
3498
3622
  last if $start >= $end;
3499
3623
  pos($$dataPt) = $start;
3500
3624
  $$dataPt =~ /\G\s+/gc; # skip white space after closing token
@@ -3540,19 +3664,30 @@ sub ProcessXMP($$;$)
3540
3664
  $$et{curURI} = { };
3541
3665
  $$et{curNS} = { };
3542
3666
  $$et{xlatNS} = { };
3667
+ $$et{definedNS} = { };
3668
+ delete $$et{XmpAbout};
3669
+ delete $$et{XmpValidate}; # don't validate by default
3543
3670
 
3544
3671
  # ignore non-standard XMP while in strict MWG compatibility mode
3545
- if (($Image::ExifTool::MWG::strict or $et->Options('Validate')) and not $$et{XMP_CAPTURE} and
3546
- $$et{FILE_TYPE} =~ /^(JPEG|TIFF|PSD)$/)
3672
+ if (($Image::ExifTool::MWG::strict or $$et{OPTIONS}{Validate}) and
3673
+ not ($$et{XMP_CAPTURE} or $$et{DOC_NUM}) and
3674
+ (($$dirInfo{DirName} || '') eq 'XMP' or $$et{FILE_TYPE} eq 'XMP'))
3547
3675
  {
3676
+ $$et{XmpValidate} = { } if $$et{OPTIONS}{Validate};
3548
3677
  my $path = $et->MetadataPath();
3549
- unless ($path =~ /^(JPEG-APP1-XMP|TIFF-IFD0-XMP|PSD-XMP)$/) {
3550
- if ($Image::ExifTool::MWG::strict) {
3551
- $et->Warn("Ignored non-standard XMP at $path");
3552
- return 1;
3553
- } else {
3554
- $et->Warn("Non-standard XMP at $path", 1);
3555
- }
3678
+ my $nonStd;
3679
+ if ($$et{FILE_TYPE} =~ /^(JPEG|TIFF|PSD)$/ and $path !~ /^(JPEG-APP1-XMP|TIFF-IFD0-XMP|PSD-XMP)$/) {
3680
+ $nonStd = 1;
3681
+ }
3682
+ if ($nonStd and $Image::ExifTool::MWG::strict) {
3683
+ $et->Warn("Ignored non-standard XMP at $path");
3684
+ return 1;
3685
+ }
3686
+ if ($nonStd) {
3687
+ $et->Warn("Non-standard XMP at $path", 1);
3688
+ } elsif (not $$dirInfo{IsExtended}) {
3689
+ $et->Warn("Duplicate XMP at $path") if $$et{DIR_COUNT}{XMP};
3690
+ $$et{DIR_COUNT}{XMP} = ($$et{DIR_COUNT}{XMP} || 0) + 1; # count standard XMP
3556
3691
  }
3557
3692
  }
3558
3693
  if ($dataPt) {
@@ -3563,7 +3698,7 @@ sub ProcessXMP($$;$)
3563
3698
  pos($$dataPt) = $dirStart;
3564
3699
  $double = $1 if $$dataPt =~ /\G((\0\0)?\xfe\xff|\xff\xfe(\0\0)?|\xef\xbb\xbf)\0*<\0*\?\0*x\0*p\0*a\0*c\0*k\0*e\0*t/g;
3565
3700
  } else {
3566
- my ($type, $buf2, $buf3);
3701
+ my ($type, $mime, $buf2, $buf3);
3567
3702
  # read information from XMP file
3568
3703
  my $raf = $$dirInfo{RAF} or return 0;
3569
3704
  $raf->Read($buff, 256) or return 0;
@@ -3603,6 +3738,7 @@ sub ProcessXMP($$;$)
3603
3738
  $bom = 1 if $1;
3604
3739
  if ($2 eq '<?xml') {
3605
3740
  if (defined $fmt and not $fmt and $buf2 =~ /^[^\n\r]*[\n\r]+<\?aid /s) {
3741
+ undef $$et{XmpValidate}; # don't validate INX
3606
3742
  if ($$et{XMP_CAPTURE}) {
3607
3743
  $et->Error("ExifTool does not yet support writing of INX files");
3608
3744
  return 0;
@@ -3611,6 +3747,7 @@ sub ProcessXMP($$;$)
3611
3747
  } elsif ($buf2 =~ /<x(mp)?:x[ma]pmeta/) {
3612
3748
  $hasXMP = 1;
3613
3749
  } else {
3750
+ undef $$et{XmpValidate}; # don't validate XML
3614
3751
  # identify SVG images and PLIST files by DOCTYPE if available
3615
3752
  if ($buf2 =~ /<!DOCTYPE\s+(\w+)/) {
3616
3753
  if ($1 eq 'svg') {
@@ -3619,6 +3756,7 @@ sub ProcessXMP($$;$)
3619
3756
  $type = 'PLIST';
3620
3757
  } elsif ($1 eq 'REDXIF') {
3621
3758
  $type = 'RMD';
3759
+ $mime = 'application/xml';
3622
3760
  } else {
3623
3761
  return 0;
3624
3762
  }
@@ -3667,7 +3805,7 @@ sub ProcessXMP($$;$)
3667
3805
  $type = $ext if $ext and $ext eq 'COS'; # recognize COS by extension
3668
3806
  }
3669
3807
  }
3670
- $et->SetFileType($type);
3808
+ $et->SetFileType($type, $mime);
3671
3809
 
3672
3810
  my $fast = $et->Options('FastScan');
3673
3811
  return 1 if $fast and $fast == 3;
@@ -3739,7 +3877,8 @@ sub ProcessXMP($$;$)
3739
3877
  # extract XMP as a block if specified
3740
3878
  my $blockName = $$dirInfo{BlockInfo} ? $$dirInfo{BlockInfo}{Name} : 'XMP';
3741
3879
  if (($$et{REQ_TAG_LOOKUP}{lc $blockName} or ($$et{TAGS_FROM_FILE} and
3742
- not $$et{EXCL_TAG_LOOKUP}{lc $blockName})) and not $isSVG)
3880
+ not $$et{EXCL_TAG_LOOKUP}{lc $blockName})) and
3881
+ ($$dirInfo{DirName} and $$dirInfo{DirName} eq 'XMP'))
3743
3882
  {
3744
3883
  $et->FoundTag($$dirInfo{BlockInfo} || 'XMP', substr($$dataPt, $dirStart, $dirLen));
3745
3884
  }
@@ -3874,6 +4013,7 @@ sub ProcessXMP($$;$)
3874
4013
  delete $$et{curURI};
3875
4014
  delete $$et{curNS};
3876
4015
  delete $$et{xlatNS};
4016
+ delete $$et{definedNS};
3877
4017
 
3878
4018
  return $rtnVal;
3879
4019
  }
@@ -3900,7 +4040,7 @@ information.
3900
4040
 
3901
4041
  =head1 AUTHOR
3902
4042
 
3903
- Copyright 2003-2017, Phil Harvey (phil at owl.phy.queensu.ca)
4043
+ Copyright 2003-2019, Phil Harvey (phil at owl.phy.queensu.ca)
3904
4044
 
3905
4045
  This library is free software; you can redistribute it and/or modify it
3906
4046
  under the same terms as Perl itself.