home *** CD-ROM | disk | FTP | other *** search
- package RISCOS::Chunkfile;
-
- require Exporter;
- use RISCOS::File 0.02 qw(load);
- use RISCOS::Chunk;
- use Carp;
- use strict;
- use vars qw ($VERSION);
-
- $VERSION = 0.04;
-
- sub new ($) {
- my $proto = shift;
- my $class = ref($proto) || $proto;
- my $chunks;
-
- if (ref($_[0]) eq 'ARRAY') {
- $chunks = shift;
- } elsif (ref($_[0]) eq 'RISCOS::Chunkfile') {
- $chunks = shift->Chunks();
- } else {
- my $file = &load; # Pass on our arguments
- unless (defined $file) {
- carp 'Could not load file' if $^W;
- return undef;
- }
- my ($tag, $maxchunks, $numchunks) = unpack 'V3', $file;
-
- if ($tag != 0xC3CBC6C5) {
- carp 'Not a chunk file' if $^W;
- return undef;
- }
-
- if (length $file < 12 + 16 * $maxchunks) {
- carp sprintf ('Chunk file with $maxchunks entries expected to be '
- . '%d, actually %d', (12 + 16 * $maxchunks),
- length $file)
- if $^W;
- return undef;
- }
-
- $chunks = [];
-
- # @$chunks = $numchunks;
-
- for (my $chunk = 0; $chunk < $maxchunks; $chunk++) {
- my ($chunkid, $offset, $size) =
- unpack 'A8V2', substr $file, 12 + 16 * $chunk, 16;
-
- if ($offset) {
- carp "Used chunk '$chunkid' at $maxchunks - expected only "
- . "$numchunks used" if ($chunk >= $numchunks);
- } else {
- if ($chunk < $numchunks) {
- carp "Unused chunk $maxchunks - expected $numchunks used";
- } else {
- next; # Unused
- }
- }
-
- push @$chunks, new RISCOS::Chunk $chunkid,
- substr ($file, $offset, $size),
- $size, $chunk, $offset;
- }
- }
-
- my $self = {};
- my $hash = {};
- $self->{'CHUNKS'} = $chunks;
-
- my $index = @$chunks;
-
- while ($index--) {
- my $chunk = $chunks->[$index];
- unshift @{$$hash{$chunk->ID}}, $index;
- # Erk ! :-)
- # It's a reference to a hash
- # The hash keys are the ID's
- # The hash entries are reference to arrays of all the chunks where this
- # ID can be found
- }
-
- $self->{'INDEX'} = $hash;
-
- bless ($self, $class);
- } # Would you believe that apart from missing this } this beastie worked
- # first time!
-
- sub Chunks ($) {
- my $self = shift;
- $self->{'CHUNKS'};
- }
-
- sub Index ($) {
- my $self = shift;
- $self->{'INDEX'};
- }
-
- sub Lookup ($$) {
- my $self = shift;
- my $index = $self->{'INDEX'};
- $index->{$_[0]};
- }
-
- sub By_Number ($$) {
- my $self = shift;
- $self->{'CHUNKS'}->[$_[0]];
- }
- sub Single ($$) {
- my $self = shift;
- my $index = $self->{'INDEX'};
- my $array = $index->{$_[0]};
-
- return (@$array == 1) ? $array->[0] : undef;
- }
-
- sub Multiple ($$) {
- my $self = shift;
- my $index = $self->{'INDEX'};
- my $array = $index->{$_[0]};
-
- return (defined $array and @$array > 1) ? @$array : ();
- }
-
- sub Chunk ($$) {
- my $self = shift;
- my $index = $self->{'INDEX'};
- my $array = $index->{$_[0]};
-
- return (defined $array and @$array == 1) ? $self->{'CHUNKS'}->[$array->[0]]
- : undef;
- }
-
- 1;
- __END__
-
- =head1 NAME
-
- RISCOS::Chunkfile -- class for manipulating Acorn chunkfiles (AOF & ALF)
-
- =head1 SYNOPSIS
-
- use RISCOS::Chunkfile;
- my $chunks = new RISCOS::Chunkfile $file;
-
- =head1 DESCRIPTION
-
- C<RISCOS::Chunkfile> provides a class for manipulating Acorn chunkfiles
- (I<e.g.> I<AOF> - B<A>RM B<O>bject B<F>ormat and I<ALF> - B<A>corn B<L>ibrary
- B<F>ormat). Currently this module is only used by the AOF and ALF modules.
-
- C<RISCOS::Chunkfile> provides the following methods:
-
- =over 4
-
- =item new <array_ref>
-
- =item new <file>
-
- If passed a reference to an array it is assumed to be an array of
- C<RISCOS::Chunk> objects to use as the file contents. Otherwise calls
- C<RISCOS::File::load> to loads the file specified using and checks that it is a
- chunkfile. Hence I<file> can be a filename, a reference to a filehandle, or a
- reference to a scalar which is used as the file's contents.
-
- If passed an array reference then this is used internally in the object, so
- should be created with the anonymous array constructor C<[]> rather than a
- reference to a named array variable (see L<perldsc/Common Mistakes>).
-
- Returns undefined if there was an error, or the file contents are corrupt.
-
- =item Chunks
-
- Returns a reference to the array of C<RISCOS::Chunk> objects, which are in the
- same order as found in the file. Treat this as B<read only>. Changing the order
- or number of the chunks will confuse all the other lookup methods. If you need
- to manipulate the chunks pass this array back to C<new> to create a new
- chunkfile object, and delete the old object (most simply by reusing the same
- named variable).
-
- =item Index
-
- Returns a reference to a hash which indexes the array of C<RISCOS::Chunk>
- objects returned by C<chunks>. The hash keys are the textual chunk IDs from the
- chunk header, the hash entries are reference to arrays containing the numbers of
- all the chunks where this ID can be found. For most IDs the array referenced
- will have only one entry (for example an C<ALF> file will contain only one
- C<LIB_DIRY> for the library directory) but where an ID occurs multiple times in
- the chunk header the reference will be to an array of the indexes of all these
- chunks (I<e.g.> in an C<ALF> library each object file is stored in a C<LIB_DATA>
- chunk - C<$index->{LIB_DATA}> will be a reference to the IDs of all of the
- chunks containing object files).
-
- =item Lookup <chunkID>
-
- Returns a reference to the array of chunk indexes in the file where this chunk
- ID is present. Effectively the value from a lookup on the hash returned by
- C<Keys>, so will return undefined if no chunks in the file have this chunk ID.
-
- =item By_Number <chunk_index>
-
- Returns the C<RISCOS::Chunk> object at I<chunk_index> position in the file.
- Effectively the value from the array returned by C<Chunks>.
-
- =item Single <chunkID>
-
- Returns the index of the only chunk in the file with ID I<chunkID>, or undefined
- if zero or multiple chunks have this ID.
-
- =item Multiple <chunkID> {
-
- Returns the list of chunks in the file with ID I<chunkID>, or an empty list if
- if less than two chunks have this ID.
-
- =item Chunk <chunkID>
-
- Returns the actual chunk of the only chunk in the file with ID I<chunkID>, or
- undefined if zero or multiple chunks have this ID.
-
- Effectively a call to C<By_Number> with the value returned from C<Single>
-
- =back
-
- =head1 EXAMPLE
-
- To display the index of chunks in a chunkfile
-
- use RISCOS::Chunkfile;
-
- my $chunks = new RISCOS::Chunkfile $file;
-
- print "$file:\n";
-
- foreach my $id (sort keys %{$chunks->Index})
- {
- print "\t$id\t", join (' ', @{$chunks->Lookup ($id)}), "\n";
- }
-
- =head1 BUGS
-
- At present there is no standard way to return errors/diagnostics to the caller.
- Currently C<new> will call C<warn> if warnings are turned on.
-
- =head1 AUTHOR
-
- Nicholas Clark <F<nick@unfortu.net>>
-