exiftool-vendored.exe 12.80.0 → 12.82.1
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.
- package/README.md +6 -0
- package/bin/exiftool.exe +0 -0
- package/bin/exiftool_files/Changes +44 -0
- package/bin/exiftool_files/Licenses_Strawberry_Perl.zip +0 -0
- package/bin/exiftool_files/README +3 -2
- package/bin/exiftool_files/exiftool.pl +36 -14
- package/bin/exiftool_files/lib/Archive/Zip/Archive.pm +399 -65
- package/bin/exiftool_files/lib/Archive/Zip/DirectoryMember.pm +1 -1
- package/bin/exiftool_files/lib/Archive/Zip/FileMember.pm +1 -1
- package/bin/exiftool_files/lib/Archive/Zip/Member.pm +499 -195
- package/bin/exiftool_files/lib/Archive/Zip/NewFileMember.pm +1 -1
- package/bin/exiftool_files/lib/Archive/Zip/StringMember.pm +2 -2
- package/bin/exiftool_files/lib/Archive/Zip/ZipFileMember.pm +79 -20
- package/bin/exiftool_files/lib/Archive/Zip.pm +179 -29
- package/bin/exiftool_files/lib/AutoLoader.pm +453 -0
- package/bin/exiftool_files/lib/B/Deparse.pm +209 -137
- package/bin/exiftool_files/lib/B.pm +1 -1
- package/bin/exiftool_files/lib/Benchmark.pm +1123 -0
- package/bin/exiftool_files/lib/Class/Struct.pm +2 -2
- package/bin/exiftool_files/lib/Compress/Raw/Bzip2.pm +14 -9
- package/bin/exiftool_files/lib/Compress/Raw/Lzma.pm +982 -0
- package/bin/exiftool_files/lib/Compress/Raw/Zlib.pm +91 -86
- package/bin/exiftool_files/lib/Compress/Zlib.pm +105 -100
- package/bin/exiftool_files/lib/Config.pm +9 -9
- package/bin/exiftool_files/lib/Config_heavy.pl +36 -33
- package/bin/exiftool_files/lib/CryptX.pm +2 -82
- package/bin/exiftool_files/lib/Data/Dumper.pm +2 -2
- package/bin/exiftool_files/lib/Digest/MD5.pm +12 -9
- package/bin/exiftool_files/lib/Digest/Perl/MD5.pm +1 -191
- package/bin/exiftool_files/lib/Digest/base.pm +26 -20
- package/bin/exiftool_files/lib/DynaLoader.pm +7 -4
- package/bin/exiftool_files/lib/Encode.pm +3 -3
- package/bin/exiftool_files/lib/Errno.pm +13 -13
- package/bin/exiftool_files/lib/Exporter/Heavy.pm +2 -2
- package/bin/exiftool_files/lib/Exporter.pm +1 -1
- package/bin/exiftool_files/lib/ExtUtils/Command/MM.pm +323 -0
- package/bin/exiftool_files/lib/ExtUtils/Command.pm +382 -0
- package/bin/exiftool_files/lib/File/Find.pm +1 -1
- package/bin/exiftool_files/lib/File/Glob.pm +1 -8
- package/bin/exiftool_files/lib/File/GlobMapper.pm +2 -2
- package/bin/exiftool_files/lib/File/HomeDir/Darwin/Carbon.pm +2 -40
- package/bin/exiftool_files/lib/File/HomeDir/Darwin/Cocoa.pm +2 -34
- package/bin/exiftool_files/lib/File/HomeDir/Darwin.pm +2 -28
- package/bin/exiftool_files/lib/File/HomeDir/Driver.pm +2 -35
- package/bin/exiftool_files/lib/File/HomeDir/FreeDesktop.pm +2 -62
- package/bin/exiftool_files/lib/File/HomeDir/MacOS9.pm +2 -53
- package/bin/exiftool_files/lib/File/HomeDir/Test.pm +2 -43
- package/bin/exiftool_files/lib/File/HomeDir/Unix.pm +2 -53
- package/bin/exiftool_files/lib/File/HomeDir/Windows.pm +2 -69
- package/bin/exiftool_files/lib/File/HomeDir.pm +5 -416
- package/bin/exiftool_files/lib/File/Path.pm +3 -3
- package/bin/exiftool_files/lib/File/Spec/Win32.pm +2 -2
- package/bin/exiftool_files/lib/File/Temp.pm +70 -35
- package/bin/exiftool_files/lib/File/Which.pm +1 -240
- package/bin/exiftool_files/lib/File/stat.pm +3 -2
- package/bin/exiftool_files/lib/IO/Compress/Adapter/Bzip2.pm +16 -17
- package/bin/exiftool_files/lib/IO/Compress/Adapter/Deflate.pm +19 -20
- package/bin/exiftool_files/lib/IO/Compress/Base/Common.pm +5 -5
- package/bin/exiftool_files/lib/IO/Compress/Base.pm +35 -26
- package/bin/exiftool_files/lib/IO/Compress/Brotli.pm +159 -0
- package/bin/exiftool_files/lib/IO/Compress/Bzip2.pm +50 -25
- package/bin/exiftool_files/lib/IO/Compress/Gzip/Constants.pm +6 -6
- package/bin/exiftool_files/lib/IO/Compress/Gzip.pm +58 -32
- package/bin/exiftool_files/lib/IO/Compress/RawDeflate.pm +63 -38
- package/bin/exiftool_files/lib/IO/Compress/Zlib/Extra.pm +20 -20
- package/bin/exiftool_files/lib/IO/Dir.pm +1 -1
- package/bin/exiftool_files/lib/IO/File.pm +1 -1
- package/bin/exiftool_files/lib/IO/Handle.pm +1 -21
- package/bin/exiftool_files/lib/IO/Pipe.pm +1 -1
- package/bin/exiftool_files/lib/IO/Seekable.pm +1 -1
- package/bin/exiftool_files/lib/IO/Select.pm +16 -2
- package/bin/exiftool_files/lib/IO/Socket/INET.pm +14 -9
- package/bin/exiftool_files/lib/IO/Socket/UNIX.pm +17 -1
- package/bin/exiftool_files/lib/IO/Socket.pm +474 -126
- package/bin/exiftool_files/lib/IO/String.pm +425 -0
- package/bin/exiftool_files/lib/IO/Uncompress/Adapter/Inflate.pm +13 -14
- package/bin/exiftool_files/lib/IO/Uncompress/Base.pm +142 -132
- package/bin/exiftool_files/lib/IO/Uncompress/Brotli.pm +119 -0
- package/bin/exiftool_files/lib/IO/Uncompress/Gunzip.pm +43 -37
- package/bin/exiftool_files/lib/IO/Uncompress/RawInflate.pm +49 -43
- package/bin/exiftool_files/lib/IO.pm +2 -2
- package/bin/exiftool_files/lib/Image/ExifTool/BuildTagLookup.pm +44 -31
- package/bin/exiftool_files/lib/Image/ExifTool/CanonVRD.pm +2 -2
- package/bin/exiftool_files/lib/Image/ExifTool/FujiFilm.pm +20 -7
- package/bin/exiftool_files/lib/Image/ExifTool/GM.pm +543 -0
- package/bin/exiftool_files/lib/Image/ExifTool/Geolocation.pm +332 -149
- package/bin/exiftool_files/lib/Image/ExifTool/Geotag.pm +9 -4
- package/bin/exiftool_files/lib/Image/ExifTool/M2TS.pm +32 -4
- package/bin/exiftool_files/lib/Image/ExifTool/MakerNotes.pm +2 -2
- package/bin/exiftool_files/lib/Image/ExifTool/Microsoft.pm +1 -1
- package/bin/exiftool_files/lib/Image/ExifTool/Nikon.pm +331 -22
- package/bin/exiftool_files/lib/Image/ExifTool/NikonCustom.pm +55 -1
- package/bin/exiftool_files/lib/Image/ExifTool/Olympus.pm +1 -0
- package/bin/exiftool_files/lib/Image/ExifTool/OpenEXR.pm +21 -3
- package/bin/exiftool_files/lib/Image/ExifTool/PNG.pm +3 -3
- package/bin/exiftool_files/lib/Image/ExifTool/QuickTime.pm +40 -24
- package/bin/exiftool_files/lib/Image/ExifTool/QuickTimeStream.pl +61 -30
- package/bin/exiftool_files/lib/Image/ExifTool/README +2 -0
- package/bin/exiftool_files/lib/Image/ExifTool/Sony.pm +1 -1
- package/bin/exiftool_files/lib/Image/ExifTool/TagLookup.pm +4815 -4775
- package/bin/exiftool_files/lib/Image/ExifTool/TagNames.pod +931 -617
- package/bin/exiftool_files/lib/Image/ExifTool/WriteQuickTime.pl +30 -8
- package/bin/exiftool_files/lib/Image/ExifTool/Writer.pl +10 -4
- package/bin/exiftool_files/lib/Image/ExifTool/XMP.pm +4 -2
- package/bin/exiftool_files/lib/Image/ExifTool.pm +77 -41
- package/bin/exiftool_files/lib/Image/ExifTool.pod +24 -11
- package/bin/exiftool_files/lib/List/Util.pm +97 -8
- package/bin/exiftool_files/lib/MIME/Base64.pm +5 -5
- package/bin/exiftool_files/lib/MIME/Charset/_Compat.pm +106 -0
- package/bin/exiftool_files/lib/MIME/Charset.pm +1303 -0
- package/bin/exiftool_files/lib/Math/BigFloat.pm +444 -27
- package/bin/exiftool_files/lib/Math/BigInt/Calc.pm +296 -313
- package/bin/exiftool_files/lib/Math/BigInt/FastCalc.pm +1 -1
- package/bin/exiftool_files/lib/Math/BigInt/GMP.pm +2 -115
- package/bin/exiftool_files/lib/Math/BigInt/LTM.pm +2 -24
- package/bin/exiftool_files/lib/Math/BigInt/Lib.pm +61 -32
- package/bin/exiftool_files/lib/Math/BigInt.pm +292 -107
- package/bin/exiftool_files/lib/POSIX.pm +1 -1
- package/bin/exiftool_files/lib/PerlIO/scalar.pm +41 -0
- package/bin/exiftool_files/lib/PerlIO.pm +397 -0
- package/bin/exiftool_files/lib/Portable/CPAN.pm +94 -94
- package/bin/exiftool_files/lib/Portable/Config.pm +94 -94
- package/bin/exiftool_files/lib/Portable/FileSpec.pm +180 -180
- package/bin/exiftool_files/lib/Portable/HomeDir.pm +110 -110
- package/bin/exiftool_files/lib/Portable/LoadYaml.pm +430 -430
- package/bin/exiftool_files/lib/Portable/minicpan.pm +55 -55
- package/bin/exiftool_files/lib/Portable.pm +246 -320
- package/bin/exiftool_files/lib/Scalar/Util.pm +9 -4
- package/bin/exiftool_files/lib/Socket.pm +16 -12
- package/bin/exiftool_files/lib/Storable.pm +1444 -1441
- package/bin/exiftool_files/lib/TAP/Base.pm +133 -0
- package/bin/exiftool_files/lib/TAP/Formatter/Base.pm +467 -0
- package/bin/exiftool_files/lib/TAP/Formatter/Color.pm +116 -0
- package/bin/exiftool_files/lib/TAP/Formatter/Console/ParallelSession.pm +201 -0
- package/bin/exiftool_files/lib/TAP/Formatter/Console/Session.pm +205 -0
- package/bin/exiftool_files/lib/TAP/Formatter/Console.pm +100 -0
- package/bin/exiftool_files/lib/TAP/Formatter/File/Session.pm +95 -0
- package/bin/exiftool_files/lib/TAP/Formatter/File.pm +56 -0
- package/bin/exiftool_files/lib/TAP/Formatter/Session.pm +220 -0
- package/bin/exiftool_files/lib/TAP/Harness/Beyond.pod +426 -0
- package/bin/exiftool_files/lib/TAP/Harness/Env.pm +215 -0
- package/bin/exiftool_files/lib/TAP/Harness.pm +1054 -0
- package/bin/exiftool_files/lib/TAP/Object.pm +155 -0
- package/bin/exiftool_files/lib/TAP/Parser/Aggregator.pm +414 -0
- package/bin/exiftool_files/lib/TAP/Parser/Grammar.pm +584 -0
- package/bin/exiftool_files/lib/TAP/Parser/Iterator/Array.pm +100 -0
- package/bin/exiftool_files/lib/TAP/Parser/Iterator/Process.pm +378 -0
- package/bin/exiftool_files/lib/TAP/Parser/Iterator/Stream.pm +116 -0
- package/bin/exiftool_files/lib/TAP/Parser/Iterator.pm +162 -0
- package/bin/exiftool_files/lib/TAP/Parser/IteratorFactory.pm +339 -0
- package/bin/exiftool_files/lib/TAP/Parser/Multiplexer.pm +194 -0
- package/bin/exiftool_files/lib/TAP/Parser/Result/Bailout.pm +62 -0
- package/bin/exiftool_files/lib/TAP/Parser/Result/Comment.pm +60 -0
- package/bin/exiftool_files/lib/TAP/Parser/Result/Plan.pm +119 -0
- package/bin/exiftool_files/lib/TAP/Parser/Result/Pragma.pm +62 -0
- package/bin/exiftool_files/lib/TAP/Parser/Result/Test.pm +271 -0
- package/bin/exiftool_files/lib/TAP/Parser/Result/Unknown.pm +48 -0
- package/bin/exiftool_files/lib/TAP/Parser/Result/Version.pm +62 -0
- package/bin/exiftool_files/lib/TAP/Parser/Result/YAML.pm +61 -0
- package/bin/exiftool_files/lib/TAP/Parser/Result.pm +297 -0
- package/bin/exiftool_files/lib/TAP/Parser/ResultFactory.pm +183 -0
- package/bin/exiftool_files/lib/TAP/Parser/Scheduler/Job.pm +127 -0
- package/bin/exiftool_files/lib/TAP/Parser/Scheduler/Spinner.pm +61 -0
- package/bin/exiftool_files/lib/TAP/Parser/Scheduler.pm +448 -0
- package/bin/exiftool_files/lib/TAP/Parser/Source.pm +381 -0
- package/bin/exiftool_files/lib/TAP/Parser/SourceHandler/Executable.pm +184 -0
- package/bin/exiftool_files/lib/TAP/Parser/SourceHandler/File.pm +136 -0
- package/bin/exiftool_files/lib/TAP/Parser/SourceHandler/Handle.pm +124 -0
- package/bin/exiftool_files/lib/TAP/Parser/SourceHandler/Perl.pm +370 -0
- package/bin/exiftool_files/lib/TAP/Parser/SourceHandler/RawTAP.pm +130 -0
- package/bin/exiftool_files/lib/TAP/Parser/SourceHandler.pm +191 -0
- package/bin/exiftool_files/lib/TAP/Parser/YAMLish/Reader.pm +332 -0
- package/bin/exiftool_files/lib/TAP/Parser/YAMLish/Writer.pm +254 -0
- package/bin/exiftool_files/lib/TAP/Parser.pm +1931 -0
- package/bin/exiftool_files/lib/Test/Builder/Formatter.pm +107 -0
- package/bin/exiftool_files/lib/Test/Builder/IO/Scalar.pm +659 -0
- package/bin/exiftool_files/lib/Test/Builder/Module.pm +182 -0
- package/bin/exiftool_files/lib/Test/Builder/Tester/Color.pm +51 -0
- package/bin/exiftool_files/lib/Test/Builder/Tester.pm +675 -0
- package/bin/exiftool_files/lib/Test/Builder/TodoDiag.pm +68 -0
- package/bin/exiftool_files/lib/Test/Builder.pm +2653 -0
- package/bin/exiftool_files/lib/Test/Harness.pm +618 -0
- package/bin/exiftool_files/lib/Test/More.pm +1997 -0
- package/bin/exiftool_files/lib/Test/Simple.pm +220 -0
- package/bin/exiftool_files/lib/Test/Tester/Capture.pm +241 -0
- package/bin/exiftool_files/lib/Test/Tester/CaptureRunner.pm +79 -0
- package/bin/exiftool_files/lib/Test/Tester/Delegate.pm +45 -0
- package/bin/exiftool_files/lib/Test/Tester.pm +695 -0
- package/bin/exiftool_files/lib/Test/Tutorial.pod +618 -0
- package/bin/exiftool_files/lib/Test/use/ok.pm +64 -0
- package/bin/exiftool_files/lib/Text/ParseWords.pm +303 -0
- package/bin/exiftool_files/lib/Tie/StdHandle.pm +2 -2
- package/bin/exiftool_files/lib/Time/HiRes.pm +73 -68
- package/bin/exiftool_files/lib/Time/Local.pm +82 -35
- package/bin/exiftool_files/lib/Time/Piece.pm +19 -4
- package/bin/exiftool_files/lib/Time/Seconds.pm +1 -1
- package/bin/exiftool_files/lib/UNIVERSAL.pm +203 -0
- package/bin/exiftool_files/lib/Unicode/GCString.pm +60 -0
- package/bin/exiftool_files/lib/Unicode/LineBreak/Constants.pm +68 -0
- package/bin/exiftool_files/lib/Unicode/LineBreak.pm +248 -0
- package/bin/exiftool_files/lib/Win32/API/Struct.pm +1 -177
- package/bin/exiftool_files/lib/Win32/API/Type.pm +1 -100
- package/bin/exiftool_files/lib/Win32/API.pm +1 -830
- package/bin/exiftool_files/lib/Win32/FindFile.pm +2 -123
- package/bin/exiftool_files/lib/Win32.pm +213 -89
- package/bin/exiftool_files/lib/Win32API/File.pm +1 -1
- package/bin/exiftool_files/lib/auto/B/B.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/Compress/Raw/Bzip2/Bzip2.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/Compress/Raw/Lzma/Lzma.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/Compress/Raw/Lzma/autosplit.ix +3 -0
- package/bin/exiftool_files/lib/auto/Compress/Raw/Zlib/Zlib.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/CryptX/CryptX.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/Cwd/Cwd.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/Data/Dumper/Dumper.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/Digest/MD5/MD5.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/Digest/SHA/SHA.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/Encode/Encode.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/Fcntl/Fcntl.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/File/Glob/Glob.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/IO/Compress/Brotli/Brotli.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/IO/IO.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/List/Util/Util.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/MIME/Base64/Base64.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/Math/BigInt/FastCalc/FastCalc.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/Math/BigInt/GMP/GMP.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/POSIX/POSIX.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/PerlIO/scalar/scalar.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/Socket/Socket.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/Storable/Storable.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/Time/HiRes/HiRes.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/Time/Piece/Piece.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/Unicode/LineBreak/LineBreak.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/Win32/API/API.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/Win32/FindFile/FindFile.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/Win32/Win32.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/Win32API/File/File.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/mro/mro.xs.dll +0 -0
- package/bin/exiftool_files/lib/auto/re/re.xs.dll +0 -0
- package/bin/exiftool_files/lib/feature.pm +49 -17
- package/bin/exiftool_files/lib/mro.pm +4 -20
- package/bin/exiftool_files/lib/overload.pm +15 -15
- package/bin/exiftool_files/lib/parent.pm +10 -2
- package/bin/exiftool_files/lib/re.pm +91 -33
- package/bin/exiftool_files/lib/warnings.pm +17 -6
- package/bin/exiftool_files/libgcc_s_seh-1.dll +0 -0
- package/bin/exiftool_files/liblzma-5__.dll +0 -0
- package/bin/exiftool_files/libstdc++-6.dll +0 -0
- package/bin/exiftool_files/libwinpthread-1.dll +0 -0
- package/bin/exiftool_files/perl.exe +0 -0
- package/bin/exiftool_files/perl532.dll +0 -0
- package/package.json +7 -5
- package/bin/exiftool_files/libgcc_s_dw2-1.dll +0 -0
- package/bin/exiftool_files/perl530.dll +0 -0
|
@@ -1,431 +1,431 @@
|
|
|
1
|
-
package Portable::LoadYaml;
|
|
2
|
-
|
|
3
|
-
### UGLY HACK: these functions where completely copied from Parse::CPAN::Meta
|
|
4
|
-
|
|
5
|
-
use 5.008;
|
|
6
|
-
use strict;
|
|
7
|
-
use warnings;
|
|
8
|
-
|
|
9
|
-
our $VERSION = '1.
|
|
10
|
-
|
|
11
|
-
sub load_file {
|
|
12
|
-
my $file = shift;
|
|
13
|
-
my $self = __PACKAGE__->_load_file($file);
|
|
14
|
-
return $self->[-1];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
#####################################################################
|
|
18
|
-
# Constants
|
|
19
|
-
|
|
20
|
-
# Printed form of the unprintable characters in the lowest range
|
|
21
|
-
# of ASCII characters, listed by ASCII ordinal position.
|
|
22
|
-
my @UNPRINTABLE = qw(
|
|
23
|
-
0 x01 x02 x03 x04 x05 x06 a
|
|
24
|
-
b t n v f r x0E x0F
|
|
25
|
-
x10 x11 x12 x13 x14 x15 x16 x17
|
|
26
|
-
x18 x19 x1A e x1C x1D x1E x1F
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
# Printable characters for escapes
|
|
30
|
-
my %UNESCAPES = (
|
|
31
|
-
0 => "\x00", z => "\x00", N => "\x85",
|
|
32
|
-
a => "\x07", b => "\x08", t => "\x09",
|
|
33
|
-
n => "\x0a", v => "\x0b", f => "\x0c",
|
|
34
|
-
r => "\x0d", e => "\x1b", '\\' => '\\',
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
# These 3 values have special meaning when unquoted and using the
|
|
38
|
-
# default YAML schema. They need quotes if they are strings.
|
|
39
|
-
my %QUOTE = map { $_ => 1 } qw{
|
|
40
|
-
null true false
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
# The commented out form is simpler, but overloaded the Perl regex
|
|
44
|
-
# engine due to recursion and backtracking problems on strings
|
|
45
|
-
# larger than 32,000ish characters. Keep it for reference purposes.
|
|
46
|
-
# qr/\"((?:\\.|[^\"])*)\"/
|
|
47
|
-
my $re_capture_double_quoted = qr/\"([^\\"]*(?:\\.[^\\"]*)*)\"/;
|
|
48
|
-
my $re_capture_single_quoted = qr/\'([^\']*(?:\'\'[^\']*)*)\'/;
|
|
49
|
-
# unquoted re gets trailing space that needs to be stripped
|
|
50
|
-
my $re_capture_unquoted_key = qr/([^:]+(?::+\S[^:]*)*)(?=\s*\:(?:\s+|$))/;
|
|
51
|
-
my $re_trailing_comment = qr/(?:\s+\#.*)?/;
|
|
52
|
-
my $re_key_value_separator = qr/\s*:(?:\s+(?:\#.*)?|$)/;
|
|
53
|
-
|
|
54
|
-
###
|
|
55
|
-
# Loader functions:
|
|
56
|
-
|
|
57
|
-
# Create an object from a file
|
|
58
|
-
sub _load_file {
|
|
59
|
-
my $class = ref $_[0] ? ref shift : shift;
|
|
60
|
-
|
|
61
|
-
# Check the file
|
|
62
|
-
my $file = shift or $class->_error( 'You did not specify a file name' );
|
|
63
|
-
$class->_error( "File '$file' does not exist" )
|
|
64
|
-
unless -e $file;
|
|
65
|
-
$class->_error( "'$file' is a directory, not a file" )
|
|
66
|
-
unless -f _;
|
|
67
|
-
$class->_error( "Insufficient permissions to read '$file'" )
|
|
68
|
-
unless -r _;
|
|
69
|
-
|
|
70
|
-
# Open unbuffered
|
|
71
|
-
open( my $fh, "<:unix", $file );
|
|
72
|
-
unless ( $fh ) {
|
|
73
|
-
$class->_error("Failed to open file '$file': $!");
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
# slurp the contents
|
|
77
|
-
my $contents = eval {
|
|
78
|
-
use warnings FATAL => 'utf8';
|
|
79
|
-
local $/;
|
|
80
|
-
<$fh>
|
|
81
|
-
};
|
|
82
|
-
if ( my $err = $@ ) {
|
|
83
|
-
$class->_error("Error reading from file '$file': $err");
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
# close the file (release the lock)
|
|
87
|
-
unless ( close $fh ) {
|
|
88
|
-
$class->_error("Failed to close file '$file': $!");
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
$class->_load_string( $contents );
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
# Create an object from a string
|
|
95
|
-
sub _load_string {
|
|
96
|
-
my $class = ref $_[0] ? ref shift : shift;
|
|
97
|
-
my $self = bless [], $class;
|
|
98
|
-
my $string = $_[0];
|
|
99
|
-
eval {
|
|
100
|
-
unless ( defined $string ) {
|
|
101
|
-
die \"Did not provide a string to load";
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
# Check if Perl has it marked as characters, but it's internally
|
|
105
|
-
# inconsistent. E.g. maybe latin1 got read on a :utf8 layer
|
|
106
|
-
if ( utf8::is_utf8($string) && ! utf8::valid($string) ) {
|
|
107
|
-
die \<<'...';
|
|
108
|
-
Read an invalid UTF-8 string (maybe mixed UTF-8 and 8-bit character set).
|
|
109
|
-
Did you decode with lax ":utf8" instead of strict ":encoding(UTF-8)"?
|
|
110
|
-
...
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
# Ensure Unicode character semantics, even for 0x80-0xff
|
|
114
|
-
utf8::upgrade($string);
|
|
115
|
-
|
|
116
|
-
# Check for and strip any leading UTF-8 BOM
|
|
117
|
-
$string =~ s/^\x{FEFF}//;
|
|
118
|
-
|
|
119
|
-
# Check for some special cases
|
|
120
|
-
return $self unless length $string;
|
|
121
|
-
|
|
122
|
-
# Split the file into lines
|
|
123
|
-
my @lines = grep { ! /^\s*(?:\#.*)?\z/ }
|
|
124
|
-
split /(?:\015{1,2}\012|\015|\012)/, $string;
|
|
125
|
-
|
|
126
|
-
# Strip the initial YAML header
|
|
127
|
-
@lines and $lines[0] =~ /^\%YAML[: ][\d\.]+.*\z/ and shift @lines;
|
|
128
|
-
|
|
129
|
-
# A nibbling parser
|
|
130
|
-
my $in_document = 0;
|
|
131
|
-
while ( @lines ) {
|
|
132
|
-
# Do we have a document header?
|
|
133
|
-
if ( $lines[0] =~ /^---\s*(?:(.+)\s*)?\z/ ) {
|
|
134
|
-
# Handle scalar documents
|
|
135
|
-
shift @lines;
|
|
136
|
-
if ( defined $1 and $1 !~ /^(?:\#.+|\%YAML[: ][\d\.]+)\z/ ) {
|
|
137
|
-
push @$self,
|
|
138
|
-
$self->_load_scalar( "$1", [ undef ], \@lines );
|
|
139
|
-
next;
|
|
140
|
-
}
|
|
141
|
-
$in_document = 1;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if ( ! @lines or $lines[0] =~ /^(?:---|\.\.\.)/ ) {
|
|
145
|
-
# A naked document
|
|
146
|
-
push @$self, undef;
|
|
147
|
-
while ( @lines and $lines[0] !~ /^---/ ) {
|
|
148
|
-
shift @lines;
|
|
149
|
-
}
|
|
150
|
-
$in_document = 0;
|
|
151
|
-
|
|
152
|
-
# XXX The final '-+$' is to look for -- which ends up being an
|
|
153
|
-
# error later.
|
|
154
|
-
} elsif ( ! $in_document && @$self ) {
|
|
155
|
-
# only the first document can be explicit
|
|
156
|
-
die \"failed to classify the line '$lines[0]'";
|
|
157
|
-
} elsif ( $lines[0] =~ /^\s*\-(?:\s|$|-+$)/ ) {
|
|
158
|
-
# An array at the root
|
|
159
|
-
my $document = [ ];
|
|
160
|
-
push @$self, $document;
|
|
161
|
-
$self->_load_array( $document, [ 0 ], \@lines );
|
|
162
|
-
|
|
163
|
-
} elsif ( $lines[0] =~ /^(\s*)\S/ ) {
|
|
164
|
-
# A hash at the root
|
|
165
|
-
my $document = { };
|
|
166
|
-
push @$self, $document;
|
|
167
|
-
$self->_load_hash( $document, [ length($1) ], \@lines );
|
|
168
|
-
|
|
169
|
-
} else {
|
|
170
|
-
# Shouldn't get here. @lines have whitespace-only lines
|
|
171
|
-
# stripped, and previous match is a line with any
|
|
172
|
-
# non-whitespace. So this clause should only be reachable via
|
|
173
|
-
# a perlbug where \s is not symmetric with \S
|
|
174
|
-
|
|
175
|
-
# uncoverable statement
|
|
176
|
-
die \"failed to classify the line '$lines[0]'";
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
};
|
|
180
|
-
if ( ref $@ eq 'SCALAR' ) {
|
|
181
|
-
$self->_error(${$@});
|
|
182
|
-
} elsif ( $@ ) {
|
|
183
|
-
$self->_error($@);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
return $self;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
sub _unquote_single {
|
|
190
|
-
my ($self, $string) = @_;
|
|
191
|
-
return '' unless length $string;
|
|
192
|
-
$string =~ s/\'\'/\'/g;
|
|
193
|
-
return $string;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
sub _unquote_double {
|
|
197
|
-
my ($self, $string) = @_;
|
|
198
|
-
return '' unless length $string;
|
|
199
|
-
$string =~ s/\\"/"/g;
|
|
200
|
-
$string =~
|
|
201
|
-
s{\\([Nnever\\fartz0b]|x([0-9a-fA-F]{2}))}
|
|
202
|
-
{(length($1)>1)?pack("H2",$2):$UNESCAPES{$1}}gex;
|
|
203
|
-
return $string;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
# Load a YAML scalar string to the actual Perl scalar
|
|
207
|
-
sub _load_scalar {
|
|
208
|
-
my ($self, $string, $indent, $lines) = @_;
|
|
209
|
-
|
|
210
|
-
# Trim trailing whitespace
|
|
211
|
-
$string =~ s/\s*\z//;
|
|
212
|
-
|
|
213
|
-
# Explitic null/undef
|
|
214
|
-
return undef if $string eq '~';
|
|
215
|
-
|
|
216
|
-
# Single quote
|
|
217
|
-
if ( $string =~ /^$re_capture_single_quoted$re_trailing_comment\z/ ) {
|
|
218
|
-
return $self->_unquote_single($1);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
# Double quote.
|
|
222
|
-
if ( $string =~ /^$re_capture_double_quoted$re_trailing_comment\z/ ) {
|
|
223
|
-
return $self->_unquote_double($1);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
# Special cases
|
|
227
|
-
if ( $string =~ /^[\'\"!&]/ ) {
|
|
228
|
-
die \"does not support a feature in line '$string'";
|
|
229
|
-
}
|
|
230
|
-
return {} if $string =~ /^{}(?:\s+\#.*)?\z/;
|
|
231
|
-
return [] if $string =~ /^\[\](?:\s+\#.*)?\z/;
|
|
232
|
-
|
|
233
|
-
# Regular unquoted string
|
|
234
|
-
if ( $string !~ /^[>|]/ ) {
|
|
235
|
-
die \"found illegal characters in plain scalar: '$string'"
|
|
236
|
-
if $string =~ /^(?:-(?:\s|$)|[\@\%\`])/ or
|
|
237
|
-
$string =~ /:(?:\s|$)/;
|
|
238
|
-
$string =~ s/\s+#.*\z//;
|
|
239
|
-
return $string;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
# Error
|
|
243
|
-
die \"failed to find multi-line scalar content" unless @$lines;
|
|
244
|
-
|
|
245
|
-
# Check the indent depth
|
|
246
|
-
$lines->[0] =~ /^(\s*)/;
|
|
247
|
-
$indent->[-1] = length("$1");
|
|
248
|
-
if ( defined $indent->[-2] and $indent->[-1] <= $indent->[-2] ) {
|
|
249
|
-
die \"found bad indenting in line '$lines->[0]'";
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
# Pull the lines
|
|
253
|
-
my @multiline = ();
|
|
254
|
-
while ( @$lines ) {
|
|
255
|
-
$lines->[0] =~ /^(\s*)/;
|
|
256
|
-
last unless length($1) >= $indent->[-1];
|
|
257
|
-
push @multiline, substr(shift(@$lines), length($1));
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
my $j = (substr($string, 0, 1) eq '>') ? ' ' : "\n";
|
|
261
|
-
my $t = (substr($string, 1, 1) eq '-') ? '' : "\n";
|
|
262
|
-
return join( $j, @multiline ) . $t;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
# Load an array
|
|
266
|
-
sub _load_array {
|
|
267
|
-
my ($self, $array, $indent, $lines) = @_;
|
|
268
|
-
|
|
269
|
-
while ( @$lines ) {
|
|
270
|
-
# Check for a new document
|
|
271
|
-
if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) {
|
|
272
|
-
while ( @$lines and $lines->[0] !~ /^---/ ) {
|
|
273
|
-
shift @$lines;
|
|
274
|
-
}
|
|
275
|
-
return 1;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
# Check the indent level
|
|
279
|
-
$lines->[0] =~ /^(\s*)/;
|
|
280
|
-
if ( length($1) < $indent->[-1] ) {
|
|
281
|
-
return 1;
|
|
282
|
-
} elsif ( length($1) > $indent->[-1] ) {
|
|
283
|
-
die \"found bad indenting in line '$lines->[0]'";
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
if ( $lines->[0] =~ /^(\s*\-\s+)[^\'\"]\S*\s*:(?:\s+|$)/ ) {
|
|
287
|
-
# Inline nested hash
|
|
288
|
-
my $indent2 = length("$1");
|
|
289
|
-
$lines->[0] =~ s/-/ /;
|
|
290
|
-
push @$array, { };
|
|
291
|
-
$self->_load_hash( $array->[-1], [ @$indent, $indent2 ], $lines );
|
|
292
|
-
|
|
293
|
-
} elsif ( $lines->[0] =~ /^\s*\-\s*\z/ ) {
|
|
294
|
-
shift @$lines;
|
|
295
|
-
unless ( @$lines ) {
|
|
296
|
-
push @$array, undef;
|
|
297
|
-
return 1;
|
|
298
|
-
}
|
|
299
|
-
if ( $lines->[0] =~ /^(\s*)\-/ ) {
|
|
300
|
-
my $indent2 = length("$1");
|
|
301
|
-
if ( $indent->[-1] == $indent2 ) {
|
|
302
|
-
# Null array entry
|
|
303
|
-
push @$array, undef;
|
|
304
|
-
} else {
|
|
305
|
-
# Naked indenter
|
|
306
|
-
push @$array, [ ];
|
|
307
|
-
$self->_load_array(
|
|
308
|
-
$array->[-1], [ @$indent, $indent2 ], $lines
|
|
309
|
-
);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
} elsif ( $lines->[0] =~ /^(\s*)\S/ ) {
|
|
313
|
-
push @$array, { };
|
|
314
|
-
$self->_load_hash(
|
|
315
|
-
$array->[-1], [ @$indent, length("$1") ], $lines
|
|
316
|
-
);
|
|
317
|
-
|
|
318
|
-
} else {
|
|
319
|
-
die \"failed to classify line '$lines->[0]'";
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
} elsif ( $lines->[0] =~ /^\s*\-(\s*)(.+?)\s*\z/ ) {
|
|
323
|
-
# Array entry with a value
|
|
324
|
-
shift @$lines;
|
|
325
|
-
push @$array, $self->_load_scalar(
|
|
326
|
-
"$2", [ @$indent, undef ], $lines
|
|
327
|
-
);
|
|
328
|
-
|
|
329
|
-
} elsif ( defined $indent->[-2] and $indent->[-1] == $indent->[-2] ) {
|
|
330
|
-
# This is probably a structure like the following...
|
|
331
|
-
# ---
|
|
332
|
-
# foo:
|
|
333
|
-
# - list
|
|
334
|
-
# bar: value
|
|
335
|
-
#
|
|
336
|
-
# ... so lets return and let the hash parser handle it
|
|
337
|
-
return 1;
|
|
338
|
-
|
|
339
|
-
} else {
|
|
340
|
-
die \"failed to classify line '$lines->[0]'";
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
return 1;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
# Load a hash
|
|
348
|
-
sub _load_hash {
|
|
349
|
-
my ($self, $hash, $indent, $lines) = @_;
|
|
350
|
-
|
|
351
|
-
while ( @$lines ) {
|
|
352
|
-
# Check for a new document
|
|
353
|
-
if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) {
|
|
354
|
-
while ( @$lines and $lines->[0] !~ /^---/ ) {
|
|
355
|
-
shift @$lines;
|
|
356
|
-
}
|
|
357
|
-
return 1;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
# Check the indent level
|
|
361
|
-
$lines->[0] =~ /^(\s*)/;
|
|
362
|
-
if ( length($1) < $indent->[-1] ) {
|
|
363
|
-
return 1;
|
|
364
|
-
} elsif ( length($1) > $indent->[-1] ) {
|
|
365
|
-
die \"found bad indenting in line '$lines->[0]'";
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
# Find the key
|
|
369
|
-
my $key;
|
|
370
|
-
|
|
371
|
-
# Quoted keys
|
|
372
|
-
if ( $lines->[0] =~
|
|
373
|
-
s/^\s*$re_capture_single_quoted$re_key_value_separator//
|
|
374
|
-
) {
|
|
375
|
-
$key = $self->_unquote_single($1);
|
|
376
|
-
}
|
|
377
|
-
elsif ( $lines->[0] =~
|
|
378
|
-
s/^\s*$re_capture_double_quoted$re_key_value_separator//
|
|
379
|
-
) {
|
|
380
|
-
$key = $self->_unquote_double($1);
|
|
381
|
-
}
|
|
382
|
-
elsif ( $lines->[0] =~
|
|
383
|
-
s/^\s*$re_capture_unquoted_key$re_key_value_separator//
|
|
384
|
-
) {
|
|
385
|
-
$key = $1;
|
|
386
|
-
$key =~ s/\s+$//;
|
|
387
|
-
}
|
|
388
|
-
elsif ( $lines->[0] =~ /^\s*\?/ ) {
|
|
389
|
-
die \"does not support a feature in line '$lines->[0]'";
|
|
390
|
-
}
|
|
391
|
-
else {
|
|
392
|
-
die \"failed to classify line '$lines->[0]'";
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
# Do we have a value?
|
|
396
|
-
if ( length $lines->[0] ) {
|
|
397
|
-
# Yes
|
|
398
|
-
$hash->{$key} = $self->_load_scalar(
|
|
399
|
-
shift(@$lines), [ @$indent, undef ], $lines
|
|
400
|
-
);
|
|
401
|
-
} else {
|
|
402
|
-
# An indent
|
|
403
|
-
shift @$lines;
|
|
404
|
-
unless ( @$lines ) {
|
|
405
|
-
$hash->{$key} = undef;
|
|
406
|
-
return 1;
|
|
407
|
-
}
|
|
408
|
-
if ( $lines->[0] =~ /^(\s*)-/ ) {
|
|
409
|
-
$hash->{$key} = [];
|
|
410
|
-
$self->_load_array(
|
|
411
|
-
$hash->{$key}, [ @$indent, length($1) ], $lines
|
|
412
|
-
);
|
|
413
|
-
} elsif ( $lines->[0] =~ /^(\s*)./ ) {
|
|
414
|
-
my $indent2 = length("$1");
|
|
415
|
-
if ( $indent->[-1] >= $indent2 ) {
|
|
416
|
-
# Null hash entry
|
|
417
|
-
$hash->{$key} = undef;
|
|
418
|
-
} else {
|
|
419
|
-
$hash->{$key} = {};
|
|
420
|
-
$self->_load_hash(
|
|
421
|
-
$hash->{$key}, [ @$indent, length($1) ], $lines
|
|
422
|
-
);
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
return 1;
|
|
429
|
-
}
|
|
430
|
-
|
|
1
|
+
package Portable::LoadYaml;
|
|
2
|
+
|
|
3
|
+
### UGLY HACK: these functions where completely copied from Parse::CPAN::Meta
|
|
4
|
+
|
|
5
|
+
use 5.008;
|
|
6
|
+
use strict;
|
|
7
|
+
use warnings;
|
|
8
|
+
|
|
9
|
+
our $VERSION = '1.23';
|
|
10
|
+
|
|
11
|
+
sub load_file {
|
|
12
|
+
my $file = shift;
|
|
13
|
+
my $self = __PACKAGE__->_load_file($file);
|
|
14
|
+
return $self->[-1];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
#####################################################################
|
|
18
|
+
# Constants
|
|
19
|
+
|
|
20
|
+
# Printed form of the unprintable characters in the lowest range
|
|
21
|
+
# of ASCII characters, listed by ASCII ordinal position.
|
|
22
|
+
my @UNPRINTABLE = qw(
|
|
23
|
+
0 x01 x02 x03 x04 x05 x06 a
|
|
24
|
+
b t n v f r x0E x0F
|
|
25
|
+
x10 x11 x12 x13 x14 x15 x16 x17
|
|
26
|
+
x18 x19 x1A e x1C x1D x1E x1F
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
# Printable characters for escapes
|
|
30
|
+
my %UNESCAPES = (
|
|
31
|
+
0 => "\x00", z => "\x00", N => "\x85",
|
|
32
|
+
a => "\x07", b => "\x08", t => "\x09",
|
|
33
|
+
n => "\x0a", v => "\x0b", f => "\x0c",
|
|
34
|
+
r => "\x0d", e => "\x1b", '\\' => '\\',
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
# These 3 values have special meaning when unquoted and using the
|
|
38
|
+
# default YAML schema. They need quotes if they are strings.
|
|
39
|
+
my %QUOTE = map { $_ => 1 } qw{
|
|
40
|
+
null true false
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
# The commented out form is simpler, but overloaded the Perl regex
|
|
44
|
+
# engine due to recursion and backtracking problems on strings
|
|
45
|
+
# larger than 32,000ish characters. Keep it for reference purposes.
|
|
46
|
+
# qr/\"((?:\\.|[^\"])*)\"/
|
|
47
|
+
my $re_capture_double_quoted = qr/\"([^\\"]*(?:\\.[^\\"]*)*)\"/;
|
|
48
|
+
my $re_capture_single_quoted = qr/\'([^\']*(?:\'\'[^\']*)*)\'/;
|
|
49
|
+
# unquoted re gets trailing space that needs to be stripped
|
|
50
|
+
my $re_capture_unquoted_key = qr/([^:]+(?::+\S[^:]*)*)(?=\s*\:(?:\s+|$))/;
|
|
51
|
+
my $re_trailing_comment = qr/(?:\s+\#.*)?/;
|
|
52
|
+
my $re_key_value_separator = qr/\s*:(?:\s+(?:\#.*)?|$)/;
|
|
53
|
+
|
|
54
|
+
###
|
|
55
|
+
# Loader functions:
|
|
56
|
+
|
|
57
|
+
# Create an object from a file
|
|
58
|
+
sub _load_file {
|
|
59
|
+
my $class = ref $_[0] ? ref shift : shift;
|
|
60
|
+
|
|
61
|
+
# Check the file
|
|
62
|
+
my $file = shift or $class->_error( 'You did not specify a file name' );
|
|
63
|
+
$class->_error( "File '$file' does not exist" )
|
|
64
|
+
unless -e $file;
|
|
65
|
+
$class->_error( "'$file' is a directory, not a file" )
|
|
66
|
+
unless -f _;
|
|
67
|
+
$class->_error( "Insufficient permissions to read '$file'" )
|
|
68
|
+
unless -r _;
|
|
69
|
+
|
|
70
|
+
# Open unbuffered
|
|
71
|
+
open( my $fh, "<:unix", $file );
|
|
72
|
+
unless ( $fh ) {
|
|
73
|
+
$class->_error("Failed to open file '$file': $!");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
# slurp the contents
|
|
77
|
+
my $contents = eval {
|
|
78
|
+
use warnings FATAL => 'utf8';
|
|
79
|
+
local $/;
|
|
80
|
+
<$fh>
|
|
81
|
+
};
|
|
82
|
+
if ( my $err = $@ ) {
|
|
83
|
+
$class->_error("Error reading from file '$file': $err");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
# close the file (release the lock)
|
|
87
|
+
unless ( close $fh ) {
|
|
88
|
+
$class->_error("Failed to close file '$file': $!");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
$class->_load_string( $contents );
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# Create an object from a string
|
|
95
|
+
sub _load_string {
|
|
96
|
+
my $class = ref $_[0] ? ref shift : shift;
|
|
97
|
+
my $self = bless [], $class;
|
|
98
|
+
my $string = $_[0];
|
|
99
|
+
eval {
|
|
100
|
+
unless ( defined $string ) {
|
|
101
|
+
die \"Did not provide a string to load";
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
# Check if Perl has it marked as characters, but it's internally
|
|
105
|
+
# inconsistent. E.g. maybe latin1 got read on a :utf8 layer
|
|
106
|
+
if ( utf8::is_utf8($string) && ! utf8::valid($string) ) {
|
|
107
|
+
die \<<'...';
|
|
108
|
+
Read an invalid UTF-8 string (maybe mixed UTF-8 and 8-bit character set).
|
|
109
|
+
Did you decode with lax ":utf8" instead of strict ":encoding(UTF-8)"?
|
|
110
|
+
...
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
# Ensure Unicode character semantics, even for 0x80-0xff
|
|
114
|
+
utf8::upgrade($string);
|
|
115
|
+
|
|
116
|
+
# Check for and strip any leading UTF-8 BOM
|
|
117
|
+
$string =~ s/^\x{FEFF}//;
|
|
118
|
+
|
|
119
|
+
# Check for some special cases
|
|
120
|
+
return $self unless length $string;
|
|
121
|
+
|
|
122
|
+
# Split the file into lines
|
|
123
|
+
my @lines = grep { ! /^\s*(?:\#.*)?\z/ }
|
|
124
|
+
split /(?:\015{1,2}\012|\015|\012)/, $string;
|
|
125
|
+
|
|
126
|
+
# Strip the initial YAML header
|
|
127
|
+
@lines and $lines[0] =~ /^\%YAML[: ][\d\.]+.*\z/ and shift @lines;
|
|
128
|
+
|
|
129
|
+
# A nibbling parser
|
|
130
|
+
my $in_document = 0;
|
|
131
|
+
while ( @lines ) {
|
|
132
|
+
# Do we have a document header?
|
|
133
|
+
if ( $lines[0] =~ /^---\s*(?:(.+)\s*)?\z/ ) {
|
|
134
|
+
# Handle scalar documents
|
|
135
|
+
shift @lines;
|
|
136
|
+
if ( defined $1 and $1 !~ /^(?:\#.+|\%YAML[: ][\d\.]+)\z/ ) {
|
|
137
|
+
push @$self,
|
|
138
|
+
$self->_load_scalar( "$1", [ undef ], \@lines );
|
|
139
|
+
next;
|
|
140
|
+
}
|
|
141
|
+
$in_document = 1;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if ( ! @lines or $lines[0] =~ /^(?:---|\.\.\.)/ ) {
|
|
145
|
+
# A naked document
|
|
146
|
+
push @$self, undef;
|
|
147
|
+
while ( @lines and $lines[0] !~ /^---/ ) {
|
|
148
|
+
shift @lines;
|
|
149
|
+
}
|
|
150
|
+
$in_document = 0;
|
|
151
|
+
|
|
152
|
+
# XXX The final '-+$' is to look for -- which ends up being an
|
|
153
|
+
# error later.
|
|
154
|
+
} elsif ( ! $in_document && @$self ) {
|
|
155
|
+
# only the first document can be explicit
|
|
156
|
+
die \"failed to classify the line '$lines[0]'";
|
|
157
|
+
} elsif ( $lines[0] =~ /^\s*\-(?:\s|$|-+$)/ ) {
|
|
158
|
+
# An array at the root
|
|
159
|
+
my $document = [ ];
|
|
160
|
+
push @$self, $document;
|
|
161
|
+
$self->_load_array( $document, [ 0 ], \@lines );
|
|
162
|
+
|
|
163
|
+
} elsif ( $lines[0] =~ /^(\s*)\S/ ) {
|
|
164
|
+
# A hash at the root
|
|
165
|
+
my $document = { };
|
|
166
|
+
push @$self, $document;
|
|
167
|
+
$self->_load_hash( $document, [ length($1) ], \@lines );
|
|
168
|
+
|
|
169
|
+
} else {
|
|
170
|
+
# Shouldn't get here. @lines have whitespace-only lines
|
|
171
|
+
# stripped, and previous match is a line with any
|
|
172
|
+
# non-whitespace. So this clause should only be reachable via
|
|
173
|
+
# a perlbug where \s is not symmetric with \S
|
|
174
|
+
|
|
175
|
+
# uncoverable statement
|
|
176
|
+
die \"failed to classify the line '$lines[0]'";
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
if ( ref $@ eq 'SCALAR' ) {
|
|
181
|
+
$self->_error(${$@});
|
|
182
|
+
} elsif ( $@ ) {
|
|
183
|
+
$self->_error($@);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return $self;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
sub _unquote_single {
|
|
190
|
+
my ($self, $string) = @_;
|
|
191
|
+
return '' unless length $string;
|
|
192
|
+
$string =~ s/\'\'/\'/g;
|
|
193
|
+
return $string;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
sub _unquote_double {
|
|
197
|
+
my ($self, $string) = @_;
|
|
198
|
+
return '' unless length $string;
|
|
199
|
+
$string =~ s/\\"/"/g;
|
|
200
|
+
$string =~
|
|
201
|
+
s{\\([Nnever\\fartz0b]|x([0-9a-fA-F]{2}))}
|
|
202
|
+
{(length($1)>1)?pack("H2",$2):$UNESCAPES{$1}}gex;
|
|
203
|
+
return $string;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
# Load a YAML scalar string to the actual Perl scalar
|
|
207
|
+
sub _load_scalar {
|
|
208
|
+
my ($self, $string, $indent, $lines) = @_;
|
|
209
|
+
|
|
210
|
+
# Trim trailing whitespace
|
|
211
|
+
$string =~ s/\s*\z//;
|
|
212
|
+
|
|
213
|
+
# Explitic null/undef
|
|
214
|
+
return undef if $string eq '~';
|
|
215
|
+
|
|
216
|
+
# Single quote
|
|
217
|
+
if ( $string =~ /^$re_capture_single_quoted$re_trailing_comment\z/ ) {
|
|
218
|
+
return $self->_unquote_single($1);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
# Double quote.
|
|
222
|
+
if ( $string =~ /^$re_capture_double_quoted$re_trailing_comment\z/ ) {
|
|
223
|
+
return $self->_unquote_double($1);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
# Special cases
|
|
227
|
+
if ( $string =~ /^[\'\"!&]/ ) {
|
|
228
|
+
die \"does not support a feature in line '$string'";
|
|
229
|
+
}
|
|
230
|
+
return {} if $string =~ /^{}(?:\s+\#.*)?\z/;
|
|
231
|
+
return [] if $string =~ /^\[\](?:\s+\#.*)?\z/;
|
|
232
|
+
|
|
233
|
+
# Regular unquoted string
|
|
234
|
+
if ( $string !~ /^[>|]/ ) {
|
|
235
|
+
die \"found illegal characters in plain scalar: '$string'"
|
|
236
|
+
if $string =~ /^(?:-(?:\s|$)|[\@\%\`])/ or
|
|
237
|
+
$string =~ /:(?:\s|$)/;
|
|
238
|
+
$string =~ s/\s+#.*\z//;
|
|
239
|
+
return $string;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
# Error
|
|
243
|
+
die \"failed to find multi-line scalar content" unless @$lines;
|
|
244
|
+
|
|
245
|
+
# Check the indent depth
|
|
246
|
+
$lines->[0] =~ /^(\s*)/;
|
|
247
|
+
$indent->[-1] = length("$1");
|
|
248
|
+
if ( defined $indent->[-2] and $indent->[-1] <= $indent->[-2] ) {
|
|
249
|
+
die \"found bad indenting in line '$lines->[0]'";
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
# Pull the lines
|
|
253
|
+
my @multiline = ();
|
|
254
|
+
while ( @$lines ) {
|
|
255
|
+
$lines->[0] =~ /^(\s*)/;
|
|
256
|
+
last unless length($1) >= $indent->[-1];
|
|
257
|
+
push @multiline, substr(shift(@$lines), length($1));
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
my $j = (substr($string, 0, 1) eq '>') ? ' ' : "\n";
|
|
261
|
+
my $t = (substr($string, 1, 1) eq '-') ? '' : "\n";
|
|
262
|
+
return join( $j, @multiline ) . $t;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
# Load an array
|
|
266
|
+
sub _load_array {
|
|
267
|
+
my ($self, $array, $indent, $lines) = @_;
|
|
268
|
+
|
|
269
|
+
while ( @$lines ) {
|
|
270
|
+
# Check for a new document
|
|
271
|
+
if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) {
|
|
272
|
+
while ( @$lines and $lines->[0] !~ /^---/ ) {
|
|
273
|
+
shift @$lines;
|
|
274
|
+
}
|
|
275
|
+
return 1;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
# Check the indent level
|
|
279
|
+
$lines->[0] =~ /^(\s*)/;
|
|
280
|
+
if ( length($1) < $indent->[-1] ) {
|
|
281
|
+
return 1;
|
|
282
|
+
} elsif ( length($1) > $indent->[-1] ) {
|
|
283
|
+
die \"found bad indenting in line '$lines->[0]'";
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if ( $lines->[0] =~ /^(\s*\-\s+)[^\'\"]\S*\s*:(?:\s+|$)/ ) {
|
|
287
|
+
# Inline nested hash
|
|
288
|
+
my $indent2 = length("$1");
|
|
289
|
+
$lines->[0] =~ s/-/ /;
|
|
290
|
+
push @$array, { };
|
|
291
|
+
$self->_load_hash( $array->[-1], [ @$indent, $indent2 ], $lines );
|
|
292
|
+
|
|
293
|
+
} elsif ( $lines->[0] =~ /^\s*\-\s*\z/ ) {
|
|
294
|
+
shift @$lines;
|
|
295
|
+
unless ( @$lines ) {
|
|
296
|
+
push @$array, undef;
|
|
297
|
+
return 1;
|
|
298
|
+
}
|
|
299
|
+
if ( $lines->[0] =~ /^(\s*)\-/ ) {
|
|
300
|
+
my $indent2 = length("$1");
|
|
301
|
+
if ( $indent->[-1] == $indent2 ) {
|
|
302
|
+
# Null array entry
|
|
303
|
+
push @$array, undef;
|
|
304
|
+
} else {
|
|
305
|
+
# Naked indenter
|
|
306
|
+
push @$array, [ ];
|
|
307
|
+
$self->_load_array(
|
|
308
|
+
$array->[-1], [ @$indent, $indent2 ], $lines
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
} elsif ( $lines->[0] =~ /^(\s*)\S/ ) {
|
|
313
|
+
push @$array, { };
|
|
314
|
+
$self->_load_hash(
|
|
315
|
+
$array->[-1], [ @$indent, length("$1") ], $lines
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
} else {
|
|
319
|
+
die \"failed to classify line '$lines->[0]'";
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
} elsif ( $lines->[0] =~ /^\s*\-(\s*)(.+?)\s*\z/ ) {
|
|
323
|
+
# Array entry with a value
|
|
324
|
+
shift @$lines;
|
|
325
|
+
push @$array, $self->_load_scalar(
|
|
326
|
+
"$2", [ @$indent, undef ], $lines
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
} elsif ( defined $indent->[-2] and $indent->[-1] == $indent->[-2] ) {
|
|
330
|
+
# This is probably a structure like the following...
|
|
331
|
+
# ---
|
|
332
|
+
# foo:
|
|
333
|
+
# - list
|
|
334
|
+
# bar: value
|
|
335
|
+
#
|
|
336
|
+
# ... so lets return and let the hash parser handle it
|
|
337
|
+
return 1;
|
|
338
|
+
|
|
339
|
+
} else {
|
|
340
|
+
die \"failed to classify line '$lines->[0]'";
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return 1;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
# Load a hash
|
|
348
|
+
sub _load_hash {
|
|
349
|
+
my ($self, $hash, $indent, $lines) = @_;
|
|
350
|
+
|
|
351
|
+
while ( @$lines ) {
|
|
352
|
+
# Check for a new document
|
|
353
|
+
if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) {
|
|
354
|
+
while ( @$lines and $lines->[0] !~ /^---/ ) {
|
|
355
|
+
shift @$lines;
|
|
356
|
+
}
|
|
357
|
+
return 1;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
# Check the indent level
|
|
361
|
+
$lines->[0] =~ /^(\s*)/;
|
|
362
|
+
if ( length($1) < $indent->[-1] ) {
|
|
363
|
+
return 1;
|
|
364
|
+
} elsif ( length($1) > $indent->[-1] ) {
|
|
365
|
+
die \"found bad indenting in line '$lines->[0]'";
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
# Find the key
|
|
369
|
+
my $key;
|
|
370
|
+
|
|
371
|
+
# Quoted keys
|
|
372
|
+
if ( $lines->[0] =~
|
|
373
|
+
s/^\s*$re_capture_single_quoted$re_key_value_separator//
|
|
374
|
+
) {
|
|
375
|
+
$key = $self->_unquote_single($1);
|
|
376
|
+
}
|
|
377
|
+
elsif ( $lines->[0] =~
|
|
378
|
+
s/^\s*$re_capture_double_quoted$re_key_value_separator//
|
|
379
|
+
) {
|
|
380
|
+
$key = $self->_unquote_double($1);
|
|
381
|
+
}
|
|
382
|
+
elsif ( $lines->[0] =~
|
|
383
|
+
s/^\s*$re_capture_unquoted_key$re_key_value_separator//
|
|
384
|
+
) {
|
|
385
|
+
$key = $1;
|
|
386
|
+
$key =~ s/\s+$//;
|
|
387
|
+
}
|
|
388
|
+
elsif ( $lines->[0] =~ /^\s*\?/ ) {
|
|
389
|
+
die \"does not support a feature in line '$lines->[0]'";
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
die \"failed to classify line '$lines->[0]'";
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
# Do we have a value?
|
|
396
|
+
if ( length $lines->[0] ) {
|
|
397
|
+
# Yes
|
|
398
|
+
$hash->{$key} = $self->_load_scalar(
|
|
399
|
+
shift(@$lines), [ @$indent, undef ], $lines
|
|
400
|
+
);
|
|
401
|
+
} else {
|
|
402
|
+
# An indent
|
|
403
|
+
shift @$lines;
|
|
404
|
+
unless ( @$lines ) {
|
|
405
|
+
$hash->{$key} = undef;
|
|
406
|
+
return 1;
|
|
407
|
+
}
|
|
408
|
+
if ( $lines->[0] =~ /^(\s*)-/ ) {
|
|
409
|
+
$hash->{$key} = [];
|
|
410
|
+
$self->_load_array(
|
|
411
|
+
$hash->{$key}, [ @$indent, length($1) ], $lines
|
|
412
|
+
);
|
|
413
|
+
} elsif ( $lines->[0] =~ /^(\s*)./ ) {
|
|
414
|
+
my $indent2 = length("$1");
|
|
415
|
+
if ( $indent->[-1] >= $indent2 ) {
|
|
416
|
+
# Null hash entry
|
|
417
|
+
$hash->{$key} = undef;
|
|
418
|
+
} else {
|
|
419
|
+
$hash->{$key} = {};
|
|
420
|
+
$self->_load_hash(
|
|
421
|
+
$hash->{$key}, [ @$indent, length($1) ], $lines
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return 1;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
431
|
1;
|