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