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

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