Net::FCP::Metadata - metadata utility class.


Net-FCP documentation Contained in the Net-FCP distribution.

Index


Code Index:

NAME

Top

Net::FCP::Metadata - metadata utility class.

SYNOPSIS

Top

 use Net::FCP::Metadata;

DESCRIPTION

Top

$metadata = new Net::FCP::Metadata [$string_or_object]

Creates a new metadata Object from the given string or reference. The object is overloaded and will stringify into the corresponding string form (which might be slightly different than the string it was created from).

If no arguments is given, creates a new metadata object with just a version part.

The object is implemented as a hash reference. See parse_metadata, below, for info on it's structure.

$metadata->as_string

Returns the string form of the metadata data.

$metadata->add_redirect ($name, $target[ info1 => arg1...])

Add a simple redirection to the document section to the given target. All extra arguments will be added to the info subsection and often contains description and format fields.

$meta = Net::FCP::Metadata::parse_metadata $string

Internal utility function, do not use directly!

Parse a metadata string and return it.

The metadata will be a hashref with key version (containing the mandatory version header entries) and key raw containing the original metadata string.

All other headers are represented by arrayrefs (they can be repeated).

Since this description is confusing, here is a rather verbose example of a parsed manifest:

   (
      raw => "Version...",
      version => { revision => 1 },
      document => [
                    {
                      info => { format" => "image/jpeg" },
                      name => "background.jpg",
                      redirect => { target => "freenet:CHK\@ZcagI,ra726bSw" },
                    },
                    {
                      info => { format" => "text/html" },
                      name => ".next",
                      redirect => { target => "freenet:SSK\@ilUPAgM/TFEE/3" },
                    },
                    {
                      info => { format" => "text/html" },
                      redirect => { target => "freenet:CHK\@8M8Po8ucwI,8xA" },
                    }
                  ]
   )

$string = Net::FCP::Metadata::build_metadata $meta

Internal utility function, do not use directly!

Takes a hash reference as returned by Net::FCP::parse_metadata and returns the corresponding string form. If a string is given, it's returned as is.

SEE ALSO

Top

Net::FCP.

BUGS

Top

Not heavily tested.

AUTHOR

Top

 Marc Lehmann <schmorp@schmorp.de>
 http://home.schmorp.de/


Net-FCP documentation Contained in the Net-FCP distribution.
package Net::FCP::Metadata;

use Carp ();

use Net::FCP::Util qw(tolc touc xeh);

no warnings;

use overload
   '""' => sub { $_[0]->as_string };

sub new {
   my ($class, $data) = @_;

   $data = ref $data ? %$data
         : $data     ? parse_metadata ($data)
         :             { version => { revision => 1 } };

   bless $data, $class;
}

sub as_string {
   build_metadata ($_[0]);
}

sub add_redirect {
   my ($self, $name, $target, %info) = @_;

   push @{ $self->{document} }, {
      redirect => { target => $target },
      $name ? (name => $name) : (),
      %info ? (info => \%info) : (),
   };
}

sub parse_metadata {
   my $data = shift;
   my $meta = { raw => $data };

   if ($data =~ /^Version\015?\012/gc) {
      my $hdr = $meta->{version} = {};

      for (;;) {
         while ($data =~ /\G([^=\015\012]+)=([^\015\012]*)\015?\012/gc) {
            my ($k, $v) = ($1, $2);
            my @p = split /\./, tolc $k, 3;

            $hdr->{$p[0]}               = $v if @p == 1; # lamest code I ever wrote
            $hdr->{$p[0]}{$p[1]}        = $v if @p == 2;
            $hdr->{$p[0]}{$p[1]}{$p[2]} = $v if @p == 3;
            die "FATAL: 4+ dot metadata"     if @p >= 4;
         }

         if ($data =~ /\GEndPart\015?\012/gc) {
            # nop
         } elsif ($data =~ /\GEnd(\015?\012|$)/gc) {
            last;
         } elsif ($data =~ /\G([A-Za-z0-9.\-]+)\015?\012/gcs) {
            push @{$meta->{tolc $1}}, $hdr = {};
         } elsif ($data =~ /\G(.*)/gcs) {
            print STDERR "metadata format error ($1), please report this string: <<$data>>";
            die "metadata format error";
         }
      }
   }

   #$meta->{tail} = substr $data, pos $data;

   $meta;
}

sub build_metadata_subhash($$$) {
   my ($prefix, $level, $hash) = @_;

   join "",
      map
         ref $hash->{$_} ? build_metadata_subhash ($prefix . (Net::FCP::touc $_) . ".", $level + 1, $hash->{$_})
                         : $prefix . ($level > 1 ? $_ : Net::FCP::touc $_) . "=" . $hash->{$_} . "\n",
         keys %$hash;
}

sub build_metadata_hash($$) {
   my ($header, $hash) = @_;

   if (ref $hash eq ARRAY::) {
      join "", map build_metadata_hash ($header, $_), @$hash
   } else {
      (Net::FCP::touc $header) . "\n"
      . (build_metadata_subhash "", 0, $hash)
      . "EndPart\n";
   }
}

sub build_metadata($) {
   my ($meta) = @_;

   return $meta unless ref $meta;

   $meta = { %$meta };

   delete $meta->{raw};

   my $res =
      (build_metadata_hash version => delete $meta->{version})
      . (join "", map +(build_metadata_hash $_, $meta->{$_}), keys %$meta);

   substr $res, -5, 4, ""; # get rid of "Part". Broken Syntax....

   $res;
}

1;