=head1 NAME Convert::CD - import/export/represent various cd image file formats =head1 SYNOPSIS use Convert::CD; # to be done =head1 DESCRIPTION Kidding? =head2 Convert:CD METHODS This class represents a full CD image, which can consist of one or more files. While track layout and TOC data is stored in this class, to read/write TOC files you need a Convert::CD::TOCFile. =over 4 =cut package Convert::CD; $VERSION = 0.01; use base Exporter; =item new param => value... Create a new Convert::CD object. my $cd = new path => "/tmp/mycd.bin"; =cut sub new { my $class = shift; my $self = bless { track => [], # an array of tracks, track #1 is in index 0 @_, }, $class; $self; } =item $cd->append_track(param => value...) Appends a new track to the image. Same parameters as Convert::CD::Track->new. =cut sub append_track { my ($self, %arg) = @_; push @{$self->{track}}, Convert::CD::Track->new (%arg); } =item $cd->as_string Returns a multi-line, textual description of the CD Image. =cut sub as_string { my ($self) = @_; my $r; $r .= "Image Path: $self->{path}\n"; for my $idx (1 .. @{$self->{track}}) { $r .= sprintf "Track %02d: %s\n", $idx, $self->{track}[$idx - 1]->as_string; } $r; } =item $cd->track ([$idx]) Returns the track with the given index, or, if no index is given, all the tracks of the CD (or the number of tracks in scalar context). The first track is track #1. =cut sub track { my ($self, $idx) = @_; @_ > 1 ? $self->{track}[$idx - 1] : @{$self->{track}}; } package Convert::CD::Track; use POSIX qw(ceil); use Carp; =back =head2 Convert::CD::Track METHODS This class is used to repesent single track objects. =over 4 =item new param => value... Create a new track object. Parameters: path the file that contains the track offset the offste within the file that contains the first sector (may be negative) rawsize the raw size (in bytes) of the track. (guessed if missing) mode a mode string (MODE1, MODE2, AUDIO, CDI, CDG....) datasize size of the data part of the sector (e.g. 2048). (def. secsize) secsize size of a sector in disk image index an array of index times (0 is pregap start, 1 is track start) =cut sub new { my $class = shift; my $self = bless { @_, }, $class; $self->{rawsize} ||= (-s $self->{path}) - $self->{offset}; $self->{datasize} ||= $self->{secsize}; $self; } # create and cache a filehandle of the given mode sub fh { my ($self, $mode) = @_; $self->{fh}{$mode} ||= do { open my $fh, $mode, $self->{path} or croak "$self->{path}: $!"; binmode $fh; # *seufz* $fh; }; } =item $track->read ($offset, $length) Reads and returns a part of the track. C<$offset> should be a multiple of the datasize. =cut sub read { my ($self, $offset, $length) = @_; my $buf; my $fh = $self->fh ("<"); $offset = $offset / $self->{secsize} * $self->{secsize}; while ($length > 0) { sysseek $fh, $self->{offset} + $offset, 0 or croak "seek($self->{path}): $!"; sysread $fh, $buf, ($length < $self->{datasize} ? $length : $self->{datasize}), length $buf or croak "read($self->{path}): $!"; $length -= $self->{datasize}; $offset += $self->{secsize}; } $buf; } =item $track->size Returns the (cooked) size of the track in bytes, i.e. logical size of the track without any ECC etc. information. =cut sub size { my ($self) = @_; ceil ($self->{rawsize} / $self->{secsize}) * $self->{datasize}; } =item $track->as_string Returns a single-line, textual description of the track. =cut sub as_string { my ($self) = @_; my %data = %$self; $data{index} = "<" . (join "|", @{$data{index}}) .">"; sprintf "%s %08x+%08x %s/%d (%s)", delete @data{qw(path offset rawsize mode secsize)}, join " ", %data; } =item $track->to_msf ($offset) Converts the given byte offste into M:S:F format. =cut sub to_msf { my ($self, $offset) = @_; my $frame = $offset / $self->{datasize}; sprintf "%02d:%02d:%02d", $frame / (60 * 75), $frame / 75 % 60, $frame % 75; } 1; =back =head1 AUTHOR Marc Lehmann =cut