I ported the linux sources to my FreeBSD 3.0-RELEASE system.
Too bad I can't identify the CDs I tried so far, so I suspect
that there is a bug in the ID calculation. (see code below)
Could anyone with one of these CDs send me his/hers LBA values?
1.
Björk - Debut yields:
track 01: lba = 0
track 02: lba = -1656160256
track 03: lba = 1738473472
track 04: lba = 988938240
track 05: lba = -1221918464
track 06: lba = 1199374592
track 07: lba = -1430126336
track 08: lba = -300023296
track 09: lba = 1231421952
track 10: lba = -474217984
track 11: lba = -1961622784
track 12: lba = 962855680
http://www.freeamp.org/cgi-bin/cdi/hget.pl?id=28E7E4967299A723D21F8F1F6722D813
2. Björk - Post yields
track 01: lba = 536870912
track 02: lba = -1119617024
track 03: lba = -509476864
track 04: lba = 753664000
track 05: lba = 1093402880
track 06: lba = -1385103104
track 07: lba = -2070085376
track 08: lba = 956498432
track 09: lba = 509411840
track 10: lba = -2036071936
track 11: lba = 2009661952
http://www.freeamp.org/cgi-bin/cdi/hget.pl?id=AE14A9BE68987CD87FF0238C0D774495
3. The Verve - Urban Hymns yields
track 01: lba = 0
track 02: lba = 40435712
track 03: lba = -1699414016
track 04: lba = 959512832
track 05: lba = -1719009024
track 06: lba = -419757824
track 07: lba = 472515072
track 08: lba = -1131675136
track 09: lba = -1377762816
track 10: lba = -1456012544
track 11: lba = 1854931712
track 12: lba = 349438720
track 13: lba = 808125440
http://www.freeamp.org/cgi-bin/cdi/hget.pl?id=588FF815688CBB777B5E107CC25EE4D3
Regards,
Marc
-------------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//
// cdindex.cpp
//
// system headers
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
// CD control
#if defined(__FreeBSD__)
#include <sys/cdio.h>
#else // don't know Linux id
#include <linux/cdrom.h>
#endif
// project headers
#include "cdindex.h"
#include "md5.h"
// stupid macros
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
#if defined(__FreeBSD__)
#define DEFAULT_DEVICE "/dev/cd0c"
#else // don't know Linux id
#define DEFAULT_DEVICE "/dev/cdrom"
#endif
// some types
typedef unsigned char byte;
int lbas[128];
//
// calculate index
//
void CDIndex_Calculate(CDINDEX_CDINFO* pCDInfo, // Charles Simonyi's (Hungarian) notation is ugly
char DiscId[33])
{
MD5_CTX md5;
char HexTbl[] = "0123456789ABCDEF";
unsigned char digest[16];
// go!
MD5Init(&md5);
MD5Update(&md5,
(unsigned char*) pCDInfo,
sizeof(CDINDEX_CDINFO));
MD5Final(digest, &md5);
for (int i=0; i<16; i++) {
DiscId[i << 1] = HexTbl[digest[i] / 0x10];
DiscId[(i << 1) + 1] = HexTbl[digest[i] % 0x10];
}
DiscId[32] = '\0';
}
//
// OS specific CD inquiries
//
#if defined(__FreeBSD__)
int readtochdr(int fd,
int& first,
int& last)
{
struct ioc_toc_header th;
int ret = ioctl(fd,
CDIOREADTOCHEADER,
&th);
if (!ret) {
first = th.starting_track;
last = th.ending_track;
}
return ret;
}
int readtocentry(int fd,
int track,
int& lba)
{
struct ioc_read_toc_entry te;
te.starting_track = (u_char) track;
te.address_format = CD_LBA_FORMAT;
struct cd_toc_entry cte;
te.data = &cte;
te.data_len = sizeof(cd_toc_entry);
int ret = ioctl(fd,
CDIOREADTOCENTRYS,
&te);
if (!ret) {
assert(te.address_format == CD_LBA_FORMAT);
lba = te.data->addr.lba;
printf("track %02d: lba = %d\n",
(u_char) track,
lba);
}
return ret;
}
#else // don't know Linux id
/// SHAMELESSLY RIPPED FROM LINUX KERNEL
static inline void lba_to_msf(int lba,
byte* m,
byte* s,
byte* f)
{
lba += CD_BLOCK_OFFSET;
lba &= 0xffffff; /* negative lbas use only 24 bits */
*m = lba / (CD_SECS * CD_FRAMES);
lba %= (CD_SECS * CD_FRAMES);
*s = lba / CD_FRAMES;
*f = lba % CD_FRAMES;
}
/// END OF SHAMELESS RIP
int readtochdr(int fd,
int& first, // some sign of C++ :-)
int& last)
{
struct cdrom_tochdr tochdr;
int ret = ioctl(fd, CDROMREADTOCHDR, &tochdr);
if (!ret) {
first = tochdr.cdth_trk0;
last = tochdr.cdth_trk1;
}
return ret;
}
int readtocentry(int fd,
int track,
int& lba,
int& control,
int& adr)
{
struct cdrom_tocentry tocentry;
tocentry.cdte_track = track;
tocentry.cdte_format = CDROM_LBA;
int ret = ioctl(fd, CDROMREADTOCENTRY, &tocentry);
if (!ret) {
assert (tocentry.cdte_format == CDROM_LBA);
lba = tocentry.cdte_addr.lba;
control = tocentry.cdte_ctrl;
adr = tocentry.cdte_adr;
}
return ret;
}
#endif
void usage()
{
printf("usage: cdindex <options> [cdrom device]\n");
printf("\n");
printf("Options:\n");
printf(" -s Submit the given CD\n");
printf(" -g Get the information for this CD\n");
printf(" -l Print the URL used, but don't launch browser\n");
printf("\n");
printf("If no device is given, " DEFAULT_DEVICE " will be used.\n");
exit(0);
}
//
// start here
//
int main(int argc,
char* argv[])
{
#if defined(__FreeBSD__)
#else
unsigned char buf[CD_FRAMESIZE_RAW]; // who ordered this?
#endif
int ret;
int first;
int last;
int i;
int lba;
int control;
int adr;
int opt_s = 0;
int opt_g = 0;
int opt_l = 0;
byte m;
byte s;
byte f;
char* device = DEFAULT_DEVICE;
CDINDEX_CDINFO cdinfo;
char id[33];
char url[255];
// go!
if (argc == 1 || (argc > 1 && strcasecmp(argv[1], "--help") == 0))
usage();
// command-line argument processing loop
for (i=1; i<argc; i++) {
if (strcmp(argv[i], "-s") == 0) {
opt_s = 1;
continue;
}
if (strcmp(argv[i], "-g") == 0) {
opt_g = 1;
continue;
}
if (strcmp(argv[i], "-l") == 0) {
opt_l = 1;
continue;
}
// special case the standalone optional final argument (device)
if (i != argc - 1)
usage();
device = argv[i];
}
int fd = open(device, O_RDONLY);
if (fd < 0) {
printf("Cannot open '%s'\n", device);
exit(0);
}
memset(&cdinfo, 0, sizeof(CDINDEX_CDINFO));
if (readtochdr(fd, first, last)) {
printf("Cannot read table of contents.\n");
close(fd);
exit(0);
}
cdinfo.FrameOffset[0] = 0;
for (i=first; i<=last; i++) {
#if defined(__FreeBSD__)
readtocentry(fd, i, lba);
// what use is msf here?
#else
readtocentry(fd, i, lba, control, adr);
lba_to_msf(lba, &m, &s, &f);
#endif
cdinfo.FrameOffset[i] = lba + 150;
}
cdinfo.FirstTrack = first;
cdinfo.LastTrack = last;
CDIndex_Calculate(&cdinfo, id);
close(fd);
if (opt_s)
sprintf(url,
"http://www.freeamp.org/cgi-bin/cdi/submit.pl?"
"id=%s&tracks=%d",
id,
(last - first) + 1);
else
sprintf(url,
"http://www.freeamp.org/cgi-bin/cdi/hget.pl?"
"id=%s",
id);
if (opt_l) { // just print the url
printf("%s\n", url);
exit(0);
}
printf("Opening netscape to: '%s'\n"
"(Please open it by hand if the browser doesn't "
"start automatically)\n",
url);
#if defined(__FreeBSD__)
execlp("netscape",
"netscape", // arg[0] is name
url,
NULL);
#else
execlp("netscape",
url,
NULL);
#endif
perror("Could not launch netscape browser");
return 1;
}
-------------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//
// cdindex.h
//
#if !defined(___CDINDEX___H___)
#define ___CDINDEX___H___
#pragma pack(1) // FreeBSD: investigate
typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long dword;
typedef signed char sbyte;
typedef signed short sword;
typedef signed long sdword;
struct CDINDEX_CDINFO {
byte FirstTrack; // The first track on CD : normally 1
byte LastTrack; // The last track on CD: max number 99
dword FrameOffset[100]; // Track 2 is TrackFrameOffset[2] etc.
}; // Leadout Track will be TrackFrameOffset[0]
void CDIndex_Calculate(CDINDEX_CDINFO* pCDInfo,
char DiscId[17]);
// true = ok
// false = error
#if !defined(CD_BLOCK_OFFSET)
#define CD_BLOCK_OFFSET CD_MSF_OFFSET
#endif
#endif
// end of cdindex.h
-------------------------------------------------------------------------------
Bye!