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
|
|
|
|
|
|
|
|