yet another cddb patch
Thomas HERAULT <[email protected]> Tue, 19 Nov 2002 18:51:49 +0100
| Newsgroups | gmane.comp.audio.cd-paranoia.devel |
|---|---|
| Organization | Laboratoire de Recherche en Informatique (parallelisme) |
| Message-ID | <[email protected]> |
Hello, I'm an over-satisfied user of cdparanoia, and I've made a patch to fetch track titles from freedb databases. I know this will not be included in the release of cdparanoia, since it is not its goal, but if someone need it, it applies against cdparanoia-III-alpha-9.8 (couldn't find cdparanoia-IV to test). Cheers, /T
cdparanoia-III-cddb.patch
(application/octet-stream, 45.6 KB)
diff -urN cdparanoia-III-alpha9.8/Makefile.in cdparanoia-III-alpha9.8-cddb/Makefile.in
--- cdparanoia-III-alpha9.8/Makefile.in Wed Mar 28 00:46:58 2001
+++ cdparanoia-III-alpha9.8-cddb/Makefile.in Wed Sep 12 13:28:32 2001
@@ -25,7 +25,7 @@
LIBDIR=@libdir@
PWD = $(shell pwd)
-OFILES = main.o report.o header.o buffering_write.o
+OFILES = main.o report.o header.o buffering_write.o cddb.o
export STATIC
export VERSION
diff -urN cdparanoia-III-alpha9.8/cddb.c cdparanoia-III-alpha9.8-cddb/cddb.c
--- cdparanoia-III-alpha9.8/cddb.c Thu Jan 1 01:00:00 1970
+++ cdparanoia-III-alpha9.8-cddb/cddb.c Tue Nov 19 17:58:36 2002
@@ -0,0 +1,907 @@
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <linux/cdrom.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#define _CDDB_C_
+#include "cddb.h"
+
+static const char CDDB_SIGNON_400[] = "Signon protocol error";
+static const char CDDB_SIGNON_200[] = "OK, read/write allowed";
+static const char CDDB_SIGNON_201[] = "OK, read only";
+static const char CDDB_SIGNON_432[] = "No connections allowed: permission denied";
+static const char CDDB_SIGNON_433[] = "No connections allowed: too much users";
+static const char CDDB_SIGNON_434[] = "No connections allowed: system load too high";
+static const char CDDB_HANDSHAKE_200[] = "Handshake successful";
+static const char CDDB_HANDSHAKE_431[] = "Handshake not successful, closing connection";
+static const char CDDB_HANDSHAKE_402[] = "Already shook hands";
+static const char CDDB_HANDSHAKE_400[] = "Handshake protocol error";
+static const char CDDB_QUERY_200[] = "Found exact match";
+static const char CDDB_QUERY_211[] = "Found inexact matches, list follows (until terminating marker)";
+static const char CDDB_QUERY_210[] = "Found exact matches, list follows (until terminating marker)";
+static const char CDDB_QUERY_400[] = "Query protocol error";
+static const char CDDB_QUERY_202[] = "No match found";
+static const char CDDB_QUERY_403[] = "Database entry is corrupt";
+static const char CDDB_QUERY_409[] = "No handshake";
+static const char CDDB_IDENTIFY_454[] = "Unable to read TOC header";
+static const char CDDB_IDENTIFY_455[] = "Unable to read TOC entry";
+static const char CDDB_READ_210[] = "OK, CDDB database entry follows (until terminating marker)";
+static const char CDDB_READ_401[] = "Specified CDDB entry not found";
+static const char CDDB_READ_402[] = "Server error";
+static const char CDDB_READ_403[] = "Database entry is corrupt";
+static const char CDDB_READ_409[] = "No handshake";
+static const char CDDB_READ_400[] = "Read protocol error";
+static const char CDDB_DB_ERROR[] = "Syntax error while parsing database entry";
+
+//#define DEBUG(toto...) fprintf(stderr, toto)
+#define DEBUG(toto...)
+
+int cddb_is_fatal(int errno)
+{
+ return (errno < 200) || (errno == 400) || ((errno >= 430) && (errno < 440));
+}
+
+int cddb_is_ok(int errno)
+{
+ return (errno >= 200) && (errno < 300);
+}
+
+int cddb_is_system(int errno)
+{
+ return (errno < 200);
+}
+
+char *read_line(struct cddb *c)
+{
+ int i,size;
+ static unsigned int pos = 0;
+ char *line;
+
+ yep:
+ for(i = pos; i < cddb_speech_size; i++)
+ if(cddb_speech[i] == '
')
+ break;
+ if(cddb_speech && cddb_speech[i] == '
')
+ {
+ line = cddb_speech + pos;
+ pos = i+2;
+ cddb_speech[i] = 0;
+ DEBUG("<-[%s]\n", line);
+ return line;
+ }
+
+ if(ioctl(c->fd, FIONREAD, &size) < 0)
+ {
+ cddb_errno = errno;
+ cddb_errstr = sys_errlist[errno];
+ return NULL;
+ }
+ cddb_speech = (char*)realloc(cddb_speech, cddb_speech_size + size + 1);
+ cddb_speech_size += size;
+ if(!cddb_speech)
+ {
+ cddb_errno = errno;
+ cddb_errstr = sys_errlist[errno];
+ return NULL;
+ }
+ if(recv(c->fd, cddb_speech + cddb_speech_size-size, size, 0) < size)
+ {
+ cddb_speech[cddb_speech_size] = 0;
+ DEBUG("<!- [%s]\n", cddb_speech + cddb_speech_size-size);
+ cddb_errno = errno;
+ cddb_errstr = sys_errlist[errno];
+ return NULL;
+ }
+ cddb_speech[cddb_speech_size] = 0;
+ goto yep;
+}
+
+int write_packet(struct cddb *c, char *msg)
+{
+ char *emsg;
+
+ emsg = (char*)alloca(strlen(msg)+2);
+ sprintf(emsg, "%s\n", msg);
+ DEBUG("-> [%s]\n", msg);
+
+ if(send(c->fd, emsg, strlen(msg)+1, 0) < strlen(msg)+1)
+ {
+ cddb_errno = errno;
+ cddb_errstr = sys_errlist[errno];
+ return -1;
+ }
+ return strlen(msg)+1;
+}
+
+int returncode(char *line)
+{
+ int r;
+ if(sscanf(line, "%d", &r) != 1)
+ return -1;
+ return r;
+}
+
+struct cddb *cddb_connect(char *hostname, short port)
+{
+ struct cddb *c;
+ struct hostent *hp;
+ struct sockaddr_in remote;
+ int nr;
+ char *line;
+
+ c = (struct cddb *)malloc(sizeof(struct cddb));
+ c->hostname = (char *)malloc(strlen(hostname)+1);
+ strcpy(c->hostname, hostname);
+ c->port = port;
+ hp = gethostbyname(hostname);
+ if(!hp)
+ {
+ cddb_errstr = sys_errlist[errno];
+ cddb_errno = errno;
+ free(c);
+ return NULL;
+ }
+
+ c->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if(c->fd < 0)
+ {
+ cddb_errstr = sys_errlist[errno];
+ cddb_errno = errno;
+ free(c);
+ return NULL;
+ }
+
+ remote.sin_family = AF_INET;
+ remote.sin_port = htons(port);
+ memcpy(&remote.sin_addr, hp->h_addr, hp->h_length);
+
+ if(connect(c->fd, (struct sockaddr*)&remote, sizeof(remote))<0)
+ {
+ cddb_errstr = sys_errlist[errno];
+ cddb_errno = errno;
+ close(c->fd);
+ free(c);
+ return NULL;
+ }
+
+ if((line = read_line(c)))
+ {
+ switch(returncode(line))
+ {
+ case 200:
+ cddb_errno = 200;
+ cddb_errstr = CDDB_SIGNON_200;
+ return c;
+ case 201:
+ cddb_errno = 201;
+ cddb_errstr = CDDB_SIGNON_201;
+ return c;
+ case 432:
+ cddb_errno = 432;
+ cddb_errstr = CDDB_SIGNON_432;
+ break;
+ case 433:
+ cddb_errno = 433;
+ cddb_errstr = CDDB_SIGNON_433;
+ break;
+ case 434:
+ cddb_errno = 434;
+ cddb_errstr = CDDB_SIGNON_434;
+ break;
+ default:
+ cddb_errno = 400;
+ cddb_errstr = CDDB_SIGNON_400;
+ }
+ }
+ close(c->fd);
+ free(c);
+ return NULL;
+}
+
+int cddb_handshake(struct cddb *c, char *client, char *version)
+{
+ char msg[strlen(client)+strlen(version)+78+L_cuserid];
+ char *line;
+
+ sprintf(msg, "cddb hello ");
+ cuserid(msg + strlen(msg));
+ strcat(msg, " ");
+ if(gethostname(msg+strlen(msg), 64)<0)
+ {
+ cddb_errno = errno;
+ cddb_errstr = sys_errlist[errno];
+ return -1;
+ }
+ strcat(msg, " ");
+ strcat(msg, client);
+ strcat(msg, " ");
+ strcat(msg, version);
+
+ if(write_packet(c, msg) < 0)
+ return -1;
+ if(!(line = read_line(c)))
+ return -1;
+
+ switch(returncode(line))
+ {
+ case 200:
+ cddb_errno = 200;
+ cddb_errstr = CDDB_HANDSHAKE_200;
+ return 1;
+ case 431:
+ cddb_errno = 431;
+ cddb_errstr = CDDB_HANDSHAKE_431;
+ close(c->fd);
+ free(c);
+ return -1;
+ case 402:
+ cddb_errno = 402;
+ cddb_errstr = CDDB_HANDSHAKE_402;
+ return 0;
+ default:
+ cddb_errno = 400;
+ cddb_errstr = CDDB_HANDSHAKE_400;
+ close(c->fd);
+ free(c);
+ return -1;
+ }
+}
+
+struct cddb_disc *cddb_identify_disc(int ioctl_fd)
+{
+ int i;
+ int tracks;
+ struct cdrom_tochdr hdr;
+ struct cdrom_tocentry entry;
+ struct cddb_disc *d;
+
+ int cddb_sum(int n)
+ {
+ int ret; /* For backward compatibility this algorithm must not change */
+ ret = 0;
+ while (n > 0) {
+ ret = ret + (n % 10);
+ n = n / 10;
+ }
+ return (ret);
+ }
+
+ unsigned long cddb_discid(int tot_trks, int *minutes, int *seconds)
+ {
+ int i,
+ t = 0,
+ n = 0; /* For backward compatibility this algorithm must not change */
+ i = 0;
+ while (i < tot_trks) {
+ n = n + cddb_sum((minutes[i] * 60) + seconds[i]);
+ i++;
+ }
+ t = ((minutes[tot_trks] * 60) + seconds[tot_trks]) -
+ ((minutes[0] * 60) + seconds[0]);
+ return ((n % 0xff) << 24 | t << 8 | tot_trks);
+ }
+
+ cddb_errno = 0;
+ cddb_errstr = sys_errlist[0];
+
+ /* get TocHeader to find out how many entries there are */
+ if(ioctl(ioctl_fd, CDROMREADTOCHDR, &hdr ))
+ switch(errno){
+ case EPERM:
+ cddb_errno = EPERM;
+ cddb_errstr = sys_errlist[errno];
+ return NULL;
+ default:
+ cddb_errno = 454;
+ cddb_errstr = CDDB_IDENTIFY_454;
+ return NULL;
+ }
+
+ d = (struct cddb_disc*)malloc(sizeof(struct cddb_disc));
+ d->trackoffsets = (int*)malloc(sizeof(int)*hdr.cdth_trk1+1);
+ d->minutes = (int*)malloc(sizeof(int)*hdr.cdth_trk1+1);
+ d->seconds = (int*)malloc(sizeof(int)*hdr.cdth_trk1+1);
+ d->frames = (int*)malloc(sizeof(int)*hdr.cdth_trk1+1);
+ d->nbtracks = hdr.cdth_trk1;
+
+ /* get all TocEntries */
+ for(i=0;i<hdr.cdth_trk1;i++){
+ entry.cdte_track= i+1;
+ entry.cdte_format = CDROM_MSF;
+ if(ioctl(ioctl_fd,CDROMREADTOCENTRY,&entry)){
+ cddb_errno = 455;
+ cddb_errstr = CDDB_IDENTIFY_455;
+ free(d->trackoffsets);
+ free(d->minutes);
+ free(d->seconds);
+ free(d->frames);
+ free(d);
+ return NULL;
+ }
+
+ d->minutes[i] = entry.cdte_addr.msf.minute;
+ d->seconds[i] = entry.cdte_addr.msf.second;
+ d->frames[i] = entry.cdte_addr.msf.frame;
+ d->trackoffsets[i] = 75*(60*d->minutes[i]+d->seconds[i])+d->frames[i];
+ }
+
+ entry.cdte_track = CDROM_LEADOUT;
+ entry.cdte_format = CDROM_MSF;
+ if(ioctl(ioctl_fd, CDROMREADTOCENTRY, &entry)){
+ cddb_errno = 455;
+ cddb_errstr = CDDB_IDENTIFY_455;
+ free(d->trackoffsets);
+ free(d->minutes);
+ free(d->seconds);
+ free(d->frames);
+ free(d);
+ return NULL;
+ }
+ d->minutes[i] = entry.cdte_addr.msf.minute;
+ d->seconds[i] = entry.cdte_addr.msf.second;
+ d->frames[i] = entry.cdte_addr.msf.frame;
+ d->trackoffsets[i] = 60*d->minutes[i]+d->seconds[i]+(d->frames[i]/75);
+ d->discid = cddb_discid(d->nbtracks, d->minutes, d->seconds);
+
+ return d;
+}
+
+void cddb_query_free(struct cddb_query *q)
+{
+ if(q)
+ {
+ free(q->categ);
+ free(q->title);
+ cddb_query_free(q->next);
+ free(q);
+ }
+}
+
+int until_first_space(char *line)
+{
+ int i;
+ for(i = 0; line[i]; i++)
+ if(line[i] == ' ')
+ return i;
+ return -1;
+}
+
+int isendmark(char *line)
+{
+ return (!strcmp(line, "."));
+}
+
+struct cddb_query *cddb_query(struct cddb *c, struct cddb_disc *d)
+{
+ char msg[22 + 10*(d->nbtracks+1)];
+ char ent[10];
+ int i;
+ struct cddb_query *q, *prev;
+ int categlen;
+ char *line;
+
+ sprintf(msg, "cddb query %08x %d",
+ d->discid, d->nbtracks);
+ for(i = 0; i < d->nbtracks+1; i++)
+ {
+ sprintf(ent, " %d", d->trackoffsets[i]);
+ strcat(msg, ent);
+ }
+
+ if(write_packet(c, msg) < 0)
+ return NULL;
+ if(!(line = read_line(c)))
+ return NULL;
+
+ switch(returncode(line))
+ {
+ case 200:
+ cddb_errno = 200;
+ cddb_errstr = CDDB_QUERY_200;
+ q = (struct cddb_query*)malloc(sizeof(struct cddb_query));
+ categlen = until_first_space(line) + 1;
+ q->categ = (char *)malloc(categlen);
+ q->title = (char *)malloc(strlen(line) - 9 - categlen);
+ q->next = NULL;
+ if(sscanf(line, "%*d %s %08x %[^\n]",
+ q->categ, &q->discid, q->title) != 3)
+ {
+ cddb_query_free(q);
+ cddb_errstr = CDDB_QUERY_400;
+ cddb_errno = 400;
+ close(c->fd);
+ free(c);
+ return NULL;
+ }
+ return q;
+ break;
+ case 211:
+ cddb_errno = 211;
+ cddb_errstr = CDDB_QUERY_211;
+ goto do_211_210;
+ case 210:
+ cddb_errno = 210;
+ cddb_errstr = CDDB_QUERY_210;
+ do_211_210:
+ q = NULL;
+ do {
+ if(!(line=read_line(c)))
+ {
+ cddb_query_free(q);
+ return NULL;
+ }
+ if(!isendmark(line))
+ {
+ if(!q)
+ {
+ q = (struct cddb_query*)malloc(sizeof(struct cddb_query));
+ categlen = until_first_space(line) + 1;
+ q->categ = (char *)malloc(categlen);
+ q->title = (char *)malloc(strlen(line) - 9 - categlen);
+ q->next = NULL;
+ if(sscanf(line, "%s %08x %[^\n]",
+ q->categ, &q->discid, q->title) != 3)
+ {
+ cddb_query_free(q);
+ cddb_errstr = CDDB_QUERY_400;
+ cddb_errno = 400;
+ close(c->fd);
+ free(c);
+ return NULL;
+ }
+ prev = q;
+ }
+ else
+ {
+ prev->next = (struct cddb_query*)malloc(sizeof(struct cddb_query));
+ categlen = until_first_space(line + 4) + 1;
+ prev->next->categ = (char *)malloc(categlen);
+ prev->next->title = (char *)malloc(strlen(line) - 9 - categlen);
+ prev->next->next = NULL;
+ if(sscanf(line, "%s %08x %[^\n]",
+ prev->next->categ, &prev->next->discid, prev->next->title) != 3)
+ {
+ cddb_query_free(q);
+ cddb_errstr = CDDB_QUERY_400;
+ cddb_errno = 400;
+ close(c->fd);
+ free(c);
+ return NULL;
+ }
+ prev = prev->next;
+ }
+ }
+ } while(!isendmark(line));
+ return q;
+ break;
+ case 202:
+ cddb_errstr = CDDB_QUERY_202;
+ cddb_errno = 202;
+ return NULL;
+ break;
+ case 403:
+ cddb_errstr = CDDB_QUERY_403;
+ cddb_errno = 403;
+ return NULL;
+ break;
+ case 409:
+ cddb_errstr = CDDB_QUERY_409;
+ cddb_errno = 409;
+ return NULL;
+ break;
+ default:
+ cddb_errstr = CDDB_QUERY_400;
+ cddb_errno = 400;
+ close(c->fd);
+ free(c);
+ return NULL;
+ }
+}
+
+void cddb_db_entry_free(struct cddb_db_entry *e)
+{
+ int i;
+ if(e->comm)
+ free(e->comm);
+ if(e->disctitle)
+ free(e->disctitle);
+ if(e->author)
+ free(e->author);
+ if(e->dgenre)
+ free(e->dgenre);
+ if(e->extended_data)
+ free(e->extended_data);
+ if(e->titles)
+ {
+ for(i = 0; i < e->nbtitles; i++)
+ if(e->titles[i])
+ free(e->titles[i]);
+ free(e->titles);
+ }
+ if(e->extended_title_data)
+ {
+ for(i = 0; i < e->nbtitles; i++)
+ if(e->extended_title_data[i])
+ free(e->extended_title_data[i]);
+ free(e->extended_title_data);
+ }
+ free(e);
+}
+
+void cddb_print_db_entry(struct cddb_db_entry *e)
+{
+ int i;
+
+ if(e->comm)
+ printf("Commentaire : %s\n\n", e->comm);
+ else
+ printf("pas de commentaire\n\n");
+ if(e->disctitle)
+ printf("titre : %s\n\n", e->disctitle);
+ else
+ printf("pas de titre\n\n");
+ if(e->author)
+ printf("Artiste : %s\n\n", e->author);
+ else
+ printf("pas d'artiste\n\n");
+ if(e->dgenre)
+ printf("Genre : %s\n\n", e->dgenre);
+ else
+ printf("pas de genre\n\n");
+ if(e->extended_data)
+ printf("Données supplémentaires sur le disque : %s\n\n", e->extended_data);
+ else
+ printf("pas de données supplémentaires sur le disque\n\n");
+ for(i = 0; i < e->nbtitles; i++)
+ {
+ printf("TITRE %d : ", i);
+ if(e->titles[i])
+ printf("%s", e->titles[i]);
+ else
+ printf("???");
+ if(e->extended_title_data[i])
+ printf(" (%s)\n", e->extended_title_data[i]);
+ else
+ printf("\n");
+ }
+ printf("\n");
+}
+
+struct cddb_db_entry *cddb_read(struct cddb *c, struct cddb_disc *d, struct cddb_query *q)
+{
+ char msg[21+strlen(q->categ)];
+ char *line;
+ struct cddb_db_entry *e;
+ char *p;
+ int len, n;
+
+ sprintf(msg, "cddb read %s %08x", q->categ, q->discid);
+ if(write_packet(c, msg) < 0)
+ return NULL;
+ if(!(line = read_line(c)))
+ return NULL;
+
+ switch(returncode(line))
+ {
+ case 210:
+ cddb_errno = 210;
+ cddb_errstr = CDDB_READ_210;
+ e = (struct cddb_db_entry*)calloc(1,sizeof(struct cddb_db_entry));
+ e->nbtitles = d->nbtracks;
+ e->titles = (char**)calloc(d->nbtracks,sizeof(char*));
+ e->extended_title_data = (char**)calloc(d->nbtracks,sizeof(char*));
+ e->comm = (char*)malloc(1);
+ e->comm[0] = 0;
+ do {
+ if(!(line=read_line(c)))
+ {
+ cddb_db_entry_free(e);
+ return NULL;
+ }
+ if(!isendmark(line))
+ {
+ switch(line[0])
+ {
+ case '#': //commentary
+ len = strlen(e->comm);
+ e->comm = (char*)realloc(e->comm, len+strlen(line+1)+2);
+ strcat(e->comm, line+1);
+ strcat(e->comm, "\n");
+ break;
+ case 'D':
+ switch(line[1])
+ {
+ case 'I': //DISCID
+ if(sscanf(line, "DISCID=%08x", &e->discid) != 1)
+ goto dberror;
+ break;
+ case 'T': //DTITLE
+ if(strncmp(line, "DTITLE=", 7))
+ goto dberror;
+ if( (p = strstr(line+7, " / ")) )
+ {
+ e->author = (char*)malloc(((p-line)-7));
+ memcpy(e->author, line+7, ((p-line)-7));
+ e->author[((p-line)-7)] = 0;
+ e->disctitle = (char*)malloc(strlen(p+1)+1);
+ strcpy(e->disctitle, p+3);
+ }
+ else
+ {
+ e->disctitle = (char*)malloc(strlen(line+7)+1);
+ strcpy(e->disctitle, line+7);
+ }
+ break;
+ case 'Y': //DYEAR
+ if(sscanf(line, "DYEAR=%d", &e->dyear) != 1)
+ goto dberror;
+ break;
+ case 'G': //DGENRE
+ if(strncmp(line, "DGENRE=", 7))
+ goto dberror;
+ break;
+ default: //Unknown
+ goto dberror;
+ }
+ break;
+ case 'T': // TTITLEN
+ if(strncmp(line, "TTITLE", 6))
+ goto dberror;
+ if(sscanf(line+6, "%d=", &n) != 1)
+ goto dberror;
+ if(n < 0 || n >= e->nbtitles)
+ goto dberror;
+ p = strstr(line, "=")+1;
+ if(p == (char*)1)
+ goto dberror;
+ len = (e->titles[n]?strlen(e->titles[n]):0);
+ e->titles[n] = (char*)realloc(e->titles[n], len+strlen(p)+2);
+ if(!len)
+ e->titles[n][0] = 0;
+ else
+ strcat(e->titles[n], "\n");
+ strcat(e->titles[n], p);
+ break;
+ case 'E':
+ switch(line[3])
+ {
+ case 'D': // EXTD
+ if(strncmp(line, "EXTD=", 5))
+ goto dberror;
+ len = (e->extended_data?strlen(e->extended_data):0);
+ e->extended_data = (char*)realloc(e->extended_data, len+strlen(line+5)+2);
+ if(!len)
+ e->extended_data[0] = 0;
+ else
+ strcat(e->extended_data, "\n");
+ strcat(e->extended_data, line+5);
+ break;
+ case 'T': // EXTTN
+ if(strncmp(line, "EXTT", 4))
+ goto dberror;
+ if(sscanf(line+4, "%d=", &n) != 1)
+ goto dberror;
+ if(n < 0 || n >=e->nbtitles)
+ goto dberror;
+ p = strstr(line, "=")+1;
+ if(p == (char*)1)
+ goto dberror;
+ len = (e->extended_title_data[n]?strlen(e->extended_title_data[n]):0);
+ e->extended_title_data[n] = (char*)realloc(e->extended_title_data[n], len+strlen(p)+2);
+ if(!len)
+ e->extended_title_data[n][0] = 0;
+ else
+ strcat(e->extended_title_data[n], "\n");
+ strcat(e->extended_title_data[n], p);
+ break;
+ default: // Unknown
+ goto dberror;
+ }
+ break;
+ case 'P': // PLAYORDER
+ break;
+ default: // Unknown
+ goto dberror;
+ }
+ }
+ } while(!isendmark(line));
+ return e;
+ dberror:
+ cddb_db_entry_free(e);
+ cddb_errno = 408;
+ cddb_errstr = CDDB_DB_ERROR;
+ return NULL;
+ case 401:
+ cddb_errno = 401;
+ cddb_errstr = CDDB_READ_401;
+ return NULL;
+ case 402:
+ cddb_errno = 402;
+ cddb_errstr = CDDB_READ_402;
+ return NULL;
+ case 403:
+ cddb_errno = 403;
+ cddb_errstr = CDDB_READ_403;
+ return NULL;
+ case 409:
+ cddb_errno = 409;
+ cddb_errstr = CDDB_READ_409;
+ return NULL;
+ default:
+ cddb_errno = 400;
+ cddb_errstr = CDDB_READ_400;
+ return NULL;
+ }
+}
+
+void cddb_quit(struct cddb *c)
+{
+ char msg[] = "quit";
+
+ write_packet(c, msg);
+ read_line(c);
+
+ close(c->fd);
+}
+
+void cddb_print_speech(void)
+{
+ int i;
+ for(i = 0; i < cddb_speech_size; i++)
+ if(cddb_speech[i] == 0)
+ printf("\n");
+ else
+ printf("%c", cddb_speech[i]);
+}
+
+void cddb_speech_erase()
+{
+ free(cddb_speech);
+ cddb_speech = NULL;
+ cddb_speech_size = 0;
+}
+
+void cddb_disc_free(struct cddb_disc *cd)
+{
+ if(cd)
+ {
+ if(cd->trackoffsets)
+ free(cd->trackoffsets);
+ if(cd->minutes)
+ free(cd->minutes);
+ if(cd->seconds)
+ free(cd->seconds);
+ if(cd->frames)
+ free(cd->frames);
+ free(cd);
+ }
+}
+
+void cddb_free(struct cddb *c)
+{
+ if(c)
+ {
+ if(c->hostname)
+ free(c->hostname);
+ free(c);
+ }
+}
+
+static char *filize(char *f)
+{
+ char *c;
+
+ if(!f)
+ return NULL;
+
+ for(c=f; *c; c++)
+ if(*c == '/')
+ *c = ',';
+
+ return f;
+}
+
+int cddb_snprintf(char *outfile, int maxlen, char *format, struct cddb_db_entry *e, int title,
+ char *path, char *extension)
+{
+ int pos = 0;
+ int i;
+
+ fprintf(stderr, "snprinteffing\n");
+
+ outfile[0] = 0;
+ if(path && ( (pos += snprintf(outfile+pos, maxlen-pos, "%s", path)) >= maxlen))
+ goto out_err;
+
+ for(i=0;format[i];i++)
+ {
+ switch(format[i])
+ {
+ case '%':
+ i++;
+ switch(format[i])
+ {
+ case 'c':
+ if( (pos += snprintf(outfile+pos, maxlen-pos, "%s", e->comm?filize(e->comm):"none")) >= maxlen)
+ goto out_err;
+ break;
+ case 'D':
+ if( (pos += snprintf(outfile+pos, maxlen-pos, "%s", e->disctitle?filize(e->disctitle):"none")) >= maxlen )
+ goto out_err;
+ break;
+ case 'A':
+ if( (pos += snprintf(outfile+pos, maxlen-pos, "%s", e->author?filize(e->author):"none")) >= maxlen )
+ goto out_err;
+ break;
+ case 'Y':
+ if( (pos += snprintf(outfile+pos, maxlen-pos, "%04d", e->dyear)) >= maxlen )
+ goto out_err;
+ break;
+ case 'y':
+ if( (pos += snprintf(outfile+pos, maxlen-pos, "%02d", e->dyear % 100)) >= maxlen )
+ goto out_err;
+ break;
+ case 'G':
+ if( (pos += snprintf(outfile+pos, maxlen-pos, "%s", e->dgenre?filize(e->dgenre):"none")) >= maxlen )
+ goto out_err;
+ break;
+ case 'X':
+ if( (pos += snprintf(outfile+pos, maxlen-pos, "%s", e->extended_data?filize(e->extended_data):"none")) >= maxlen )
+ goto out_err;
+ break;
+ case 'N':
+ if( (pos += snprintf(outfile+pos, maxlen-pos, "%d", e->nbtitles)) >= maxlen )
+ goto out_err;
+ break;
+ case 'T':
+ if( (pos += snprintf(outfile+pos, maxlen-pos, "%s",
+ ( (title<e->nbtitles) && e->titles[title])?
+ filize(e->titles[title]):
+ "none")) >= maxlen )
+ goto out_err;
+ break;
+ case 'x':
+ if( (pos += snprintf(outfile+pos, maxlen-pos, "%s",
+ ((title<e->nbtitles) && e->extended_title_data[title])?
+ filize(e->extended_title_data[title]):
+ "none")) >= maxlen )
+ goto out_err;
+ break;
+ case 'C':
+ if( (pos += snprintf(outfile+pos, maxlen-pos, "%02d", title+1)) >= maxlen )
+ goto out_err;
+ break;
+ case '%':
+ if( (pos += snprintf(outfile+pos, maxlen-pos, "%%")) >= maxlen)
+ goto out_err;
+ break;
+ case 0:
+ goto out;
+ default:
+ fprintf(stderr, "cddb wrong output format flag <%c>\n", format[i]);
+ return -1;
+ }
+ break;
+ case 0:
+ goto out;
+ default:
+ if( (pos += snprintf(outfile+pos, maxlen-pos, "%c", format[i])) >= maxlen)
+ goto out_err;
+ }
+ }
+
+ out:
+ if(extension)
+ pos += snprintf(outfile+pos, maxlen-pos, "%s", extension);
+
+ out_err:
+ return pos;
+}
diff -urN cdparanoia-III-alpha9.8/cddb.h cdparanoia-III-alpha9.8-cddb/cddb.h
--- cdparanoia-III-alpha9.8/cddb.h Thu Jan 1 01:00:00 1970
+++ cdparanoia-III-alpha9.8-cddb/cddb.h Tue Nov 19 16:10:28 2002
@@ -0,0 +1,70 @@
+#ifndef _CDDB_H_
+#define _CDDB_H_
+
+struct cddb {
+ char *hostname;
+ short port;
+ int fd;
+};
+
+struct cddb_disc {
+ unsigned long discid;
+ int nbtracks;
+ int *trackoffsets;
+ int *minutes;
+ int *seconds;
+ int *frames;
+};
+
+struct cddb_query {
+ unsigned long discid;
+ char *categ;
+ char *title;
+ struct cddb_query *next;
+};
+
+struct cddb_db_entry {
+ char *comm; /* %c */
+ unsigned long discid;
+ char *disctitle; /* %D */
+ char *author; /* %A */
+ short dyear; /* %Y|%y */
+ char *dgenre; /* %G */
+ char *extended_data; /* %X */
+ int nbtitles; /* %N */
+ char **titles; /* %T */
+ char **extended_title_data; /* %x */
+ /* %C : title index */
+};
+
+#ifndef _CDDB_C_
+#define GLOBHACK extern
+#else
+#define GLOBHACK
+#endif
+
+GLOBHACK int cddb_errno;
+GLOBHACK int cddb_speech_size;
+GLOBHACK char *cddb_speech;
+GLOBHACK const char *cddb_errstr;
+
+int cddb_is_fatal(int errno);
+int cddb_is_ok(int errno);
+int cddb_is_system(int errno);
+struct cddb *cddb_connect(char *hostname, short port);
+int cddb_handshake(struct cddb *c, char *client, char *version);
+struct cddb_disc *cddb_identify_disc(int ioctl_fd);
+void cddb_query_free(struct cddb_query *q);
+struct cddb_query *cddb_query(struct cddb *c, struct cddb_disc *d);
+void cddb_db_entry_free(struct cddb_db_entry *e);
+void cddb_print_db_entry(struct cddb_db_entry *e);
+struct cddb_db_entry *cddb_read(struct cddb *c, struct cddb_disc *d, struct cddb_query *q);
+void cddb_quit(struct cddb *c);
+void cddb_speech_erase();
+void cddb_disc_free(struct cddb_disc *cd);
+void cddb_free(struct cddb *c);
+int cddb_snprintf(char *outfile, int maxlen, char *format,
+ struct cddb_db_entry *e, int title,
+ char *path, char *extension);
+
+#endif
diff -urN cdparanoia-III-alpha9.8/cddbtest.c cdparanoia-III-alpha9.8-cddb/cddbtest.c
--- cdparanoia-III-alpha9.8/cddbtest.c Thu Jan 1 01:00:00 1970
+++ cdparanoia-III-alpha9.8-cddb/cddbtest.c Thu Sep 13 16:01:56 2001
@@ -0,0 +1,57 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "cddb.h"
+
+int main(int argc, char *argv[])
+{
+ struct cddb *c;
+ struct cddb_disc *cd;
+ struct cddb_query *q;
+ struct cddb_db_entry *e;
+ int fd;
+
+ c = cddb_connect("freedb.freedb.org", 888);
+
+ printf("connect : %s\n", cddb_errstr);
+
+
+ cddb_handshake(c, "cddblib", "0.1");
+
+ printf("handshake : %s\n", cddb_errstr);
+
+
+ fd = open("/dev/hdc", O_RDONLY);
+ if(fd<0)
+ {
+ perror("open");
+ exit(0);
+ }
+ cd = cddb_identify_disc(fd);
+ close(fd);
+
+ printf("identify : %s\n", cddb_errstr);
+
+
+ q = cddb_query(c, cd);
+
+ printf("query : %s\n", cddb_errstr);
+
+ e = cddb_read(c, cd, q);
+
+ printf("read : %s\n", cddb_errstr);
+
+ cddb_print_db_entry(e);
+
+ cddb_quit(c);
+
+ //cddb_print_speech();
+ cddb_speech_erase();
+
+ cddb_disc_free(cd);
+ cddb_query_free(q);
+ cddb_db_entry_free(e);
+ cddb_free(c);
+
+ exit(0);
+}
diff -urN cdparanoia-III-alpha9.8/cdparanoia.1 cdparanoia-III-alpha9.8-cddb/cdparanoia.1
--- cdparanoia-III-alpha9.8/cdparanoia.1 Mon Mar 26 05:44:50 2001
+++ cdparanoia-III-alpha9.8-cddb/cdparanoia.1 Tue Nov 19 18:29:11 2002
@@ -192,6 +192,68 @@
.B \-X --abort-on-skip
If the read skips due to imperfect data, a scratch, whatever, abort reading this track. If output is to a file, delete the partially completed file.
+.SH CDDB FLAGS
+
+.TP
+.B \-l --cddb-lookup
+In conjunction with -B flag, perform a cddb query to fetch informations on the cd, and names each track accordingly. Default is off
+
+.TP
+.B \-b --cddb-server <name[:port]>
+Set the server used for cddb queries and the port to connect to it. Default is freedb.freedb.org on port 888
+
+.TP
+.B \-k --cddb-output-format <format>
+Set the format of files prefix. The format is printf-like, using the following tags :
+.TP
+.B
+ %D
+Disc Title (that is the part of the string before the first '/' in the database DTITLE entry)
+.TP
+.B
+ %A
+Disc Author (that is the part of the string between the first and the second '/' in the database DTITLE entry)
+.TP
+.B
+ %c
+General commentary on the disc (Namely, the data after the second '/' in the database DTITLE entry)
+.TP
+.B
+ %Y
+The 4-digit year of the CD release (0 if no DYEAR entry in the database).
+.TP
+.B
+ %y
+The last 2 digits of the %Y flag
+.TP
+.B
+ %G
+The genre of the CD (DGENRE entry)
+.TP
+.B
+ %X
+Extended data of the disc (generally, indexes informations and references of the people who entered the entry in the database)
+.TP
+.B
+ %N
+Number of tracks referenced in the database
+.TP
+.B
+ %T
+Title of current track. If the disc has more than one author, author name will appear first, then track title separated by a comma
+.TP
+.B
+ %C
+Index of current track on 2 digits at least filled with 0s
+.TP
+.B
+ %%
+a '%'
+.TP
+ every other %sequence produce an error
+.TP
+ every other character is printed as is
+
.SH OUTPUT SMILIES
.TP
.B
@@ -328,6 +390,11 @@
cdparanoia -- "-3"
.TP
The "--" above is to distinguish "-3" from an option flag.
+
+.TP
+Extract the whole disc, putting each track on a separate file, whose name is <title>:<number>-<track-title>.cdda.wav this information being fetch from the cddb server mydb on port 2222:
+.P
+ cdparanoia -B -l -b mydb:2222 -k "%D:%C-%T"
.SH OUTPUT
The output file argument is optional; if it is not specified,
diff -urN cdparanoia-III-alpha9.8/cdparanoia.1~ cdparanoia-III-alpha9.8-cddb/cdparanoia.1~
--- cdparanoia-III-alpha9.8/cdparanoia.1~ Thu Jan 1 01:00:00 1970
+++ cdparanoia-III-alpha9.8-cddb/cdparanoia.1~ Mon Mar 26 05:44:50 2001
@@ -0,0 +1,356 @@
+.TH CDPARANOIA 1
+.SH NAME
+cdparanoia (Paranoia release III) \- an audio CD reading utility which includes extra data verification features
+.SH DATE
+version III release alpha 9.8 (02 Mar 2001)
+.SH SYNOPSIS
+.B cdparanoia
+.RB [ options ]
+.B span
+.RB [ outfile ]
+.SH DESCRIPTION
+.B cdparanoia
+retrieves audio tracks from CDDA capable CDROM drives. The data can
+be saved to a file or directed to standard output in WAV, AIFF, AIFF-C
+or raw format. Most ATAPI, SCSI and several proprietary CDROM drive
+makes are supported;
+.B cdparanoia
+can determine if the target drive is CDDA capable.
+.P
+In addition to simple reading,
+.B cdparanoia
+adds extra-robust data verification, synchronization, error handling
+and scratch reconstruction capability.
+.SH OPTIONS
+
+.TP
+.B \-v --verbose
+Be absurdly verbose about the autosensing and reading process. Good
+for setup and debugging.
+
+.TP
+.B \-q --quiet
+Do not print any progress or error information during the reading process.
+
+.TP
+.B \-e --stderr-progress
+Force output of progress information to stderr (for wrapper scripts).
+
+.TP
+.B \-V --version
+Print the program version and quit.
+
+.TP
+.B \-Q --query
+Perform CDROM drive autosense, query and print the CDROM table of
+contents, then quit.
+
+.TP
+.B \-s --search-for-drive
+Forces a complete search for a cdrom drive, even if the /dev/cdrom link exists.
+
+.TP
+.B \-h --help
+Print a brief synopsis of
+.B cdparanoia
+usage and options.
+
+.TP
+.B \-p --output-raw
+Output headerless data as raw 16 bit PCM data with interleaved samples in host byte order. To force little or big endian byte order, use
+.B \-r
+or
+.B \-R
+as described below.
+
+.TP
+.B \-r --output-raw-little-endian
+Output headerless data as raw 16 bit PCM data with interleaved samples in LSB first byte order.
+
+.TP
+.B \-R --output-raw-big-endian
+Output headerless data as raw 16 bit PCM data with interleaved samples in MSB first byte order.
+
+.TP
+.B \-w --output-wav
+Output data in Micro$oft RIFF WAV format (note that WAV data is always
+LSB first byte order).
+
+.TP
+.B \-f --output-aiff
+Output data in Apple AIFF format (note that AIFC data is
+always in MSB first byte order).
+
+.TP
+.B \-a --output-aifc
+Output data in uncompressed Apple AIFF-C format (note that AIFF-C data is
+always in MSB first byte order).
+
+.TP
+.BI "\-B --batch "
+
+Cdda2wav-style batch output flag; cdparanoia will split the output
+into multiple files at track boundaries. Output file names are
+prepended with 'track#.'
+
+.TP
+.B \-c --force-cdrom-little-endian
+Some CDROM drives misreport their endianness (or do not report it at
+all); it's possible that cdparanoia will guess wrong. Use
+.B \-c
+to force cdparanoia to treat the drive as a little endian device.
+
+.TP
+.B \-C --force-cdrom-big-endian
+As above but force cdparanoia to treat the drive as a big endian device.
+
+.TP
+.BI "\-n --force-default-sectors " n
+Force the interface backend to do atomic reads of
+.B n
+sectors per read. This number can be misleading; the kernel will often
+split read requests into multiple atomic reads (the automated Paranoia
+code is aware of this) or allow reads only wihin a restricted size
+range.
+.B This option should generally not be used.
+
+.TP
+.BI "\-d --force-cdrom-device " device
+Force the interface backend to read from
+.B device
+rather than the first readable CDROM drive it finds. This can be used
+to specify devices of any valid interface type (ATAPI, SCSI or
+proprietary).
+
+.TP
+.BI "\-g --force-generic-device " device
+This option is used along with
+.B \-d
+when one wants explicit control in setting both the SCSI cdrom and
+generic devices seperately. This option is only useful on
+non-standard SCSI setups.
+
+.TP
+.BI "\-S --force-read-speed " number
+Use this option explicitly to set the read rate of the CD drive (where
+supported). This can reduce underruns on machines with slow disks, or
+which are low on memory.
+
+.TP
+.BI "\-t --toc-offset " number
+Use this option to force the entire disc LBA addressing to shift by
+the given amount; the value is added to the beginning offsets in the
+TOC. This can be used to shift track boundaries for the whole disc
+manually on sector granularity. The next option does something
+similar...
+
+.TP
+.BI "\-T --toc-bias "
+Some drives (usually random Toshibas) report the actual track
+beginning offset values in the TOC, but then treat the beginning of
+track 1 index 1 as sector 0 for all read operations. This results in
+every track seeming to start too late (losing a bit of the beginning
+and catching a bit of the next track).
+.B \-T
+accounts for this behavior. Note that this option will cause
+cdparanoia to attempt to read sectors before or past the known user
+data area of the disc, resulting in read errors at disc edges on most
+drives and possibly even hard lockups on some buggy hardware.
+
+.TP
+.BI "\-O --sample-offset " number
+Use this option to force the entire disc to shift sample position
+output by the given amount; This can be used to shift track boundaries
+for the whole disc manually on sample granularity. Note that this will
+cause cdparanoia to attempt to read partial sectors before or past the
+known user data area of the disc, probably causing read errors on most
+drives and possibly even hard lockups on some buggy hardware.
+
+
+.TP
+.B \-Z --disable-paranoia
+Disable
+.B all
+data verification and correction features. When using -Z, cdparanoia
+reads data exactly as would cdda2wav with an overlap setting of zero.
+This option implies that
+.B \-Y
+is active.
+
+.TP
+.B \-z --never-skip[=max_retries]
+Do not accept any skips; retry forever if needed. An optional maximum
+number of retries can be specified; for comparison, default without -z is
+currently 20.
+
+.TP
+.B \-Y --disable-extra-paranoia
+Disables intra-read data verification; only overlap checking at read
+boundaries is performed. It can wedge if errors occur in the attempted overlap area. Not recommended.
+
+.TP
+.B \-X --abort-on-skip
+If the read skips due to imperfect data, a scratch, whatever, abort reading this track. If output is to a file, delete the partially completed file.
+
+.SH OUTPUT SMILIES
+.TP
+.B
+ :-)
+Normal operation, low/no jitter
+.TP
+.B
+ :-|
+Normal operation, considerable jitter
+.TP
+.B
+ :-/
+Read drift
+.TP
+.B
+ :-P
+Unreported loss of streaming in atomic read operation
+.TP
+.B
+ 8-|
+Finding read problems at same point during reread; hard to correct
+.TP
+.B
+ :-0
+SCSI/ATAPI transport error
+.TP
+.B
+ :-(
+Scratch detected
+.TP
+.B
+ ;-(
+Gave up trying to perform a correction
+.TP
+.B
+ 8-X
+Aborted read due to known, uncorrectable error
+.TP
+.B
+ :^D
+Finished extracting
+
+.SH PROGRESS BAR SYMBOLS
+.TP
+.B
+<space>
+No corrections needed
+.TP
+.B
+ -
+Jitter correction required
+.TP
+.B
+ +
+Unreported loss of streaming/other error in read
+.TP
+.B
+ !
+Errors found after stage 1 correction; the drive is making the
+same error through multiple re-reads, and cdparanoia is having trouble
+detecting them.
+.TP
+.B
+ e
+SCSI/ATAPI transport error (corrected)
+.TP
+.B
+ V
+Uncorrected error/skip
+
+.SH SPAN ARGUMENT
+
+The span argument specifies which track, tracks or subsections of
+tracks to read. This argument is required.
+.B NOTE:
+Unless the span is a simple number, it's generally a good idea to
+quote the span argument to protect it from the shell.
+.P
+The span argument may be a simple track number or an offset/span
+specification. The syntax of an offset/span takes the rough form:
+.P
+1[ww:xx:yy.zz]-2[aa:bb:cc.dd]
+.P
+Here, 1 and 2 are track numbers; the numbers in brackets provide a
+finer grained offset within a particular track. [aa:bb:cc.dd] is in
+hours/minutes/seconds/sectors format. Zero fields need not be
+specified: [::20], [:20], [20], [20.], etc, would be interpreted as
+twenty seconds, [10:] would be ten minutes, [.30] would be thirty
+sectors (75 sectors per second).
+.P
+When only a single offset is supplied, it is interpreted as a starting
+offset and ripping will continue to the end of the track. If a single
+offset is preceeded or followed by a hyphen, the implicit missing
+offset is taken to be the start or end of the disc, respectively. Thus:
+
+.TP
+.B 1:[20.35]
+Specifies ripping from track 1, second 20, sector 35 to the end of
+track 1.
+.TP
+.B 1:[20.35]-
+Specifies ripping from 1[20.35] to the end of the disc
+.TP
+.B \-2
+Specifies ripping from the beginning of the disc up to (and including) track 2
+.TP
+.B \-2:[30.35]
+Specifies ripping from the beginning of the disc up to 2:[30.35]
+.TP
+.B 2-4
+Specifies ripping from the beginning of track 2 to the end of track 4.
+.P
+Again, don't forget to protect square brackets and preceeding hyphens from
+the shell.
+
+.SH EXAMPLES
+
+A few examples, protected from the shell:
+.TP
+Query only with exhaustive search for a drive and full reporting of autosense:
+.P
+ cdparanoia -vsQ
+.TP
+Extract an entire disc, putting each track in a seperate file:
+.P
+ cdparanoia -B
+.TP
+Extract from track 1, time 0:30.12 to 1:10.00:
+.P
+ cdparanoia "1[:30.12]-1[1:10]"
+.TP
+Extract from the beginning of the disc up to track 3:
+.P
+ cdparanoia -- "-3"
+.TP
+The "--" above is to distinguish "-3" from an option flag.
+.SH OUTPUT
+
+The output file argument is optional; if it is not specified,
+cdparanoia will output samples to one of
+.BR cdda.wav ", " cdda.aifc ", or " cdda.raw
+depending on whether
+.BR \-w ", " \-a ", " \-r " or " \-R " is used (" \-w
+is the implicit default). The output file argument of
+.B \-
+specifies standard output; all data formats may be piped.
+
+.SH ACKNOWLEDGEMENTS
+Cdparanoia sprang from and once drew heavily from the interface of
+Heiko Eissfeldt's ([email protected]) 'cdda2wav'
+package. Cdparanoia would not have happened without it.
+.P
+Joerg Schilling has also contributed SCSI expertise through his
+generic SCSI transport library.
+.P
+.SH AUTHOR
+Monty <[email protected]>
+.P
+Cdparanoia's homepage may be found at:
+.P
+.ce
+http://www.xiph.org/paranoia/
diff -urN cdparanoia-III-alpha9.8/main.c cdparanoia-III-alpha9.8-cddb/main.c
--- cdparanoia-III-alpha9.8/main.c Mon Mar 26 05:44:50 2001
+++ cdparanoia-III-alpha9.8-cddb/main.c Tue Nov 19 17:45:14 2002
@@ -61,6 +61,7 @@
#include "report.h"
#include "version.h"
#include "header.h"
+#include "cddb.h"
extern int verbose;
extern int quiet;
@@ -223,8 +224,12 @@
report("");
}
-static void usage(FILE *f){
- fprintf( f,
+#define CDDBSERVER "freedb.freedb.org"
+#define CDDBPORT 888
+#define CDDBPORT_STR "888"
+#define CDDBOUTPUTFORMAT "%D[%A]-%C:%T"
+
+static char usage_str[] =
VERSION"\n"
"USAGE:\n"
@@ -277,6 +282,29 @@
" -Y --disable-extra-paranoia : only do cdda2wav-style overlap checking\n"
" -X --abort-on-skip : abort on imperfect reads/skips\n\n"
+"CDDB OPTIONS:\n"
+" -l --cddb-lookup : do cddb lookup when in batch mode\n"
+" default dont do cddb-lookup\n"
+" -b --cddb-server <name[:port]> : use name on port port for cddb server\n"
+" default " CDDBSERVER":"CDDBPORT_STR "\n"
+" -k --cddb-output-format <f> : use the format f for file names\n"
+" flags for format :\n"
+" %% : put a '%'\n"
+" %c : put the general cddb commentary\n"
+" %D : put the disc title\n"
+" %A : put the disc author\n"
+" %Y : put the year 4 digits\n"
+" %y : put the year 2 last digits\n"
+" %G : put the disc genre (cddb codes)\n"
+" %X : put the disc extented data\n"
+" %N : put the number of titles\n"
+" %T : put the title of the current track\n"
+" %x : put the extended title data of the\n"
+" current track\n"
+" %C : put the number of current track\n"
+" other char : put the char\n"
+" default : "CDDBOUTPUTFORMAT"\n\n"
+
"OUTPUT SMILIES:\n"
" :-) Normal operation, low/no jitter\n"
" :-| Normal operation, considerable jitter\n"
@@ -338,10 +366,17 @@
" B) extract up to and including track 3, putting each track in a seperate\n"
" file:\n"
" cdparanoia -B -- \"-3\"\n\n"
-" C) extract from track 1, time 0:30.12 to 1:10.00:\n"
+" C) extract every track, putting each track in a separate file whose name\n"
+" is <track-number>-<track-name>.cdda.wav, informations being\n"
+" fetch from mydb.freedb.org on port 333:\n"
+" cdparanoia -B -l -b mydb.freedb.org:333 -k \"%C-%T\"\n\n"
+" D) extract from track 1, time 0:30.12 to 1:10.00:\n"
" cdparanoia \"1[:30.12]-1[1:10]\"\n\n"
-"Submit bug reports to [email protected]\n\n");
+"Submit bug reports to [email protected]\n\n";
+
+static void usage(FILE *f){
+ fprintf( f, "%s", usage_str);
}
long callbegin;
@@ -585,7 +620,7 @@
memset(dispcache,' ',graph);
}
-const char *optstring = "escCn:o:O:d:g:S:prRwafvqVQhZz::YXWBi:Tt:";
+const char *optstring = "escCn:o:O:d:g:S:prRwafvqVQhZz::YXWBi:Tt:b:lk:";
struct option options [] = {
{"stderr-progress",no_argument,NULL,'e'},
@@ -618,6 +653,9 @@
{"disable-fragmentation",no_argument,NULL,'F'},
{"output-info",required_argument,NULL,'i'},
{"never-skip",optional_argument,NULL,'z'},
+ {"cddb-server",required_argument,NULL,'b'},
+ {"cddb-lookup",no_argument,NULL,'l'},
+ {"cddb-output-format",required_argument,NULL,'k'},
{NULL,0,NULL,0}
};
@@ -661,6 +699,11 @@
int output_endian=0; /* -1=host, 0=little, 1=big */
int query_only=0;
int batch=0,i;
+ char *cddb_server_name = CDDBSERVER;
+ unsigned short cddb_server_port = CDDBPORT;
+ int cddb_lookup = 0;
+ char *cddb_output_format = CDDBOUTPUTFORMAT;
+ struct cddb_db_entry *e = NULL;
/* full paranoia, but allow skipping */
int paranoia_mode=PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP;
@@ -790,6 +833,24 @@
case 'O':
sample_offset=atoi(optarg);
break;
+ case 'b':
+ cddb_server_name = copystring(optarg);
+ {
+ int i;
+ for(i=0; cddb_server_name[i] && cddb_server_name[i] != ':'; i++) ;
+ if(cddb_server_name[i] == ':')
+ {
+ cddb_server_name[i] = 0;
+ cddb_server_port = atoi(cddb_server_name + i + 1);
+ }
+ }
+ break;
+ case 'l':
+ cddb_lookup = 1;
+ break;
+ case 'k':
+ cddb_output_format = copystring(optarg);
+ break;
default:
usage(stderr);
exit(1);
@@ -806,6 +867,8 @@
}
}else
span=copystring(argv[optind]);
+
+ fprintf(stderr, "%d %s %u %s\n", cddb_lookup, cddb_server_name, cddb_server_port, cddb_output_format);
report(VERSION);
@@ -1027,6 +1090,34 @@
int16_t offset_buffer[1176];
int offset_buffer_used=0;
int offset_skip=sample_offset*4;
+ struct cddb *c;
+ struct cddb_disc *cd;
+ struct cddb_query *q;
+
+ if(batch) {
+ if(cddb_lookup)
+ c = cddb_connect(cddb_server_name, cddb_server_port);
+ else
+ c = NULL;
+ if(c)
+ {
+ cddb_handshake(c, "cdparanoia", "III-a9.8-cddb0.2");
+ cd = cddb_identify_disc(d->ioctl_fd);
+ if(cd)
+ {
+ q = cddb_query(c, cd);
+ if(q)
+ e = cddb_read(c, cd, q);
+ else
+ fprintf(stderr, "CDDB error while query : %s\n", cddb_errstr);
+ }
+ else
+ fprintf(stderr, "CDDB error while identify or handshake : %s\n", cddb_errstr);
+ }
+ else
+ if(cddb_lookup)
+ fprintf(stderr, "CDDB error while connect : %s\n", cddb_errstr);
+ }
p=paranoia_init(d);
paranoia_modeset(p,paranoia_mode);
@@ -1090,7 +1181,11 @@
strncat(path,argv[optind+1],pos>256?256:pos);
if(batch)
- snprintf(outfile_name,246,"%strack%02d.%s",path,batch_track,file);
+ {
+ if( !(e && (batch_track-1 >= 0) && (batch_track-1 < e->nbtitles) &&
+ ( cddb_snprintf(outfile_name, 246, cddb_output_format, e, batch_track-1, path, file) < 0) ) )
+ snprintf(outfile_name,246,"%strack%02d.%s",path,batch_track,file);
+ }
else
snprintf(outfile_name,246,"%s%s",path,file);
@@ -1124,7 +1219,11 @@
}else{
/* default */
if(batch)
- sprintf(outfile_name,"track%02d.",batch_track);
+ {
+ if(! (e && (batch_track-1 >= 0) && (batch_track-1 < e->nbtitles) &&
+ (cddb_snprintf(outfile_name, 246, cddb_output_format, e, batch_track-1, NULL, ".")>0)) )
+ snprintf(outfile_name,246,"track%02d",batch_track);
+ }
else
outfile_name[0]='\0';