Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
146 lines (123 sloc) 3.27 KB
#include <cassert>
#include <cdio/paranoia.h>
#include <cdio/cdda.h>
#include <cdio/cd_types.h>
#include "Paranoia.h"
using namespace std;
struct CannotFindCDROMDevice {};
struct UnableToOpenDisc {};
struct TroubleGettingStartingLSN {};
struct ParanoiaSentNoData {};
Paranoia::Paranoia(): m_cdrom(nullptr), m_paranoia(nullptr)
{
}
Paranoia::~Paranoia()
{
close();
}
std::map<int, std::string> Paranoia::flags()
{
return {
{ PARANOIA_MODE_VERIFY, "Verify data integrety in overlap area" },
{ PARANOIA_MODE_OVERLAP, "Perform overlapped reads" },
{ PARANOIA_MODE_NEVERSKIP, "Do not skip failed reads (retry)" }
};
}
int Paranoia::defaultFlags()
{
return PARANOIA_MODE_FULL ^ PARANOIA_MODE_NEVERSKIP;
}
std::map<std::string, std::string> Paranoia::devices()
{
std::map<std::string, std::string> ret;
char** devs = cdio_get_devices(DRIVER_UNKNOWN);
for (char** dev = devs; dev && *dev; ++dev)
{
cdrom_drive_s* cdrom = cdio_cddap_identify(*dev, 0, 0);
ret[*dev] = cdrom->drive_model;
}
cdio_free_device_list(devs);
return ret;
}
bool Paranoia::open(string const& _device)
{
close();
if (_device.empty())
m_cdrom = cdio_cddap_find_a_cdrom(0, nullptr);
else
m_cdrom = cdio_cddap_identify(_device.c_str(), 0, nullptr);
if (!m_cdrom)
throw CannotFindCDROMDevice();
cdio_cddap_verbose_set(m_cdrom, CDDA_MESSAGE_PRINTIT, CDDA_MESSAGE_PRINTIT);
if (cdio_cddap_open(m_cdrom))
throw UnableToOpenDisc();
if (m_cdrom)
m_paranoia = cdio_paranoia_init(m_cdrom);
return m_cdrom && m_paranoia;
}
void Paranoia::close()
{
if (m_paranoia)
{
cdio_paranoia_free(m_paranoia);
m_paranoia = nullptr;
}
if (m_cdrom)
{
cdio_cddap_close(m_cdrom);
m_cdrom = nullptr;
}
}
unsigned Paranoia::tracks() const
{
if (!m_cdrom)
return 0;
int ret = cdio_cddap_tracks(m_cdrom);
if (ret == 255)
return 0;
return ret;
}
size_t Paranoia::frameLength()
{
return CDIO_CD_FRAMESIZE_RAW / sizeof(int16_t) / 2;
}
size_t Paranoia::trackLength(unsigned _track) const
{
if (cdio_get_track_format(m_cdrom->p_cdio, _track + 1) != TRACK_FORMAT_AUDIO)
return 0;
lsn_t begin = cdio_cddap_track_firstsector(m_cdrom, _track + 1);
lsn_t end = cdio_cddap_track_lastsector(m_cdrom, _track + 1);
return (end - begin + 1) * frameLength();
}
void Paranoia::rip(unsigned _track, function<bool(unsigned, unsigned, int16_t const*)> const& _f, int _flags)
{
if (cdio_get_track_format(m_cdrom->p_cdio, _track + 1) != TRACK_FORMAT_AUDIO)
return;
assert(_track < tracks());
lsn_t begin = cdio_cddap_track_firstsector(m_cdrom, _track + 1);
lsn_t end = cdio_cddap_track_lastsector(m_cdrom, _track + 1);
if (begin < 0)
throw TroubleGettingStartingLSN();
// TODO: allow change
cdio_paranoia_modeset(m_paranoia, _flags == -1 ? defaultFlags() : _flags);
cdio_paranoia_seek(m_paranoia, begin, SEEK_SET);
for (lsn_t cursor = begin; cursor <= end; ++cursor)
{
// read a sector
int16_t* buffer = cdio_paranoia_read_limited(m_paranoia, nullptr, 1);
char* psz_err = cdio_cddap_errors(m_cdrom);
char* psz_mes = cdio_cddap_messages(m_cdrom);
if (psz_mes || psz_err)
{
printf("%s%s\n", psz_mes ? psz_mes: "", psz_err ? psz_err: "");
if (psz_err)
free(psz_err);
if (psz_mes)
free(psz_mes);
}
if (!buffer)
throw ParanoiaSentNoData();
if (!_f(cursor - begin, end - begin, buffer))
break;
}
}