exiftool_vendored 12.62.0 → 12.64.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/Changes +50 -1
- data/bin/MANIFEST +4 -0
- data/bin/META.json +4 -1
- data/bin/META.yml +4 -1
- data/bin/Makefile.PL +7 -1
- data/bin/README +50 -46
- data/bin/config_files/guano.config +161 -0
- data/bin/exiftool +88 -62
- data/bin/lib/Image/ExifTool/7Z.pm +793 -0
- data/bin/lib/Image/ExifTool/Apple.pm +6 -3
- data/bin/lib/Image/ExifTool/Canon.pm +1 -0
- data/bin/lib/Image/ExifTool/CanonRaw.pm +4 -4
- data/bin/lib/Image/ExifTool/CanonVRD.pm +4 -1
- data/bin/lib/Image/ExifTool/Exif.pm +31 -14
- data/bin/lib/Image/ExifTool/FujiFilm.pm +3 -3
- data/bin/lib/Image/ExifTool/GPS.pm +5 -2
- data/bin/lib/Image/ExifTool/Geotag.pm +4 -1
- data/bin/lib/Image/ExifTool/Jpeg2000.pm +226 -28
- data/bin/lib/Image/ExifTool/Lang/fr.pm +1467 -202
- data/bin/lib/Image/ExifTool/MPF.pm +2 -1
- data/bin/lib/Image/ExifTool/Matroska.pm +16 -1
- data/bin/lib/Image/ExifTool/MinoltaRaw.pm +2 -2
- data/bin/lib/Image/ExifTool/Nikon.pm +419 -5
- data/bin/lib/Image/ExifTool/NikonCustom.pm +13 -3
- data/bin/lib/Image/ExifTool/PDF.pm +9 -1
- data/bin/lib/Image/ExifTool/PLIST.pm +8 -1
- data/bin/lib/Image/ExifTool/PNG.pm +6 -6
- data/bin/lib/Image/ExifTool/PhaseOne.pm +5 -5
- data/bin/lib/Image/ExifTool/QuickTime.pm +74 -21
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +20 -19
- data/bin/lib/Image/ExifTool/README +2 -2
- data/bin/lib/Image/ExifTool/RIFF.pm +11 -9
- data/bin/lib/Image/ExifTool/Shortcuts.pm +2 -1
- data/bin/lib/Image/ExifTool/SigmaRaw.pm +4 -4
- data/bin/lib/Image/ExifTool/Sony.pm +103 -8
- data/bin/lib/Image/ExifTool/TagLookup.pm +4738 -4630
- data/bin/lib/Image/ExifTool/TagNames.pod +249 -5
- data/bin/lib/Image/ExifTool/Validate.pm +17 -1
- data/bin/lib/Image/ExifTool/WriteExif.pl +9 -7
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +21 -9
- data/bin/lib/Image/ExifTool/WriteXMP.pl +2 -2
- data/bin/lib/Image/ExifTool/Writer.pl +28 -10
- data/bin/lib/Image/ExifTool/XMP.pm +14 -2
- data/bin/lib/Image/ExifTool/XMP2.pl +32 -0
- data/bin/lib/Image/ExifTool/XMPStruct.pl +96 -28
- data/bin/lib/Image/ExifTool/ZIP.pm +5 -5
- data/bin/lib/Image/ExifTool.pm +67 -39
- data/bin/lib/Image/ExifTool.pod +83 -52
- data/bin/perl-Image-ExifTool.spec +44 -44
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +4 -2
@@ -139,7 +139,7 @@ my @delGroups = qw(
|
|
139
139
|
Adobe AFCP APP0 APP1 APP2 APP3 APP4 APP5 APP6 APP7 APP8 APP9 APP10 APP11
|
140
140
|
APP12 APP13 APP14 APP15 CanonVRD CIFF Ducky EXIF ExifIFD File FlashPix
|
141
141
|
FotoStation GlobParamIFD GPS ICC_Profile IFD0 IFD1 Insta360 InteropIFD IPTC
|
142
|
-
ItemList JFIF Jpeg2000 Keys MakerNotes Meta MetaIFD Microsoft MIE MPF
|
142
|
+
ItemList JFIF Jpeg2000 JUMBF Keys MakerNotes Meta MetaIFD Microsoft MIE MPF
|
143
143
|
NikonApp NikonCapture PDF PDF-update PhotoMechanic Photoshop PNG PNG-pHYs
|
144
144
|
PrintIM QuickTime RMETA RSRC SubIFD Trailer UserData XML XML-* XMP XMP-*
|
145
145
|
);
|
@@ -1028,7 +1028,7 @@ TAG: foreach $tagInfo (@matchingTags) {
|
|
1028
1028
|
foreach (@vals) {
|
1029
1029
|
if (ref $_ eq 'HASH') {
|
1030
1030
|
require 'Image/ExifTool/XMPStruct.pl';
|
1031
|
-
$_ = Image::ExifTool::XMP::SerializeStruct($_);
|
1031
|
+
$_ = Image::ExifTool::XMP::SerializeStruct($self, $_);
|
1032
1032
|
}
|
1033
1033
|
print $out "$$self{INDENT2}$verb $wgrp1:$tag$fromList if value is '${_}'\n";
|
1034
1034
|
}
|
@@ -1293,6 +1293,7 @@ sub SetNewValuesFromFile($$;@)
|
|
1293
1293
|
HexTagIDs => $$options{HexTagIDs},
|
1294
1294
|
IgnoreMinorErrors=>$$options{IgnoreMinorErrors},
|
1295
1295
|
IgnoreTags => $$options{IgnoreTags},
|
1296
|
+
ImageHashType => $$options{ImageHashType},
|
1296
1297
|
Lang => $$options{Lang},
|
1297
1298
|
LargeFileSupport=> $$options{LargeFileSupport},
|
1298
1299
|
List => 1,
|
@@ -1313,6 +1314,7 @@ sub SetNewValuesFromFile($$;@)
|
|
1313
1314
|
ScanForXMP => $$options{ScanForXMP},
|
1314
1315
|
StrictDate => defined $$options{StrictDate} ? $$options{StrictDate} : 1,
|
1315
1316
|
Struct => $structOpt,
|
1317
|
+
StructFormat => $$options{StructFormat},
|
1316
1318
|
SystemTags => $$options{SystemTags},
|
1317
1319
|
TimeZone => $$options{TimeZone},
|
1318
1320
|
Unknown => $$options{Unknown},
|
@@ -1763,7 +1765,14 @@ GNV_TagInfo: foreach $tagInfo (@tagInfoList) {
|
|
1763
1765
|
}
|
1764
1766
|
}
|
1765
1767
|
# return our value(s)
|
1766
|
-
|
1768
|
+
if (wantarray) {
|
1769
|
+
# remove duplicates if requested
|
1770
|
+
if (@$vals > 1 and $self->Options('NoDups')) {
|
1771
|
+
my %seen;
|
1772
|
+
@$vals = grep { !$seen{$_}++ } @$vals;
|
1773
|
+
}
|
1774
|
+
return @$vals;
|
1775
|
+
}
|
1767
1776
|
return $$vals[0];
|
1768
1777
|
}
|
1769
1778
|
|
@@ -3283,7 +3292,7 @@ sub InsertTagValues($$$;$$$)
|
|
3283
3292
|
}
|
3284
3293
|
} elsif (ref $val eq 'HASH') {
|
3285
3294
|
require 'Image/ExifTool/XMPStruct.pl';
|
3286
|
-
$val = Image::ExifTool::XMP::SerializeStruct($val);
|
3295
|
+
$val = Image::ExifTool::XMP::SerializeStruct($self, $val);
|
3287
3296
|
} elsif (not defined $val) {
|
3288
3297
|
$val = $$self{OPTIONS}{MissingTagValue} if $asList;
|
3289
3298
|
}
|
@@ -3767,6 +3776,8 @@ sub GetNewValueHash($$;$$$$)
|
|
3767
3776
|
# this is a bit tricky: we want to add to a protected nvHash only if we
|
3768
3777
|
# are adding a conditional delete ($_[5] true or DelValue with no Shift)
|
3769
3778
|
# or accumulating List items (NoReplace true)
|
3779
|
+
# (NOTE: this should be looked into --> lists may be accumulated instead of being replaced
|
3780
|
+
# as expected when copying to the same list from different dynamic -tagsFromFile source files)
|
3770
3781
|
if ($protect and not ($opts{create} and ($$nvHash{NoReplace} or $_[5] or
|
3771
3782
|
($$nvHash{DelValue} and not defined $$nvHash{Shift}))))
|
3772
3783
|
{
|
@@ -5598,6 +5609,8 @@ sub WriteJPEG($$)
|
|
5598
5609
|
$s =~ /^(Meta|META|Exif)\0\0/ and $dirName = 'Meta';
|
5599
5610
|
} elsif ($marker == 0xe5) {
|
5600
5611
|
$s =~ /^RMETA\0/ and $dirName = 'RMETA';
|
5612
|
+
} elsif ($marker == 0xeb) {
|
5613
|
+
$s =~ /^JP/ and $dirName = 'JUMBF';
|
5601
5614
|
} elsif ($marker == 0xec) {
|
5602
5615
|
$s =~ /^Ducky/ and $dirName = 'Ducky';
|
5603
5616
|
} elsif ($marker == 0xed) {
|
@@ -6463,6 +6476,11 @@ sub WriteJPEG($$)
|
|
6463
6476
|
$segType = 'Ricoh RMETA';
|
6464
6477
|
$$delGroup{RMETA} and $del = 1;
|
6465
6478
|
}
|
6479
|
+
} elsif ($marker == 0xeb) { # APP10 (JUMBF)
|
6480
|
+
if ($$segDataPt =~ /^JP/) {
|
6481
|
+
$segType = 'JUMBF';
|
6482
|
+
$$delGroup{JUMBF} and $del = 1;
|
6483
|
+
}
|
6466
6484
|
} elsif ($marker == 0xec) { # APP12 (Ducky)
|
6467
6485
|
if ($$segDataPt =~ /^Ducky/) {
|
6468
6486
|
$segType = 'Ducky';
|
@@ -6880,14 +6898,14 @@ sub SetFileTime($$;$$$$)
|
|
6880
6898
|
}
|
6881
6899
|
|
6882
6900
|
#------------------------------------------------------------------------------
|
6883
|
-
# Add data to
|
6901
|
+
# Add data to hash checksum
|
6884
6902
|
# Inputs: 0) ExifTool ref, 1) RAF ref, 2) data size (or undef to read to end of file),
|
6885
6903
|
# 3) data name (or undef for no warnings or messages), 4) flag for no verbose message
|
6886
|
-
# Returns: number of bytes read and
|
6887
|
-
sub
|
6904
|
+
# Returns: number of bytes read and hashed
|
6905
|
+
sub ImageDataHash($$$;$$)
|
6888
6906
|
{
|
6889
6907
|
my ($self, $raf, $size, $type, $noMsg) = @_;
|
6890
|
-
my $
|
6908
|
+
my $hash = $$self{ImageDataHash} or return;
|
6891
6909
|
my ($bytesRead, $n) = (0, 65536);
|
6892
6910
|
my $buff;
|
6893
6911
|
for (;;) {
|
@@ -6900,11 +6918,11 @@ sub ImageDataMD5($$$;$$)
|
|
6900
6918
|
$self->Warn("Error reading $type data") if $type and defined $size;
|
6901
6919
|
last;
|
6902
6920
|
}
|
6903
|
-
$
|
6921
|
+
$hash->add($buff);
|
6904
6922
|
$bytesRead += length $buff;
|
6905
6923
|
}
|
6906
6924
|
if ($$self{OPTIONS}{Verbose} and $bytesRead and $type and not $noMsg) {
|
6907
|
-
$self->VPrint(0, "$$self{INDENT}(
|
6925
|
+
$self->VPrint(0, "$$self{INDENT}(ImageDataHash: $bytesRead bytes of $type data)\n");
|
6908
6926
|
}
|
6909
6927
|
return $bytesRead;
|
6910
6928
|
}
|
@@ -50,7 +50,7 @@ use Image::ExifTool::Exif;
|
|
50
50
|
use Image::ExifTool::GPS;
|
51
51
|
require Exporter;
|
52
52
|
|
53
|
-
$VERSION = '3.
|
53
|
+
$VERSION = '3.60';
|
54
54
|
@ISA = qw(Exporter);
|
55
55
|
@EXPORT_OK = qw(EscapeXML UnescapeXML);
|
56
56
|
|
@@ -144,6 +144,7 @@ my %xmpNS = (
|
|
144
144
|
xmpTPg => 'http://ns.adobe.com/xap/1.0/t/pg/',
|
145
145
|
xmpidq => 'http://ns.adobe.com/xmp/Identifier/qual/1.0/',
|
146
146
|
xmpPLUS => 'http://ns.adobe.com/xap/1.0/PLUS/',
|
147
|
+
panorama => 'http://ns.adobe.com/photoshop/1.0/panorama-profile',
|
147
148
|
dex => 'http://ns.optimasc.com/dex/1.0/',
|
148
149
|
mediapro => 'http://ns.iview-multimedia.com/mediapro/1.0/',
|
149
150
|
expressionmedia => 'http://ns.microsoft.com/expressionmedia/1.0/',
|
@@ -199,6 +200,7 @@ my %xmpNS = (
|
|
199
200
|
ast => 'http://ns.nikon.com/asteroid/1.0/',
|
200
201
|
nine => 'http://ns.nikon.com/nine/1.0/',
|
201
202
|
hdr_metadata => 'http://ns.adobe.com/hdr-metadata/1.0/',
|
203
|
+
hdrgm => 'http://ns.adobe.com/hdr-gain-map/1.0/',
|
202
204
|
);
|
203
205
|
|
204
206
|
# build reverse namespace lookup
|
@@ -709,6 +711,10 @@ my %sRangeMask = (
|
|
709
711
|
Name => 'xmpPLUS',
|
710
712
|
SubDirectory => { TagTable => 'Image::ExifTool::XMP::xmpPLUS' },
|
711
713
|
},
|
714
|
+
panorama => {
|
715
|
+
Name => 'panorama',
|
716
|
+
SubDirectory => { TagTable => 'Image::ExifTool::XMP::panorama' },
|
717
|
+
},
|
712
718
|
plus => {
|
713
719
|
Name => 'plus',
|
714
720
|
SubDirectory => { TagTable => 'Image::ExifTool::PLUS::XMP' },
|
@@ -909,6 +915,10 @@ my %sRangeMask = (
|
|
909
915
|
Name => 'hdr',
|
910
916
|
SubDirectory => { TagTable => 'Image::ExifTool::XMP::hdr' },
|
911
917
|
},
|
918
|
+
hdrgm => {
|
919
|
+
Name => 'hdrgm',
|
920
|
+
SubDirectory => { TagTable => 'Image::ExifTool::XMP::hdrgm' },
|
921
|
+
},
|
912
922
|
);
|
913
923
|
|
914
924
|
# hack to allow XML containing Dublin Core metadata to be handled like XMP (eg. EPUB - see ZIP.pm)
|
@@ -2566,7 +2576,9 @@ my %sPantryItem = (
|
|
2566
2576
|
%xmpTableDefaults,
|
2567
2577
|
GROUPS => { 1 => 'XMP-et', 2 => 'Image' },
|
2568
2578
|
NAMESPACE => 'et',
|
2569
|
-
|
2579
|
+
OriginalImageHash => { Notes => 'used to store ExifTool ImageDataHash digest' },
|
2580
|
+
OriginalImageHashType => { Notes => "ImageHashType API setting, default 'MD5'" },
|
2581
|
+
OriginalImageMD5 => { Notes => 'deprecated' },
|
2570
2582
|
);
|
2571
2583
|
|
2572
2584
|
# table to add tags in other namespaces
|
@@ -1388,6 +1388,17 @@ my %sSubVersion = (
|
|
1388
1388
|
ReuseAllowed => { Writable => 'boolean' },
|
1389
1389
|
);
|
1390
1390
|
|
1391
|
+
%Image::ExifTool::XMP::panorama = (
|
1392
|
+
%xmpTableDefaults,
|
1393
|
+
GROUPS => { 1 => 'XMP-panorama', 2 => 'Image' },
|
1394
|
+
NAMESPACE => 'panorama',
|
1395
|
+
NOTES => 'Adobe Photoshop Panorama-profile tags.',
|
1396
|
+
Transformation => { },
|
1397
|
+
VirtualFocalLength => { Writable => 'real' },
|
1398
|
+
VirtualImageXCenter => { Writable => 'real' },
|
1399
|
+
VirtualImageYCenter => { Writable => 'real' },
|
1400
|
+
);
|
1401
|
+
|
1391
1402
|
# Creative Commons namespace properties (cc) (ref 5)
|
1392
1403
|
%Image::ExifTool::XMP::cc = (
|
1393
1404
|
%xmpTableDefaults,
|
@@ -2094,6 +2105,27 @@ my %sSubVersion = (
|
|
2094
2105
|
scene_referred => { Name => 'SceneReferred', Writable => 'boolean' },
|
2095
2106
|
);
|
2096
2107
|
|
2108
|
+
# HDR Gain Map metadata namespace
|
2109
|
+
%Image::ExifTool::XMP::hdrgm = (
|
2110
|
+
%xmpTableDefaults,
|
2111
|
+
GROUPS => { 1 => 'XMP-hdrgm', 2 => 'Image' },
|
2112
|
+
NAMESPACE => 'hdrgm',
|
2113
|
+
TABLE_DESC => 'XMP HDR Gain Map Metadata',
|
2114
|
+
NOTES => 'Tags used in Adobe gain map images.',
|
2115
|
+
Version => { Avoid => 1 },
|
2116
|
+
BaseRenditionIsHDR => { Writable => 'boolean' },
|
2117
|
+
# this is a pain in the ass: List items below may or may not be lists
|
2118
|
+
# according to the Adobe specification -- I don't know how to handle tags
|
2119
|
+
# with a variable format like this, so just make them lists here for now
|
2120
|
+
OffsetSDR => { Writable => 'real', List => 'Seq' },
|
2121
|
+
OffsetHDR => { Writable => 'real', List => 'Seq' },
|
2122
|
+
HDRCapacityMin => { Writable => 'real' },
|
2123
|
+
HDRCapacityMax => { Writable => 'real' },
|
2124
|
+
GainMapMin => { Writable => 'real', List => 'Seq' },
|
2125
|
+
GainMapMax => { Writable => 'real', List => 'Seq' },
|
2126
|
+
Gamma => { Writable => 'real', List => 'Seq', Avoid => 1 },
|
2127
|
+
);
|
2128
|
+
|
2097
2129
|
# SVG namespace properties (ref 9)
|
2098
2130
|
%Image::ExifTool::XMP::SVG = (
|
2099
2131
|
GROUPS => { 0 => 'SVG', 1 => 'SVG', 2 => 'Image' },
|
@@ -14,42 +14,55 @@ use vars qw(%specialStruct %stdXlatNS);
|
|
14
14
|
use Image::ExifTool qw(:Utils);
|
15
15
|
use Image::ExifTool::XMP;
|
16
16
|
|
17
|
-
sub SerializeStruct(
|
18
|
-
sub InflateStruct(
|
17
|
+
sub SerializeStruct($$;$);
|
18
|
+
sub InflateStruct($$;$);
|
19
19
|
sub DumpStruct($;$);
|
20
20
|
sub CheckStruct($$$);
|
21
21
|
sub AddNewStruct($$$$$$);
|
22
22
|
sub ConvertStruct($$$$;$);
|
23
|
+
sub EscapeJSON($;$);
|
24
|
+
|
25
|
+
# lookups for JSON characters that we escape specially
|
26
|
+
my %jsonChar = ( '"'=>'"', '\\'=>'\\', "\b"=>'b', "\f"=>'f', "\n"=>'n', "\r"=>'r', "\t"=>'t' );
|
27
|
+
my %jsonEsc = ( '"'=>'"', '\\'=>'\\', 'b'=>"\b", 'f'=>"\f", 'n'=>"\n", 'r'=>"\r", 't'=>"\t" );
|
23
28
|
|
24
29
|
#------------------------------------------------------------------------------
|
25
30
|
# Serialize a structure (or other object) into a simple string
|
26
|
-
# Inputs: 0) HASH ref, ARRAY ref, or SCALAR,
|
27
|
-
# Returns: serialized structure string
|
31
|
+
# Inputs: 0) ExifTool ref, 1) HASH ref, ARRAY ref, or SCALAR, 2) closing bracket (or undef)
|
32
|
+
# Returns: serialized structure string (in format specified by StructFormat option)
|
28
33
|
# eg) "{field=text with {braces|}|, and a comma, field2=val2,field3={field4=[a,b]}}"
|
29
|
-
sub SerializeStruct(
|
34
|
+
sub SerializeStruct($$;$)
|
30
35
|
{
|
31
|
-
my ($obj, $ket) = @_;
|
36
|
+
my ($et, $obj, $ket) = @_;
|
32
37
|
my ($key, $val, @vals, $rtnVal);
|
38
|
+
my $sfmt = $et->Options('StructFormat');
|
33
39
|
|
34
40
|
if (ref $obj eq 'HASH') {
|
35
41
|
# support hashes with ordered keys
|
36
42
|
my @keys = $$obj{_ordered_keys_} ? @{$$obj{_ordered_keys_}} : sort keys %$obj;
|
37
43
|
foreach $key (@keys) {
|
38
|
-
|
44
|
+
my $hdr = $sfmt ? EscapeJSON($key) . ':' : $key . '=';
|
45
|
+
push @vals, $hdr . SerializeStruct($et, $$obj{$key}, '}');
|
39
46
|
}
|
40
47
|
$rtnVal = '{' . join(',', @vals) . '}';
|
41
48
|
} elsif (ref $obj eq 'ARRAY') {
|
42
49
|
foreach $val (@$obj) {
|
43
|
-
push @vals, SerializeStruct($val, ']');
|
50
|
+
push @vals, SerializeStruct($et, $val, ']');
|
44
51
|
}
|
45
52
|
$rtnVal = '[' . join(',', @vals) . ']';
|
46
53
|
} elsif (defined $obj) {
|
47
54
|
$obj = $$obj if ref $obj eq 'SCALAR';
|
48
55
|
# escape necessary characters in string (closing bracket plus "," and "|")
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
56
|
+
if ($sfmt) {
|
57
|
+
$rtnVal = EscapeJSON($obj, $sfmt eq 'JSONQ');
|
58
|
+
} else {
|
59
|
+
my $pat = $ket ? "\\$ket|,|\\|" : ',|\\|';
|
60
|
+
($rtnVal = $obj) =~ s/($pat)/|$1/g;
|
61
|
+
# also must escape opening bracket or whitespace at start of string
|
62
|
+
$rtnVal =~ s/^([\s\[\{])/|$1/;
|
63
|
+
}
|
64
|
+
} elsif ($sfmt) {
|
65
|
+
$rtnVal = 'null';
|
53
66
|
} else {
|
54
67
|
$rtnVal = ''; # allow undefined list items
|
55
68
|
}
|
@@ -58,21 +71,25 @@ sub SerializeStruct($;$)
|
|
58
71
|
|
59
72
|
#------------------------------------------------------------------------------
|
60
73
|
# Inflate structure (or other object) from a serialized string
|
61
|
-
# Inputs: 0) reference to object in string form
|
62
|
-
#
|
74
|
+
# Inputs: 0) ExifTool ref, 1) reference to object in string form
|
75
|
+
# (serialized using the '|' escape, or JSON)
|
76
|
+
# 2) extra delimiter for scalar values delimiters
|
63
77
|
# Returns: 0) object as a SCALAR, HASH ref, or ARRAY ref (or undef on error),
|
64
78
|
# 1) warning string (or undef)
|
65
79
|
# Notes: modifies input string to remove parsed objects
|
66
|
-
sub InflateStruct(
|
80
|
+
sub InflateStruct($$;$)
|
67
81
|
{
|
68
|
-
my ($obj, $delim) = @_;
|
82
|
+
my ($et, $obj, $delim) = @_;
|
69
83
|
my ($val, $warn, $part);
|
84
|
+
my $sfmt = $et->Options('StructFormat');
|
70
85
|
|
71
86
|
if ($$obj =~ s/^\s*\{//) {
|
72
87
|
my %struct;
|
73
|
-
|
88
|
+
for (;;) {
|
89
|
+
last unless $sfmt ? $$obj =~ s/^\s*"(.*?)"\s*://s :
|
90
|
+
$$obj =~ s/^\s*([-\w:]+#?)\s*=//s;
|
74
91
|
my $tag = $1;
|
75
|
-
my ($v, $w) = InflateStruct($obj, '}');
|
92
|
+
my ($v, $w) = InflateStruct($et, $obj, '}');
|
76
93
|
$warn = $w if $w and not $warn;
|
77
94
|
return(undef, $warn) unless defined $v;
|
78
95
|
$struct{$tag} = $v;
|
@@ -94,7 +111,7 @@ sub InflateStruct($;$)
|
|
94
111
|
} elsif ($$obj =~ s/^\s*\[//) {
|
95
112
|
my @list;
|
96
113
|
for (;;) {
|
97
|
-
my ($v, $w) = InflateStruct($obj, ']');
|
114
|
+
my ($v, $w) = InflateStruct($et, $obj, ']');
|
98
115
|
$warn = $w if $w and not $warn;
|
99
116
|
return(undef, $warn) unless defined $v;
|
100
117
|
push @list, $v;
|
@@ -105,20 +122,71 @@ sub InflateStruct($;$)
|
|
105
122
|
$val = \@list;
|
106
123
|
} else {
|
107
124
|
$$obj =~ s/^\s+//s; # remove leading whitespace
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
125
|
+
if ($sfmt) {
|
126
|
+
if ($$obj =~ s/^"//) {
|
127
|
+
$val = '';
|
128
|
+
while ($$obj =~ s/(.*?)"//) {
|
129
|
+
$val .= $1;
|
130
|
+
last unless $val =~ /([\\]+)$/ and length($1) & 0x01;
|
131
|
+
substr($val, -1, 1) = '"'; # (was an escaped quote)
|
132
|
+
}
|
133
|
+
if ($val =~ s/^base64://) {
|
134
|
+
$val = DecodeBase64($val);
|
135
|
+
} else {
|
136
|
+
# un-escape characters in JSON string
|
137
|
+
$val =~ s/\\(.)/$jsonEsc{$1}||'\\'.$1/egs;
|
138
|
+
}
|
139
|
+
} elsif ($$obj =~ s/^(true|false)\b//) {
|
140
|
+
$val = '"' . ucfirst($1) . '"';
|
141
|
+
} elsif ($$obj =~ s/^([+-]?(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?)//) {
|
142
|
+
$val = $1;
|
143
|
+
} else {
|
144
|
+
$warn or $warn = 'Unknown JSON object';
|
145
|
+
$val = '""';
|
146
|
+
}
|
147
|
+
} else {
|
148
|
+
# read scalar up to specified delimiter (or "," if not defined)
|
149
|
+
$delim = $delim ? "\\$delim|,|\\||\$" : ',|\\||$';
|
150
|
+
$val = '';
|
151
|
+
for (;;) {
|
152
|
+
$$obj =~ s/^(.*?)($delim)//s or last;
|
153
|
+
$val .= $1;
|
154
|
+
last unless $2;
|
155
|
+
$2 eq '|' or $$obj = $2 . $$obj, last;
|
156
|
+
$$obj =~ s/^(.)//s and $val .= $1; # add escaped character
|
157
|
+
}
|
117
158
|
}
|
118
159
|
}
|
119
160
|
return($val, $warn);
|
120
161
|
}
|
121
162
|
|
163
|
+
#------------------------------------------------------------------------------
|
164
|
+
# Escape string for JSON
|
165
|
+
# Inputs: 0) string, 1) flag to force numbers to be quoted too
|
166
|
+
# Returns: Escaped string (quoted if necessary)
|
167
|
+
sub EscapeJSON($;$)
|
168
|
+
{
|
169
|
+
my ($str, $quote) = @_;
|
170
|
+
unless ($quote) {
|
171
|
+
return 'null' unless defined $str;
|
172
|
+
# JSON boolean (true or false)
|
173
|
+
return lc($str) if $str =~ /^(true|false)$/i;
|
174
|
+
# JSON number (see json.org for numerical format)
|
175
|
+
# return $str if $str =~ /^-?(\d|[1-9]\d+)(\.\d+)?(e[-+]?\d+)?$/i;
|
176
|
+
# (these big numbers caused problems for some JSON parsers, so be more conservative)
|
177
|
+
return $str if $str =~ /^-?(\d|[1-9]\d{1,14})(\.\d{1,16})?(e[-+]?\d{1,3})?$/i;
|
178
|
+
}
|
179
|
+
return '""' unless defined $str;
|
180
|
+
# encode JSON string in base64 if necessary
|
181
|
+
return '"base64:' . EncodeBase64($str, 1) . '"' if Image::ExifTool::IsUTF8(\$str) < 0;
|
182
|
+
# escape special characters
|
183
|
+
$str =~ s/(["\t\n\r\\])/\\$jsonChar{$1}/sg;
|
184
|
+
$str =~ tr/\0//d; # remove all nulls
|
185
|
+
# escape other control characters with \u
|
186
|
+
$str =~ s/([\0-\x1f])/sprintf("\\u%.4X",ord $1)/sge;
|
187
|
+
return '"' . $str . '"'; # return the quoted string
|
188
|
+
}
|
189
|
+
|
122
190
|
#------------------------------------------------------------------------------
|
123
191
|
# Get XMP language code from tag name string
|
124
192
|
# Inputs: 0) tag name string
|
@@ -20,7 +20,7 @@ use strict;
|
|
20
20
|
use vars qw($VERSION $warnString);
|
21
21
|
use Image::ExifTool qw(:DataAccess :Utils);
|
22
22
|
|
23
|
-
$VERSION = '1.
|
23
|
+
$VERSION = '1.30';
|
24
24
|
|
25
25
|
sub WarnProc($) { $warnString = $_[0]; }
|
26
26
|
|
@@ -259,8 +259,8 @@ my %iWorkType = (
|
|
259
259
|
%Image::ExifTool::ZIP::RAR5 = (
|
260
260
|
GROUPS => { 2 => 'Other' },
|
261
261
|
VARS => { NO_ID => 1 },
|
262
|
-
NOTES => 'These tags are extracted from RAR v5 archive files.',
|
263
|
-
|
262
|
+
NOTES => 'These tags are extracted from RAR v5 and 7z archive files.',
|
263
|
+
FileVersion => { },
|
264
264
|
CompressedSize => { },
|
265
265
|
ModifyDate => {
|
266
266
|
Groups => { 2 => 'Time' },
|
@@ -310,7 +310,7 @@ sub ProcessRAR($$)
|
|
310
310
|
$et->SetFileType();
|
311
311
|
SetByteOrder('II');
|
312
312
|
my $tagTablePtr = GetTagTable('Image::ExifTool::ZIP::RAR5');
|
313
|
-
$et->HandleTag($tagTablePtr, '
|
313
|
+
$et->HandleTag($tagTablePtr, 'FileVersion', 'RAR v4');
|
314
314
|
$tagTablePtr = GetTagTable('Image::ExifTool::ZIP::RAR');
|
315
315
|
|
316
316
|
for (;;) {
|
@@ -356,7 +356,7 @@ sub ProcessRAR($$)
|
|
356
356
|
return 0 unless $raf->Read($buff, 1) and $buff eq "\0";
|
357
357
|
$et->SetFileType();
|
358
358
|
my $tagTablePtr = GetTagTable('Image::ExifTool::ZIP::RAR5');
|
359
|
-
$et->HandleTag($tagTablePtr, '
|
359
|
+
$et->HandleTag($tagTablePtr, 'FileVersion', 'RAR v5');
|
360
360
|
$$et{INDENT} .= '| ';
|
361
361
|
|
362
362
|
# loop through header blocks
|