Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

292 lines
7.2 KiB

  1. package YAML;
  2. use strict;
  3. use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  4. use vars qw($Width $Comma $Level $TabWidth $Sort $MaxLines $HashMode);
  5. require Exporter;
  6. @ISA = qw(Exporter);
  7. @EXPORT = qw(serialize deserialize);
  8. $VERSION = '0.16';
  9. use Carp;
  10. sub serialize {
  11. local $/ = "\n";
  12. my $o = bless {serial => '',
  13. level => 0,
  14. width => 4,
  15. }, __PACKAGE__;
  16. while (@_) {
  17. $_ = shift;
  18. croak "Arguments to serialize() must be a list of hash refs\n"
  19. unless ref eq 'HASH' and not /=/;
  20. $o->_serialize_hash($_, 1);
  21. $o->{serial} .= "----\n" if @_;
  22. }
  23. return $o->{serial};
  24. }
  25. sub _serialize_data {
  26. my $o = shift;
  27. $_ = shift;
  28. return $o->_serialize_undef($_)
  29. if not defined;
  30. return $o->_serialize_value($_)
  31. if (not ref);
  32. return $o->_serialize_hash($_, 0)
  33. if (ref eq 'HASH' and not /=/ or /=HASH/);
  34. return $o->_serialize_array($_)
  35. if (ref eq 'ARRAY' and not /=/ or /=ARRAY/);
  36. warn "WARNING: Cannot serialize the following reference:\n\t$_\n"
  37. if $^W;
  38. $o->{serial} .= "$_\n";
  39. }
  40. sub _serialize_value {
  41. my ($o, $data) = @_;
  42. my $value;
  43. if ($data =~ /\n/) {
  44. my $indent = ' ' x (($o->{level} + 1) * $o->{width});
  45. my $sigil = ($data =~ s/\n\Z//) ? '|' : '|-';
  46. $data =~ s/^/$indent/mg;
  47. chomp $data;
  48. $value = "$sigil\n$data\n";
  49. }
  50. elsif ($data =~ /^[\s\%\@\~\"]|\s$/ or
  51. $data =~ /([\x00-\x1f\x7f-\xff])/ or
  52. $data eq '') {
  53. $data =~ s/\"/\\\"/g;
  54. $value = qq{"$data"\n};
  55. }
  56. else {
  57. $value = "$data\n";
  58. }
  59. $o->{serial} .= $value;
  60. }
  61. sub _serialize_hash {
  62. my ($o, $data, $top) = @_;
  63. $o->_serialize_reference($data, '%', 'HASH', $top);
  64. $o->{level}++ unless $top;
  65. my $indent = ' ' x ($o->{level} * $o->{width});
  66. for my $key (sort keys %$data) {
  67. my $key_out = $key;
  68. if ($key =~ /^[\s\%\@\~\"]|:|\s\s|\n|\s$/) {
  69. $key_out =~ s/\n/\\n/g;
  70. $key_out =~ s/\"/\\\"/g;
  71. $key_out = qq{"$key_out"};
  72. }
  73. $o->{serial} .= "$indent$key_out: ";
  74. $o->_serialize_data($data->{$key});
  75. }
  76. $o->{level}--;
  77. delete $o->{ref_stack_xref}{pop @{$o->{ref_stack}} or die};
  78. }
  79. sub _serialize_array {
  80. my ($o, $data) = @_;
  81. $o->_serialize_reference($data, '@', 'ARRAY', 0);
  82. my $indent = ' ' x (++$o->{level} * $o->{width});
  83. for my $datum (@$data) {
  84. $o->{serial} .= "$indent: ";
  85. $o->_serialize_data($datum);
  86. }
  87. $o->{level}--;
  88. delete $o->{ref_stack_xref}{pop @{$o->{ref_stack}} or die};
  89. }
  90. sub _serialize_undef {
  91. my ($o) = @_;
  92. $o->{serial} .= "~\n";
  93. }
  94. sub _serialize_reference {
  95. my ($o, $data, $sigil, $type, $top) = @_;
  96. $data =~ /^(([\w:]+)=)?$type\(0x([0-9a-f]+)\)$/
  97. or croak "Invalid reference: $data, for type $type\n";
  98. croak "YAML.pm does not yet support circular references\n"
  99. if defined $o->{ref_stack_xref}{$3};
  100. if (not $top) {
  101. $o->{serial} .= "!$2 " if defined $2;
  102. $o->{serial} .= $sigil . "\n";
  103. }
  104. push @{$o->{ref_stack}}, $3;
  105. $o->{ref_stack_xref}{$3}++;
  106. }
  107. sub deserialize {
  108. local $/ = "\n";
  109. my ($text) = @_;
  110. chomp $text;
  111. my $o = bless {lines => [split($/, $text)],
  112. level => 0,
  113. width => 4,
  114. tabwidth => 8,
  115. }, __PACKAGE__;
  116. @{$o->{objects}} = ();
  117. $o->{level} = 0;
  118. $o->{line} ||= 1;
  119. $o->_setup_line;
  120. while (not $o->{eod}) {
  121. croak "Deserialize error. Starting production not a hash.\n"
  122. unless $o->{content} =~ /^\S.*[^\\]:/;
  123. $o->{done} = 0;
  124. my $hash = {};
  125. %$hash = $o->_deserialize_hash(1);
  126. push @{$o->{objects}}, $hash;
  127. $o->_next_line;
  128. $o->_setup_line;
  129. }
  130. return wantarray ? @{$o->{objects}} : ${$o->{objects}}[-1];
  131. }
  132. sub _deserialize_data {
  133. my $o = shift;
  134. my ($obj, $class) = ('', '');
  135. if ($o->{content} =~ /^(?:\!(\w(?:\w|::)*))?\s*
  136. ([\%\@])
  137. \s*$/x
  138. ) {
  139. $obj = ($2 eq '%') ? {} : [];
  140. $class = $1 || '';
  141. if ($2 eq '%') {
  142. %$obj = $o->_deserialize_hash(0);
  143. }
  144. elsif ($2 eq '@') {
  145. @$obj = $o->_deserialize_array;
  146. }
  147. else {
  148. croak "Insane error\n";
  149. }
  150. bless $obj, $class if length $class;
  151. }
  152. elsif ($o->{content} =~ /^\~\s*$/) {
  153. $obj = $o->_deserialize_undef;
  154. }
  155. else {
  156. $obj = $o->_deserialize_value;
  157. }
  158. return $obj;
  159. }
  160. sub _deserialize_value {
  161. my $o = shift;
  162. my $value = '';
  163. my $indent = $o->{level} * $o->{width};
  164. if ($o->{content} =~ /^\s*\|\s*(-)?\s*$/) {
  165. my $chomp = $1 eq '-';
  166. $o->_next_line;
  167. my $indent = ($o->{level} + 1) * $o->{width};
  168. while (not $o->{done} and
  169. $o->{lines}[0] =~ /^\s{$indent}/) {
  170. $value .= substr($o->{lines}[0], $indent) . "\n";
  171. $o->_next_line;
  172. }
  173. chomp $value if $chomp;
  174. $o->_setup_line;
  175. }
  176. elsif ($o->{content} =~ /^\"/) {
  177. croak "Mismatched quotes"
  178. unless $o->{content} =~ /^\"(.*)\"\s*$/;
  179. $value = $1;
  180. $o->_next_line;
  181. $o->_setup_line;
  182. }
  183. else {
  184. $value = $o->{content};
  185. $o->_next_line;
  186. $o->_setup_line;
  187. }
  188. return $value;
  189. }
  190. sub _deserialize_hash {
  191. my @values;
  192. my ($o, $top) = @_;
  193. my $level = $o->{level};
  194. unless ($top) {
  195. $level++;
  196. $o->_next_line;
  197. $o->_setup_line;
  198. }
  199. my ($key, $value);
  200. while ($o->{level} == $level) {
  201. if ($o->{content} =~ /^\"/) {
  202. croak "Bad map key at line $o->{line}\n"
  203. unless ($o->{content} =~ /^\"(.*?(?<!\\))\"\s*:\s*(.*)/);
  204. ($key, $value) = ($1, $2);
  205. $key =~ s/\\n/\n/g;
  206. $key =~ s/\\\"/\"/g;
  207. }
  208. else {
  209. ($key, $value) = split /\s*:\s*/, $o->{content}, 2;
  210. croak $o->invalid_key_value unless (defined $key);
  211. }
  212. $o->{content} = defined $value ? $value : '';
  213. push @values, $o->_get_key($key), $o->_deserialize_data;;
  214. }
  215. croak "Invalid ident level\n$o->{content}\nLine: $o->{line}\n$o->{level}\n$level\n"
  216. if $o->{level} > $level;
  217. return @values;
  218. }
  219. sub _get_key {
  220. my ($o, $key) = @_;
  221. return $key unless $key =~ /^\"(.*)\"$/;
  222. $key = $1;
  223. $key =~ s/\\n/\n/g;
  224. $key =~ s/\\\"/\"/g;
  225. return $key;
  226. }
  227. sub _deserialize_array {
  228. my @values;
  229. my $o = shift;
  230. my $level = $o->{level} + 1;
  231. $o->_next_line;
  232. $o->_setup_line;
  233. while ($o->{level} == $level) {
  234. croak "List item not bulleted at line $o->{line}\n"
  235. unless($o->{content} =~ /^(: +)/);
  236. substr($o->{content}, 0, length($1), '');
  237. push @values, $o->_deserialize_data;
  238. }
  239. croak "Invalid indent level\n" if $o->{level} > $level;
  240. return @values;
  241. }
  242. sub _deserialize_undef {
  243. my $o = shift;
  244. $o->_next_line;
  245. $o->_setup_line;
  246. return undef;
  247. }
  248. sub _next_line {
  249. my $o = shift;
  250. $o->{eod}++, $o->{done}++, $o->{level} = -1, return unless @{$o->{lines}};
  251. $_ = shift @{$o->{lines}};
  252. $o->{line}++;
  253. }
  254. sub _setup_line {
  255. my $o = shift;
  256. $o->{eod}++, $o->{done}++, $o->{level} = -1, return unless @{$o->{lines}};
  257. $o->{done}++, $o->{level} = -1, return if $o->{lines}[0] =~ /^----$/;
  258. my ($width, $tabwidth) = @{$o}{qw(width tabwidth)};
  259. $_ = $o->{lines}[0];
  260. croak "Invalid indent width at line $o->{line}\n"
  261. unless /^(( {$width})*)(\S.*)$/;
  262. $o->{level} = length($1) / $width;
  263. $o->{content} = $3;
  264. }
  265. 1;