/* -------------------------------------------------------------------------- MusicBrainz -- The Internet music metadatabase Copyright (C) 2006 Matthias Friedrich Copyright (C) 2000 Robert Kaye Copyright (C) 1999 Marc E E van Woerkom This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA $Id$ --------------------------------------------------------------------------- */ #include #include #include "sha1.h" #include "base64.h" #include "discid/discid.h" #include "discid/discid_private.h" #define TRACK_NUM_IS_VALID(disc, i) \ ( i >= disc->first_track_num && i <= disc->last_track_num ) static void create_disc_id(mb_disc_private *d, char buf[]); static void create_freedb_disc_id(mb_disc_private *d, char buf[]); static void create_submission_url(mb_disc_private *d, char buf[]); static void create_webservice_url(mb_disc_private *d, char buf[]); /**************************************************************************** * * Implementation of the public interface. * ****************************************************************************/ DiscId *discid_new() { /* initializes everything to zero */ return calloc(1, sizeof(mb_disc_private)); } void discid_free(DiscId *d) { free(d); } char *discid_get_error_msg(DiscId *d) { mb_disc_private *disc = (mb_disc_private *) d; assert( disc != NULL ); return disc->error_msg; } char *discid_get_id(DiscId *d) { mb_disc_private *disc = (mb_disc_private *) d; assert( disc != NULL ); assert( disc->success ); if ( ! disc->success ) return NULL; if ( strlen(disc->id) == 0 ) create_disc_id(disc, disc->id); return disc->id; } char *discid_get_freedb_id(DiscId *d) { mb_disc_private *disc = (mb_disc_private *) d; assert( disc != NULL ); assert( disc->success ); if ( ! disc->success ) return NULL; if ( strlen(disc->freedb_id) == 0 ) create_freedb_disc_id(disc, disc->freedb_id); return disc->freedb_id; } char *discid_get_submission_url(DiscId *d) { mb_disc_private *disc = (mb_disc_private *) d; assert( disc != NULL ); assert( disc->success ); if ( ! disc->success ) return NULL; if ( strlen(disc->submission_url) == 0 ) create_submission_url(disc, disc->submission_url); return disc->submission_url; } char *discid_get_webservice_url(DiscId *d) { mb_disc_private *disc = (mb_disc_private *) d; assert( disc != NULL ); assert( disc->success ); if ( ! disc->success ) return NULL; if ( strlen(disc->webservice_url) == 0 ) create_webservice_url(disc, disc->webservice_url); return disc->webservice_url; } int discid_read(DiscId *d, const char *device) { mb_disc_private *disc = (mb_disc_private *) d; assert( disc != NULL ); if ( device == NULL ) device = discid_get_default_device(); assert( device != NULL ); /* Necessary, because the disc handle could have been used before. */ memset(disc, 0, sizeof(mb_disc_private)); return disc->success = mb_disc_read_unportable(disc, device); } int discid_put(DiscId *d, int first, int last, int *offsets) { mb_disc_private *disc = (mb_disc_private *) d; assert( disc != NULL ); memset(disc, 0, sizeof(mb_disc_private)); if ( first > last || first < 1 || first > 99 || last < 1 || last > 99 || offsets==NULL ) { sprintf(disc->error_msg, "Illegal parameters"); return 0; } disc->first_track_num = first; disc->last_track_num = last; memcpy(disc->track_offsets, offsets, sizeof(int) * (last+1)); disc->success = 1; return 1; } char *discid_get_default_device(void) { return mb_disc_get_default_device_unportable(); } int discid_get_first_track_num(DiscId *d) { mb_disc_private *disc = (mb_disc_private *) d; assert( disc != NULL ); return disc->first_track_num; } int discid_get_last_track_num(DiscId *d) { mb_disc_private *disc = (mb_disc_private *) d; assert( disc != NULL ); return disc->last_track_num; } int discid_get_sectors(DiscId *d) { mb_disc_private *disc = (mb_disc_private *) d; assert( disc != NULL ); return disc->track_offsets[0]; } int discid_get_track_offset(DiscId *d, int i) { mb_disc_private *disc = (mb_disc_private *) d; assert( disc != NULL ); assert( TRACK_NUM_IS_VALID(disc, i) ); if ( ! TRACK_NUM_IS_VALID(disc, i) ) return 0; return disc->track_offsets[i]; } int discid_get_track_length(DiscId *d, int i) { mb_disc_private *disc = (mb_disc_private *) d; assert( disc != NULL ); assert( TRACK_NUM_IS_VALID(disc, i) ); if ( ! TRACK_NUM_IS_VALID(disc, i) ) return 0; if ( i < disc->last_track_num ) return disc->track_offsets[i+1] - disc->track_offsets[i]; else return disc->track_offsets[0] - disc->track_offsets[i]; } char *discid_get_mcn(DiscId *d) { mb_disc_private *disc = (mb_disc_private *) d; assert( disc != NULL ); return disc->mcn; } char* discid_get_track_isrc(DiscId *d, int i) { mb_disc_private *disc = (mb_disc_private *) d; assert( disc != NULL ); assert( TRACK_NUM_IS_VALID(disc, i) ); if ( ! TRACK_NUM_IS_VALID(disc, i) || i == 0) return NULL; return disc->isrc[i]; } int discid_has_feature(enum discid_feature feature) { return mb_disc_has_feature_unportable(feature); } void discid_get_feature_list(char *features[DISCID_FEATURE_LENGTH]) { int i; /* for the code, the parameter is actually only a pointer */ memset(features, 0, sizeof(char *) * DISCID_FEATURE_LENGTH); i = 0; if (discid_has_feature(DISCID_FEATURE_READ)) { features[i++] = DISCID_FEATURE_STR_READ; } if (discid_has_feature(DISCID_FEATURE_MCN)) { features[i++] = DISCID_FEATURE_STR_MCN; } if (discid_has_feature(DISCID_FEATURE_ISRC)) { features[i++] = DISCID_FEATURE_STR_ISRC; } return; } char *discid_get_version_string(void) { #ifdef HAVE_CONFIG_H #include return PACKAGE_STRING; #else return ""; #endif } /**************************************************************************** * * Private utilities, not exported. * ****************************************************************************/ /* * Create a DiscID based on the TOC data found in the DiscId object. * The DiscID is placed in the provided string buffer. */ static void create_disc_id(mb_disc_private *d, char buf[]) { SHA_INFO sha; unsigned char digest[20], *base64; unsigned long size; char tmp[17]; /* for 8 hex digits (16 to avoid trouble) */ int i; assert( d != NULL ); sha_init(&sha); sprintf(tmp, "%02X", d->first_track_num); sha_update(&sha, (unsigned char *) tmp, strlen(tmp)); sprintf(tmp, "%02X", d->last_track_num); sha_update(&sha, (unsigned char *) tmp, strlen(tmp)); for (i = 0; i < 100; i++) { sprintf(tmp, "%08X", d->track_offsets[i]); sha_update(&sha, (unsigned char *) tmp, strlen(tmp)); } sha_final(digest, &sha); base64 = rfc822_binary(digest, sizeof(digest), &size); memcpy(buf, base64, size); buf[size] = '\0'; free(base64); } /* * Create a FreeDB DiscID based on the TOC data found in the DiscId object. * The DiscID is placed in the provided string buffer. */ static void create_freedb_disc_id(mb_disc_private *d, char buf[]) { int i, n, m, t; assert( d != NULL ); n = 0; for (i = 0; i < d->last_track_num; i++) { m = d->track_offsets[i + 1] / 75; while (m > 0) { n += m % 10; m /= 10; } } t = d->track_offsets[0] / 75 - d->track_offsets[1] / 75; sprintf(buf, "%08x", ((n % 0xff) << 24 | t << 8 | d->last_track_num)); } /* * Create a submission URL based on the TOC data found in the mb_disc_private * object. The URL is placed in the provided string buffer. */ static void create_submission_url(mb_disc_private *d, char buf[]) { char tmp[1024]; int i; assert( d != NULL ); strcpy(buf, MB_SUBMISSION_URL); strcat(buf, "?id="); strcat(buf, discid_get_id((DiscId *) d)); sprintf(tmp, "&tracks=%d", d->last_track_num); strcat(buf, tmp); sprintf(tmp, "&toc=%d+%d+%d", d->first_track_num, d->last_track_num, d->track_offsets[0]); strcat(buf, tmp); for (i = d->first_track_num; i <= d->last_track_num; i++) { sprintf(tmp, "+%d", d->track_offsets[i]); strcat(buf, tmp); } } /* * Create a web service URL based on the TOC data found in the mb_disc_private * object. The URL is placed in the provided string buffer. */ static void create_webservice_url(mb_disc_private *d, char buf[]) { char tmp[1024]; int i; assert( d != NULL ); strcpy(buf, MB_WEBSERVICE_URL); strcat(buf, "?type=xml&discid="); strcat(buf, discid_get_id((DiscId *) d)); sprintf(tmp, "&toc=%d+%d+%d", d->first_track_num, d->last_track_num, d->track_offsets[0]); strcat(buf, tmp); for (i = d->first_track_num; i <= d->last_track_num; i++) { sprintf(tmp, "+%d", d->track_offsets[i]); strcat(buf, tmp); } } /* EOF */