ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Net-FCP/FCP/Metadata.pm
Revision: 1.2
Committed: Fri May 14 16:28:20 2004 UTC (22 years, 4 months ago) by root
Branch: MAIN
Changes since 1.1: +2 -0 lines
Log Message:
*** empty log message ***

File Contents

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