=head1 NAME Convert::CD::Cue - import/export .bin/.cue files. =head1 SYNOPSIS use Convert::CD::Cue; # to be done =head1 DESCRIPTION Parse/Write .cue files. =head2 Convert:CD::Cue METHODS This class represents a .bin/.cue file combination. =over 4 =cut package Convert::CD::Cue; $VERSION = 0.01; use Carp; use Convert::CD::Track; use base Convert::CD::TOCFile; =item new param => value... Create a new Convert::CD::Cue object. Parameters: path the base image filename tocpath the (optional) path of the tocfile =cut sub new { my $class = shift; my $self = bless { @_, }, $class; exists $self->{tocpath} or $self->{tocpath} = $self->find_tocfile ("cue", "CUE", "Cue"); $self; } sub _read { my ($self, $cd) = @_; defined $self->{tocpath} or croak "no tocpath specified and/or no .cue found"; open my $cue, "<", $self->{tocpath} or croak "$self->{tocpath}: $!"; my @tracks; # perliminary track data my $file; my $track; # assumption #1: these thingies are line-based while (<$cue>) { s/[\015\012]+$//; # assumption #2, leading whitespace don't matter much # assumption #3, case? what case? if (/\S*FILE \"?(.*?)\"? (\S+)$/i) { my ($path, $type) = ($1, $2); if (-e $path) { $file = $path; } else { my $name = $path; $name =~ s/^.*[\/\\]//; if (-e $name) { $file = $name; } elsif (-e lc $name) { $file = lc $name; } else { $file = $self->{path}; } warn "\"$path\" not found, using \"$file\" instead\n"; } } elsif (/\S*TRACK (\d+) (\S+)/i) { my ($idx, $mode) = ($1, $2); my $secsize = 2352; $secsize = $1 if $mode =~ s/\/(\d+)$//; # MODE2/1234 => MODE2 $mode = MODE_AUDIO if $mode eq "AUDIO"; $mode = MODE_MODE1 if $mode eq "MODE1"; $mode = MODE_MODE2 if $mode eq "MODE2"; $mode = MODE_CDI if $mode eq "CDI"; $mode = MODE_CDG if $mode eq "CDG"; if ($mode == 0) { warn "unrecognized mode '$mode', using MODE2 instead\n"; $mode = MODE_MODE2; } $secsize = 2448 if $mode == MODE_CDG; $track = $tracks[$idx - 1] = {}; $track->{path} = $file; $track->{mode} = $mode; $track->{secsize} = $secsize; } elsif (/\S*INDEX (\d+) ([0-9:]+)/i) { my ($idx, $time) = ($1, $self->parse_msf ($2)); $track->{index}[$idx] = $time; $track->{offset} = $time * $track->{secsize} if $idx == 1; } elsif (/\S*TITLE "((?:[^"\\]+|\\.)*)"/i) { $track->{title} = $1; } elsif (/\S*PERFORMER "((?:[^"\\]+|\\.)*)"/i) { $track->{performer} = $1; } elsif (/\S*PREGAP ([0-9:]+)/i) { $track->{pregap} = $self->parse_msf ($1); } elsif (/\S*POSTGAP ([0-9:]+)/i) { $track->{postgap} = $self->parse_msf ($1); # need to parse FLAGS } else { warn "unknown .cue directive skipped: $_"; } } # now go through the tracks array my $prev = undef; for (@tracks) { next unless $_; if ($prev && $prev->{offset} <= $_->{offset}) { $prev->{rawsize} = $_->{offset} - $prev->{offset}; } $prev = $_; } for (@tracks) { if (defined $_) { $cd->append_track (%$_); } else { # synthesize empty track $cd->append_track (size => 0, mode => "MODE1", secsize => 2048); } } } #sub _write { # my ($self, $cd) = @_; #} 1; =back =head1 AUTHOR Marc Lehmann =cut