ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Net-FCP/FCP/Metadata.pm
Revision: 1.3
Committed: Fri May 14 17:47:34 2004 UTC (20 years ago) by root
Branch: MAIN
Changes since 1.2: +28 -5 lines
Log Message:
*** empty log message ***

File Contents

# Content
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 use Carp ();
18
19 use Net::FCP::Util qw(tolc touc xeh);
20
21 no warnings;
22
23 use overload
24 '""' => sub { $_[0]->as_string };
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<version> part.
34
35 The object is implemented as a hash reference. See C<parse_metadata>,
36 below, for info on it's structure.
37
38 =cut
39
40 sub new {
41 my ($class, $data) = @_;
42
43 $data = ref $data ? %$data
44 : $data ? parse_metadata ($data)
45 : { version => { revision => 1 } };
46
47 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 build_metadata ($_[0]);
58 }
59
60 =item $metadata->add_redirect ($name, $target[ info1 => arg1...])
61
62 Add a simple redirection to the C<document> section to the given
63 target. All extra arguments will be added to the C<info> subsection and
64 often contains C<description> and C<format> fields.
65
66 =cut
67
68 sub add_redirect {
69 my ($self, $name, $target, %info) = @_;
70
71 push @{ $self->{document} }, {
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<version> (containing the
85 mandatory version header entries) and key C<raw> 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 my $data = shift;
118 my $meta = { raw => $data };
119
120 if ($data =~ /^Version\015?\012/gc) {
121 my $hdr = $meta->{version} = {};
122
123 for (;;) {
124 while ($data =~ /\G([^=\015\012]+)=([^\015\012]*)\015?\012/gc) {
125 my ($k, $v) = ($1, $2);
126 my @p = split /\./, tolc $k, 3;
127
128 $hdr->{$p[0]} = $v if @p == 1; # lamest code I ever wrote
129 $hdr->{$p[0]}{$p[1]} = $v if @p == 2;
130 $hdr->{$p[0]}{$p[1]}{$p[2]} = $v if @p == 3;
131 die "FATAL: 4+ dot metadata" if @p >= 4;
132 }
133
134 if ($data =~ /\GEndPart\015?\012/gc) {
135 # nop
136 } elsif ($data =~ /\GEnd(\015?\012|$)/gc) {
137 last;
138 } elsif ($data =~ /\G([A-Za-z0-9.\-]+)\015?\012/gcs) {
139 push @{$meta->{tolc $1}}, $hdr = {};
140 } elsif ($data =~ /\G(.*)/gcs) {
141 print STDERR "metadata format error ($1), please report this string: <<$data>>";
142 die "metadata format error";
143 }
144 }
145 }
146
147 #$meta->{tail} = substr $data, pos $data;
148
149 $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<Net::FCP::parse_metadata> 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 my ($prefix, $level, $hash) = @_;
164
165 join "",
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 my ($header, $hash) = @_;
174
175 if (ref $hash eq ARRAY::) {
176 join "", map build_metadata_hash ($header, $_), @$hash
177 } else {
178 (Net::FCP::touc $header) . "\n"
179 . (build_metadata_subhash "", 0, $hash)
180 . "EndPart\n";
181 }
182 }
183
184 sub build_metadata($) {
185 my ($meta) = @_;
186
187 return $meta unless ref $meta;
188
189 $meta = { %$meta };
190
191 delete $meta->{raw};
192
193 my $res =
194 (build_metadata_hash version => delete $meta->{version})
195 . (join "", map +(build_metadata_hash $_, $meta->{$_}), keys %$meta);
196
197 substr $res, -5, 4, ""; # get rid of "Part". Broken Syntax....
198
199 $res;
200 }
201
202 =back
203
204 =head1 SEE ALSO
205
206 L<Net::FCP>.
207
208 =head1 BUGS
209
210 Not heavily tested.
211
212 =head1 AUTHOR
213
214 Marc Lehmann <pcg@goof.com>
215 http://www.goof.com/pcg/marc/
216
217 =cut
218
219 1;
220