File Coverage

blib/lib/Net/FCP/Metadata.pm
Criterion Covered Total %
statement 12 52 23.0
branch 0 34 0.0
condition n/a
subroutine 4 12 33.3
pod 5 7 71.4
total 21 105 20.0


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Net::FCP::Metadata - metadata utility class.
4              
5             =head1 SYNOPSIS
6              
7             use Net::FCP::Metadata;
8              
9             =head1 DESCRIPTION
10              
11             =over 4
12              
13             =cut
14              
15             package Net::FCP::Metadata;
16              
17 1     1   4 use Carp ();
  1         1  
  1         21  
18              
19 1     1   485 use Net::FCP::Util qw(tolc touc xeh);
  1         3  
  1         77  
20              
21 1     1   7 no warnings;
  1         1  
  1         56  
22              
23             use overload
24 1     1   1445 '""' => sub { $_[0]->as_string };
  1     0   1095  
  1         10  
  0            
25              
26             =item $metadata = new Net::FCP::Metadata [$string_or_object]
27              
28             Creates a new metadata Object from the given string or reference. The
29             object is overloaded and will stringify into the corresponding string form
30             (which might be slightly different than the string it was created from).
31              
32             If no arguments is given, creates a new metadata object with just a
33             C part.
34              
35             The object is implemented as a hash reference. See C,
36             below, for info on it's structure.
37              
38             =cut
39              
40             sub new {
41 0     0 1   my ($class, $data) = @_;
42              
43 0 0         $data = ref $data ? %$data
    0          
44             : $data ? parse_metadata ($data)
45             : { version => { revision => 1 } };
46              
47 0           bless $data, $class;
48             }
49              
50             =item $metadata->as_string
51              
52             Returns the string form of the metadata data.
53              
54             =cut
55              
56             sub as_string {
57 0     0 1   build_metadata ($_[0]);
58             }
59              
60             =item $metadata->add_redirect ($name, $target[ info1 => arg1...])
61              
62             Add a simple redirection to the C section to the given
63             target. All extra arguments will be added to the C subsection and
64             often contains C and C fields.
65              
66             =cut
67              
68             sub add_redirect {
69 0     0 1   my ($self, $name, $target, %info) = @_;
70              
71 0 0         push @{ $self->{document} }, {
  0 0          
72             redirect => { target => $target },
73             $name ? (name => $name) : (),
74             %info ? (info => \%info) : (),
75             };
76             }
77              
78             =item $meta = Net::FCP::Metadata::parse_metadata $string
79              
80             Internal utility function, do not use directly!
81              
82             Parse a metadata string and return it.
83              
84             The metadata will be a hashref with key C (containing the
85             mandatory version header entries) and key C containing the original
86             metadata string.
87              
88             All other headers are represented by arrayrefs (they can be repeated).
89              
90             Since this description is confusing, here is a rather verbose example of a
91             parsed manifest:
92              
93             (
94             raw => "Version...",
95             version => { revision => 1 },
96             document => [
97             {
98             info => { format" => "image/jpeg" },
99             name => "background.jpg",
100             redirect => { target => "freenet:CHK\@ZcagI,ra726bSw" },
101             },
102             {
103             info => { format" => "text/html" },
104             name => ".next",
105             redirect => { target => "freenet:SSK\@ilUPAgM/TFEE/3" },
106             },
107             {
108             info => { format" => "text/html" },
109             redirect => { target => "freenet:CHK\@8M8Po8ucwI,8xA" },
110             }
111             ]
112             )
113              
114             =cut
115              
116             sub parse_metadata {
117 0     0 1   my $data = shift;
118 0           my $meta = { raw => $data };
119              
120 0 0         if ($data =~ /^Version\015?\012/gc) {
121 0           my $hdr = $meta->{version} = {};
122              
123 0           for (;;) {
124 0           while ($data =~ /\G([^=\015\012]+)=([^\015\012]*)\015?\012/gc) {
125 0           my ($k, $v) = ($1, $2);
126 0           my @p = split /\./, tolc $k, 3;
127              
128 0 0         $hdr->{$p[0]} = $v if @p == 1; # lamest code I ever wrote
129 0 0         $hdr->{$p[0]}{$p[1]} = $v if @p == 2;
130 0 0         $hdr->{$p[0]}{$p[1]}{$p[2]} = $v if @p == 3;
131 0 0         die "FATAL: 4+ dot metadata" if @p >= 4;
132             }
133              
134 0 0         if ($data =~ /\GEndPart\015?\012/gc) {
    0          
    0          
    0          
135             # nop
136             } elsif ($data =~ /\GEnd(\015?\012|$)/gc) {
137 0           last;
138             } elsif ($data =~ /\G([A-Za-z0-9.\-]+)\015?\012/gcs) {
139 0           push @{$meta->{tolc $1}}, $hdr = {};
  0            
140             } elsif ($data =~ /\G(.*)/gcs) {
141 0           print STDERR "metadata format error ($1), please report this string: <<$data>>";
142 0           die "metadata format error";
143             }
144             }
145             }
146              
147             #$meta->{tail} = substr $data, pos $data;
148              
149 0           $meta;
150             }
151              
152             =item $string = Net::FCP::Metadata::build_metadata $meta
153              
154             Internal utility function, do not use directly!
155              
156             Takes a hash reference as returned by C and
157             returns the corresponding string form. If a string is given, it's returned
158             as is.
159              
160             =cut
161              
162             sub build_metadata_subhash($$$) {
163 0     0 0   my ($prefix, $level, $hash) = @_;
164              
165 0 0         join "",
    0          
166             map
167             ref $hash->{$_} ? build_metadata_subhash ($prefix . (Net::FCP::touc $_) . ".", $level + 1, $hash->{$_})
168             : $prefix . ($level > 1 ? $_ : Net::FCP::touc $_) . "=" . $hash->{$_} . "\n",
169             keys %$hash;
170             }
171              
172             sub build_metadata_hash($$) {
173 0     0 0   my ($header, $hash) = @_;
174              
175 0 0         if (ref $hash eq ARRAY::) {
176 0           join "", map build_metadata_hash ($header, $_), @$hash
177             } else {
178 0           (Net::FCP::touc $header) . "\n"
179             . (build_metadata_subhash "", 0, $hash)
180             . "EndPart\n";
181             }
182             }
183              
184             sub build_metadata($) {
185 0     0 1   my ($meta) = @_;
186              
187 0 0         return $meta unless ref $meta;
188              
189 0           $meta = { %$meta };
190              
191 0           delete $meta->{raw};
192              
193 0           my $res =
194             (build_metadata_hash version => delete $meta->{version})
195             . (join "", map +(build_metadata_hash $_, $meta->{$_}), keys %$meta);
196              
197 0           substr $res, -5, 4, ""; # get rid of "Part". Broken Syntax....
198              
199 0           $res;
200             }
201              
202             =back
203              
204             =head1 SEE ALSO
205              
206             L.
207              
208             =head1 BUGS
209              
210             Not heavily tested.
211              
212             =head1 AUTHOR
213              
214             Marc Lehmann
215             http://home.schmorp.de/
216              
217             =cut
218              
219             1;
220