#include "discid.h"
#include <stdarg.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
static int cddb_sum(int n)
{
int ret=0;
while (n > 0) {
ret = ret + (n % 10);
n = n / 10;
}
return ret;
}
#define DISCID_STRING_BUFFER_SIZE 2048
#define MISC_STRING_BUFFER_SIZE 512
static char discid_string[DISCID_STRING_BUFFER_SIZE];
static char discid_error_message[MISC_STRING_BUFFER_SIZE];
static bool discid_string_new = true;
static char *command = "libcd-utils.a";
static bool verbose = false;
static void set_error_message(const char *command, const char *devicename, const char * perror_tag) {
if (verbose) {
fprintf(stderr, "%s: %s: ", command, devicename);
perror(perror_tag);
}
snprintf(discid_error_message, MISC_STRING_BUFFER_SIZE - 1, "%s %s: %s", command, devicename, strerror(errno));
}
char *cdrom_get_error_message() {
return discid_error_message;
}
static void append_discid_string(const char *str)
{
if ((str == NULL) || (*str == '\0')) {
return;
}
if (discid_string_new) {
strcpy(discid_string, str);
discid_string_new = false;
}
else {
strcat(discid_string, str);
}
}
static void append_discid_formatted(const char * format, ...) {
if ((format == NULL) || (*format == '\0')) {
return;
}
char str[MISC_STRING_BUFFER_SIZE];
va_list argptr;
va_start(argptr, format);
vsprintf(str, format, argptr);
va_end(argptr);
append_discid_string(str);
}
char *cdrom_get_discid(const char *devicename, int musicbrainz)
{
int len;
int drive, i, totaltime;
long int cksum=0;
struct cdrom_tochdr hdr;
struct cdrom_tocentry *TocEntry;
#if defined(__OpenBSD__) || defined(__NetBSD__)
struct ioc_read_toc_entry t;
#elif defined(__APPLE__)
dk_cd_read_disc_info_t discInfoParams;
#endif
strcpy(discid_error_message, "");
discid_error_message[MISC_STRING_BUFFER_SIZE - 1] = '\0';
drive = open(devicename, O_RDONLY | O_NONBLOCK);
if (drive < 0) {
fprintf(stderr, "%s: %s: ", command, devicename);
set_error_message(command, devicename, "open");
return NULL;
}
#if defined(__APPLE__)
memset(&discInfoParams, 0, sizeof(discInfoParams));
discInfoParams.buffer = &hdr;
discInfoParams.bufferLength = sizeof(hdr);
if (ioctl(drive, DKIOCCDREADDISCINFO, &discInfoParams) < 0
|| discInfoParams.bufferLength != sizeof(hdr)) {
set_error_message(command, devicename, "DKIOCCDREADDISCINFO");
return NULL;
}
#else
if (ioctl(drive, CDROMREADTOCHDR, &hdr) < 0) {
set_error_message(command, devicename, "CDROMREADTOCHDR");
return NULL;
}
#endif
unsigned char last = hdr.cdth_trk1;
len = (last + 1) * sizeof(struct cdrom_tocentry);
TocEntry = malloc(len);
if (!TocEntry) {
set_error_message(command, devicename, "Can't allocate memory for TOC entries");
return NULL;
}
#if defined(__OpenBSD__)
t.starting_track = 0;
#elif defined(__NetBSD__)
t.starting_track = 1;
#endif
#if defined(__OpenBSD__) || defined(__NetBSD__)
t.address_format = CDROM_LBA;
t.data_len = len;
t.data = TocEntry;
memset(TocEntry, 0, len);
if (ioctl(drive, CDIOREADTOCENTRYS, (char *) &t) < 0) {
set_error_message(command, devicename, "CDIOREADTOCENTRYS");
}
#elif defined(__APPLE__)
dk_cd_read_track_info_t trackInfoParams;
memset( &trackInfoParams, 0, sizeof( trackInfoParams ) );
trackInfoParams.addressType = kCDTrackInfoAddressTypeTrackNumber;
trackInfoParams.bufferLength = sizeof( *TocEntry );
for (i = 0; i < last; i++) {
trackInfoParams.address = i + 1;
trackInfoParams.buffer = &TocEntry[i];
if (ioctl(drive, DKIOCCDREADTRACKINFO, &trackInfoParams) < 0) {
set_error_message(command, devicename, "DKIOCCDREADTRACKINFO");
}
}
TocEntry[last].cdte_track_address = TocEntry[last-1].trackSize + TocEntry[last-1].trackStartAddress;
#else
for (i=0; i < last; i++) {
TocEntry[i].cdte_track = i + 1;
TocEntry[i].cdte_format = CDROM_LBA;
if (ioctl(drive, CDROMREADTOCENTRY, &TocEntry[i]) < 0) {
set_error_message(command, devicename, "CDROMREADTOCENTRY");
return NULL;
}
}
TocEntry[last].cdte_track = CDROM_LEADOUT;
TocEntry[last].cdte_format = CDROM_LBA;
if (ioctl(drive, CDROMREADTOCENTRY, &TocEntry[i]) < 0) {
set_error_message(command, devicename, "CDROMREADTOCENTRY");
return NULL;
}
#endif
#if defined(__FreeBSD__)
TocEntry[i].cdte_track_address = ntohl(TocEntry[i].cdte_track_address);
#endif
for (i=0; i < last; i++) {
#if defined(__FreeBSD__)
TocEntry[i].cdte_track_address = ntohl(TocEntry[i].cdte_track_address);
#endif
cksum += cddb_sum((TocEntry[i].cdte_track_address + CD_MSF_OFFSET) / CD_FRAMES);
}
totaltime = ((TocEntry[last].cdte_track_address + CD_MSF_OFFSET) / CD_FRAMES) -
((TocEntry[0].cdte_track_address + CD_MSF_OFFSET) / CD_FRAMES);
if (! musicbrainz) {
append_discid_formatted("%08lx ", (cksum % 0xff) << 24 | totaltime << 8 | last);
}
append_discid_formatted("%d", last);
for (i = 0; i < last; i++) {
append_discid_formatted(" %d", TocEntry[i].cdte_track_address + CD_MSF_OFFSET);
}
if (musicbrainz) {
append_discid_formatted(" %d", TocEntry[last].cdte_track_address + CD_MSF_OFFSET);
} else {
append_discid_formatted(" %d", (TocEntry[last].cdte_track_address + CD_MSF_OFFSET) / CD_FRAMES);
}
free(TocEntry);
close(drive);
return discid_string;
}
#ifdef STANDALONE
int main(int argc, char *argv[])
{
int musicbrainz=0;
char *devicename=DEVICE_NAME;
command=argv[0];
if (argc >= 2 && ! strcmp(argv[1], "--musicbrainz")) {
musicbrainz = 1;
argc--;
argv++;
}
if (argc == 2) {
devicename = argv[1];
} else if (argc > 2) {
fprintf(stderr, "Usage: %s [--musicbrainz] [devicename]\n",
command);
exit(1);
}
char *discid = cdrom_get_discid(devicename, musicbrainz);
printf("%s\n", discid);
return 0;
}
#endif