exiftool-vendored.exe 12.82.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.
Files changed (225) hide show
  1. package/README.md +6 -0
  2. package/bin/exiftool.exe +0 -0
  3. package/bin/exiftool_files/Licenses_Strawberry_Perl.zip +0 -0
  4. package/bin/exiftool_files/lib/Archive/Zip/Archive.pm +399 -65
  5. package/bin/exiftool_files/lib/Archive/Zip/DirectoryMember.pm +1 -1
  6. package/bin/exiftool_files/lib/Archive/Zip/FileMember.pm +1 -1
  7. package/bin/exiftool_files/lib/Archive/Zip/Member.pm +499 -195
  8. package/bin/exiftool_files/lib/Archive/Zip/NewFileMember.pm +1 -1
  9. package/bin/exiftool_files/lib/Archive/Zip/StringMember.pm +2 -2
  10. package/bin/exiftool_files/lib/Archive/Zip/ZipFileMember.pm +79 -20
  11. package/bin/exiftool_files/lib/Archive/Zip.pm +179 -29
  12. package/bin/exiftool_files/lib/AutoLoader.pm +453 -0
  13. package/bin/exiftool_files/lib/B/Deparse.pm +209 -137
  14. package/bin/exiftool_files/lib/B.pm +1 -1
  15. package/bin/exiftool_files/lib/Benchmark.pm +1123 -0
  16. package/bin/exiftool_files/lib/Class/Struct.pm +2 -2
  17. package/bin/exiftool_files/lib/Compress/Raw/Bzip2.pm +14 -9
  18. package/bin/exiftool_files/lib/Compress/Raw/Lzma.pm +982 -0
  19. package/bin/exiftool_files/lib/Compress/Raw/Zlib.pm +91 -86
  20. package/bin/exiftool_files/lib/Compress/Zlib.pm +105 -100
  21. package/bin/exiftool_files/lib/Config.pm +9 -9
  22. package/bin/exiftool_files/lib/Config_heavy.pl +36 -33
  23. package/bin/exiftool_files/lib/CryptX.pm +2 -82
  24. package/bin/exiftool_files/lib/Data/Dumper.pm +2 -2
  25. package/bin/exiftool_files/lib/Digest/MD5.pm +12 -9
  26. package/bin/exiftool_files/lib/Digest/Perl/MD5.pm +1 -191
  27. package/bin/exiftool_files/lib/Digest/base.pm +26 -20
  28. package/bin/exiftool_files/lib/DynaLoader.pm +7 -4
  29. package/bin/exiftool_files/lib/Encode.pm +3 -3
  30. package/bin/exiftool_files/lib/Errno.pm +13 -13
  31. package/bin/exiftool_files/lib/Exporter/Heavy.pm +2 -2
  32. package/bin/exiftool_files/lib/Exporter.pm +1 -1
  33. package/bin/exiftool_files/lib/ExtUtils/Command/MM.pm +323 -0
  34. package/bin/exiftool_files/lib/ExtUtils/Command.pm +382 -0
  35. package/bin/exiftool_files/lib/File/Find.pm +1 -1
  36. package/bin/exiftool_files/lib/File/Glob.pm +1 -8
  37. package/bin/exiftool_files/lib/File/GlobMapper.pm +2 -2
  38. package/bin/exiftool_files/lib/File/HomeDir/Darwin/Carbon.pm +2 -40
  39. package/bin/exiftool_files/lib/File/HomeDir/Darwin/Cocoa.pm +2 -34
  40. package/bin/exiftool_files/lib/File/HomeDir/Darwin.pm +2 -28
  41. package/bin/exiftool_files/lib/File/HomeDir/Driver.pm +2 -35
  42. package/bin/exiftool_files/lib/File/HomeDir/FreeDesktop.pm +2 -62
  43. package/bin/exiftool_files/lib/File/HomeDir/MacOS9.pm +2 -53
  44. package/bin/exiftool_files/lib/File/HomeDir/Test.pm +2 -43
  45. package/bin/exiftool_files/lib/File/HomeDir/Unix.pm +2 -53
  46. package/bin/exiftool_files/lib/File/HomeDir/Windows.pm +2 -69
  47. package/bin/exiftool_files/lib/File/HomeDir.pm +5 -416
  48. package/bin/exiftool_files/lib/File/Path.pm +3 -3
  49. package/bin/exiftool_files/lib/File/Spec/Win32.pm +2 -2
  50. package/bin/exiftool_files/lib/File/Temp.pm +70 -35
  51. package/bin/exiftool_files/lib/File/Which.pm +1 -240
  52. package/bin/exiftool_files/lib/File/stat.pm +3 -2
  53. package/bin/exiftool_files/lib/IO/Compress/Adapter/Bzip2.pm +16 -17
  54. package/bin/exiftool_files/lib/IO/Compress/Adapter/Deflate.pm +19 -20
  55. package/bin/exiftool_files/lib/IO/Compress/Base/Common.pm +5 -5
  56. package/bin/exiftool_files/lib/IO/Compress/Base.pm +35 -26
  57. package/bin/exiftool_files/lib/IO/Compress/Brotli.pm +159 -0
  58. package/bin/exiftool_files/lib/IO/Compress/Bzip2.pm +50 -25
  59. package/bin/exiftool_files/lib/IO/Compress/Gzip/Constants.pm +6 -6
  60. package/bin/exiftool_files/lib/IO/Compress/Gzip.pm +58 -32
  61. package/bin/exiftool_files/lib/IO/Compress/RawDeflate.pm +63 -38
  62. package/bin/exiftool_files/lib/IO/Compress/Zlib/Extra.pm +20 -20
  63. package/bin/exiftool_files/lib/IO/Dir.pm +1 -1
  64. package/bin/exiftool_files/lib/IO/File.pm +1 -1
  65. package/bin/exiftool_files/lib/IO/Handle.pm +1 -21
  66. package/bin/exiftool_files/lib/IO/Pipe.pm +1 -1
  67. package/bin/exiftool_files/lib/IO/Seekable.pm +1 -1
  68. package/bin/exiftool_files/lib/IO/Select.pm +16 -2
  69. package/bin/exiftool_files/lib/IO/Socket/INET.pm +14 -9
  70. package/bin/exiftool_files/lib/IO/Socket/UNIX.pm +17 -1
  71. package/bin/exiftool_files/lib/IO/Socket.pm +474 -126
  72. package/bin/exiftool_files/lib/IO/String.pm +425 -0
  73. package/bin/exiftool_files/lib/IO/Uncompress/Adapter/Inflate.pm +13 -14
  74. package/bin/exiftool_files/lib/IO/Uncompress/Base.pm +142 -132
  75. package/bin/exiftool_files/lib/IO/Uncompress/Brotli.pm +119 -0
  76. package/bin/exiftool_files/lib/IO/Uncompress/Gunzip.pm +43 -37
  77. package/bin/exiftool_files/lib/IO/Uncompress/RawInflate.pm +49 -43
  78. package/bin/exiftool_files/lib/IO.pm +2 -2
  79. package/bin/exiftool_files/lib/List/Util.pm +97 -8
  80. package/bin/exiftool_files/lib/MIME/Base64.pm +5 -5
  81. package/bin/exiftool_files/lib/MIME/Charset/_Compat.pm +106 -0
  82. package/bin/exiftool_files/lib/MIME/Charset.pm +1303 -0
  83. package/bin/exiftool_files/lib/Math/BigFloat.pm +444 -27
  84. package/bin/exiftool_files/lib/Math/BigInt/Calc.pm +296 -313
  85. package/bin/exiftool_files/lib/Math/BigInt/FastCalc.pm +1 -1
  86. package/bin/exiftool_files/lib/Math/BigInt/GMP.pm +2 -115
  87. package/bin/exiftool_files/lib/Math/BigInt/LTM.pm +2 -24
  88. package/bin/exiftool_files/lib/Math/BigInt/Lib.pm +61 -32
  89. package/bin/exiftool_files/lib/Math/BigInt.pm +292 -107
  90. package/bin/exiftool_files/lib/POSIX.pm +1 -1
  91. package/bin/exiftool_files/lib/PerlIO/scalar.pm +41 -0
  92. package/bin/exiftool_files/lib/PerlIO.pm +397 -0
  93. package/bin/exiftool_files/lib/Portable/CPAN.pm +94 -94
  94. package/bin/exiftool_files/lib/Portable/Config.pm +94 -94
  95. package/bin/exiftool_files/lib/Portable/FileSpec.pm +180 -180
  96. package/bin/exiftool_files/lib/Portable/HomeDir.pm +110 -110
  97. package/bin/exiftool_files/lib/Portable/LoadYaml.pm +430 -430
  98. package/bin/exiftool_files/lib/Portable/minicpan.pm +55 -55
  99. package/bin/exiftool_files/lib/Portable.pm +246 -320
  100. package/bin/exiftool_files/lib/Scalar/Util.pm +9 -4
  101. package/bin/exiftool_files/lib/Socket.pm +16 -12
  102. package/bin/exiftool_files/lib/Storable.pm +1444 -1441
  103. package/bin/exiftool_files/lib/TAP/Base.pm +133 -0
  104. package/bin/exiftool_files/lib/TAP/Formatter/Base.pm +467 -0
  105. package/bin/exiftool_files/lib/TAP/Formatter/Color.pm +116 -0
  106. package/bin/exiftool_files/lib/TAP/Formatter/Console/ParallelSession.pm +201 -0
  107. package/bin/exiftool_files/lib/TAP/Formatter/Console/Session.pm +205 -0
  108. package/bin/exiftool_files/lib/TAP/Formatter/Console.pm +100 -0
  109. package/bin/exiftool_files/lib/TAP/Formatter/File/Session.pm +95 -0
  110. package/bin/exiftool_files/lib/TAP/Formatter/File.pm +56 -0
  111. package/bin/exiftool_files/lib/TAP/Formatter/Session.pm +220 -0
  112. package/bin/exiftool_files/lib/TAP/Harness/Beyond.pod +426 -0
  113. package/bin/exiftool_files/lib/TAP/Harness/Env.pm +215 -0
  114. package/bin/exiftool_files/lib/TAP/Harness.pm +1054 -0
  115. package/bin/exiftool_files/lib/TAP/Object.pm +155 -0
  116. package/bin/exiftool_files/lib/TAP/Parser/Aggregator.pm +414 -0
  117. package/bin/exiftool_files/lib/TAP/Parser/Grammar.pm +584 -0
  118. package/bin/exiftool_files/lib/TAP/Parser/Iterator/Array.pm +100 -0
  119. package/bin/exiftool_files/lib/TAP/Parser/Iterator/Process.pm +378 -0
  120. package/bin/exiftool_files/lib/TAP/Parser/Iterator/Stream.pm +116 -0
  121. package/bin/exiftool_files/lib/TAP/Parser/Iterator.pm +162 -0
  122. package/bin/exiftool_files/lib/TAP/Parser/IteratorFactory.pm +339 -0
  123. package/bin/exiftool_files/lib/TAP/Parser/Multiplexer.pm +194 -0
  124. package/bin/exiftool_files/lib/TAP/Parser/Result/Bailout.pm +62 -0
  125. package/bin/exiftool_files/lib/TAP/Parser/Result/Comment.pm +60 -0
  126. package/bin/exiftool_files/lib/TAP/Parser/Result/Plan.pm +119 -0
  127. package/bin/exiftool_files/lib/TAP/Parser/Result/Pragma.pm +62 -0
  128. package/bin/exiftool_files/lib/TAP/Parser/Result/Test.pm +271 -0
  129. package/bin/exiftool_files/lib/TAP/Parser/Result/Unknown.pm +48 -0
  130. package/bin/exiftool_files/lib/TAP/Parser/Result/Version.pm +62 -0
  131. package/bin/exiftool_files/lib/TAP/Parser/Result/YAML.pm +61 -0
  132. package/bin/exiftool_files/lib/TAP/Parser/Result.pm +297 -0
  133. package/bin/exiftool_files/lib/TAP/Parser/ResultFactory.pm +183 -0
  134. package/bin/exiftool_files/lib/TAP/Parser/Scheduler/Job.pm +127 -0
  135. package/bin/exiftool_files/lib/TAP/Parser/Scheduler/Spinner.pm +61 -0
  136. package/bin/exiftool_files/lib/TAP/Parser/Scheduler.pm +448 -0
  137. package/bin/exiftool_files/lib/TAP/Parser/Source.pm +381 -0
  138. package/bin/exiftool_files/lib/TAP/Parser/SourceHandler/Executable.pm +184 -0
  139. package/bin/exiftool_files/lib/TAP/Parser/SourceHandler/File.pm +136 -0
  140. package/bin/exiftool_files/lib/TAP/Parser/SourceHandler/Handle.pm +124 -0
  141. package/bin/exiftool_files/lib/TAP/Parser/SourceHandler/Perl.pm +370 -0
  142. package/bin/exiftool_files/lib/TAP/Parser/SourceHandler/RawTAP.pm +130 -0
  143. package/bin/exiftool_files/lib/TAP/Parser/SourceHandler.pm +191 -0
  144. package/bin/exiftool_files/lib/TAP/Parser/YAMLish/Reader.pm +332 -0
  145. package/bin/exiftool_files/lib/TAP/Parser/YAMLish/Writer.pm +254 -0
  146. package/bin/exiftool_files/lib/TAP/Parser.pm +1931 -0
  147. package/bin/exiftool_files/lib/Test/Builder/Formatter.pm +107 -0
  148. package/bin/exiftool_files/lib/Test/Builder/IO/Scalar.pm +659 -0
  149. package/bin/exiftool_files/lib/Test/Builder/Module.pm +182 -0
  150. package/bin/exiftool_files/lib/Test/Builder/Tester/Color.pm +51 -0
  151. package/bin/exiftool_files/lib/Test/Builder/Tester.pm +675 -0
  152. package/bin/exiftool_files/lib/Test/Builder/TodoDiag.pm +68 -0
  153. package/bin/exiftool_files/lib/Test/Builder.pm +2653 -0
  154. package/bin/exiftool_files/lib/Test/Harness.pm +618 -0
  155. package/bin/exiftool_files/lib/Test/More.pm +1997 -0
  156. package/bin/exiftool_files/lib/Test/Simple.pm +220 -0
  157. package/bin/exiftool_files/lib/Test/Tester/Capture.pm +241 -0
  158. package/bin/exiftool_files/lib/Test/Tester/CaptureRunner.pm +79 -0
  159. package/bin/exiftool_files/lib/Test/Tester/Delegate.pm +45 -0
  160. package/bin/exiftool_files/lib/Test/Tester.pm +695 -0
  161. package/bin/exiftool_files/lib/Test/Tutorial.pod +618 -0
  162. package/bin/exiftool_files/lib/Test/use/ok.pm +64 -0
  163. package/bin/exiftool_files/lib/Text/ParseWords.pm +303 -0
  164. package/bin/exiftool_files/lib/Tie/StdHandle.pm +2 -2
  165. package/bin/exiftool_files/lib/Time/HiRes.pm +73 -68
  166. package/bin/exiftool_files/lib/Time/Local.pm +82 -35
  167. package/bin/exiftool_files/lib/Time/Piece.pm +19 -4
  168. package/bin/exiftool_files/lib/Time/Seconds.pm +1 -1
  169. package/bin/exiftool_files/lib/UNIVERSAL.pm +203 -0
  170. package/bin/exiftool_files/lib/Unicode/GCString.pm +60 -0
  171. package/bin/exiftool_files/lib/Unicode/LineBreak/Constants.pm +68 -0
  172. package/bin/exiftool_files/lib/Unicode/LineBreak.pm +248 -0
  173. package/bin/exiftool_files/lib/Win32/API/Struct.pm +1 -177
  174. package/bin/exiftool_files/lib/Win32/API/Type.pm +1 -100
  175. package/bin/exiftool_files/lib/Win32/API.pm +1 -830
  176. package/bin/exiftool_files/lib/Win32/FindFile.pm +2 -123
  177. package/bin/exiftool_files/lib/Win32.pm +213 -89
  178. package/bin/exiftool_files/lib/Win32API/File.pm +1 -1
  179. package/bin/exiftool_files/lib/auto/B/B.xs.dll +0 -0
  180. package/bin/exiftool_files/lib/auto/Compress/Raw/Bzip2/Bzip2.xs.dll +0 -0
  181. package/bin/exiftool_files/lib/auto/Compress/Raw/Lzma/Lzma.xs.dll +0 -0
  182. package/bin/exiftool_files/lib/auto/Compress/Raw/Lzma/autosplit.ix +3 -0
  183. package/bin/exiftool_files/lib/auto/Compress/Raw/Zlib/Zlib.xs.dll +0 -0
  184. package/bin/exiftool_files/lib/auto/CryptX/CryptX.xs.dll +0 -0
  185. package/bin/exiftool_files/lib/auto/Cwd/Cwd.xs.dll +0 -0
  186. package/bin/exiftool_files/lib/auto/Data/Dumper/Dumper.xs.dll +0 -0
  187. package/bin/exiftool_files/lib/auto/Digest/MD5/MD5.xs.dll +0 -0
  188. package/bin/exiftool_files/lib/auto/Digest/SHA/SHA.xs.dll +0 -0
  189. package/bin/exiftool_files/lib/auto/Encode/Encode.xs.dll +0 -0
  190. package/bin/exiftool_files/lib/auto/Fcntl/Fcntl.xs.dll +0 -0
  191. package/bin/exiftool_files/lib/auto/File/Glob/Glob.xs.dll +0 -0
  192. package/bin/exiftool_files/lib/auto/IO/Compress/Brotli/Brotli.xs.dll +0 -0
  193. package/bin/exiftool_files/lib/auto/IO/IO.xs.dll +0 -0
  194. package/bin/exiftool_files/lib/auto/List/Util/Util.xs.dll +0 -0
  195. package/bin/exiftool_files/lib/auto/MIME/Base64/Base64.xs.dll +0 -0
  196. package/bin/exiftool_files/lib/auto/Math/BigInt/FastCalc/FastCalc.xs.dll +0 -0
  197. package/bin/exiftool_files/lib/auto/Math/BigInt/GMP/GMP.xs.dll +0 -0
  198. package/bin/exiftool_files/lib/auto/POSIX/POSIX.xs.dll +0 -0
  199. package/bin/exiftool_files/lib/auto/PerlIO/scalar/scalar.xs.dll +0 -0
  200. package/bin/exiftool_files/lib/auto/Socket/Socket.xs.dll +0 -0
  201. package/bin/exiftool_files/lib/auto/Storable/Storable.xs.dll +0 -0
  202. package/bin/exiftool_files/lib/auto/Time/HiRes/HiRes.xs.dll +0 -0
  203. package/bin/exiftool_files/lib/auto/Time/Piece/Piece.xs.dll +0 -0
  204. package/bin/exiftool_files/lib/auto/Unicode/LineBreak/LineBreak.xs.dll +0 -0
  205. package/bin/exiftool_files/lib/auto/Win32/API/API.xs.dll +0 -0
  206. package/bin/exiftool_files/lib/auto/Win32/FindFile/FindFile.xs.dll +0 -0
  207. package/bin/exiftool_files/lib/auto/Win32/Win32.xs.dll +0 -0
  208. package/bin/exiftool_files/lib/auto/Win32API/File/File.xs.dll +0 -0
  209. package/bin/exiftool_files/lib/auto/mro/mro.xs.dll +0 -0
  210. package/bin/exiftool_files/lib/auto/re/re.xs.dll +0 -0
  211. package/bin/exiftool_files/lib/feature.pm +49 -17
  212. package/bin/exiftool_files/lib/mro.pm +4 -20
  213. package/bin/exiftool_files/lib/overload.pm +15 -15
  214. package/bin/exiftool_files/lib/parent.pm +10 -2
  215. package/bin/exiftool_files/lib/re.pm +91 -33
  216. package/bin/exiftool_files/lib/warnings.pm +17 -6
  217. package/bin/exiftool_files/libgcc_s_seh-1.dll +0 -0
  218. package/bin/exiftool_files/liblzma-5__.dll +0 -0
  219. package/bin/exiftool_files/libstdc++-6.dll +0 -0
  220. package/bin/exiftool_files/libwinpthread-1.dll +0 -0
  221. package/bin/exiftool_files/perl.exe +0 -0
  222. package/bin/exiftool_files/perl532.dll +0 -0
  223. package/package.json +5 -3
  224. package/bin/exiftool_files/libgcc_s_dw2-1.dll +0 -0
  225. 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.22';
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;