diff options
Diffstat (limited to 'Src/external_dependencies/libdiscid-0.6.2/src/disc.c')
-rw-r--r-- | Src/external_dependencies/libdiscid-0.6.2/src/disc.c | 508 |
1 files changed, 508 insertions, 0 deletions
diff --git a/Src/external_dependencies/libdiscid-0.6.2/src/disc.c b/Src/external_dependencies/libdiscid-0.6.2/src/disc.c new file mode 100644 index 00000000..391b7cff --- /dev/null +++ b/Src/external_dependencies/libdiscid-0.6.2/src/disc.c @@ -0,0 +1,508 @@ +/* -------------------------------------------------------------------------- + + 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 + +--------------------------------------------------------------------------- */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include <string.h> +#include <assert.h> +#include <limits.h> + +#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 char *create_toc_string(mb_disc_private *d, char *sep); +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_toc_string(DiscId *d) { + mb_disc_private *disc = (mb_disc_private *) d; + assert( disc != NULL ); + assert( disc->success ); + + if ( ! disc->success ) + return NULL; + + if ( strlen(disc->toc_string) == 0 ) { + char *toc = create_toc_string(disc, " "); + if (toc) { + memcpy(disc->toc_string, toc, strlen(toc) + 1); + free(toc); + } + } + + return disc->toc_string; +} + +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) { + return discid_read_sparse(d, device, UINT_MAX); +} + +int discid_read_sparse(DiscId *d, const char *device, unsigned int features) { + 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)); + + /* pre-read the TOC to reduce "not-ready" problems + * See LIB-44 (issues with multi-session discs) + */ + if (!mb_disc_read_unportable(disc, device, DISCID_FEATURE_READ)) { + return 0; + } + memset(disc, 0, sizeof(mb_disc_private)); + + return disc->success = mb_disc_read_unportable(disc, device, features); +} + +int discid_put(DiscId *d, int first, int last, int *offsets) { + int i, disc_length; + mb_disc_private *disc = (mb_disc_private *) d; + assert(disc != NULL); + + /* Necessary, because the disc handle could have been used before. */ + memset(disc, 0, sizeof(mb_disc_private)); + + /* extensive checking of given parameters */ + if (first > last || first < 1 + || first > 99 || last < 1 || last > 99) { + + sprintf(disc->error_msg, "Illegal track limits"); + return 0; + } + if (offsets == NULL) { + sprintf(disc->error_msg, "No offsets given"); + return 0; + } + disc_length = offsets[0]; + if (disc_length > MAX_DISC_LENGTH) { + sprintf(disc->error_msg, "Disc too long"); + return 0; + } + for (i = 0; i <= last; i++) { + if (offsets[i] > disc_length) { + sprintf(disc->error_msg, "Invalid offset"); + return 0; + } + if (i > 1 && offsets[i-1] > offsets[i]) { + sprintf(disc->error_msg, "Invalid order"); + 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); + assert(disc->success); + + if (!disc->success) + return -1; + else + return disc->first_track_num; +} + + +int discid_get_last_track_num(DiscId *d) { + mb_disc_private *disc = (mb_disc_private *) d; + assert(disc != NULL); + assert(disc->success); + + if (!disc->success) + return -1; + else + return disc->last_track_num; +} + + +int discid_get_sectors(DiscId *d) { + mb_disc_private *disc = (mb_disc_private *) d; + assert(disc != NULL); + assert(disc->success); + + if (!disc->success) + return -1; + else + 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(disc->success); + assert(TRACK_NUM_IS_VALID(disc, i)); + + if (!disc->success || !TRACK_NUM_IS_VALID(disc, i)) + return -1; + else + 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(disc->success); + assert(TRACK_NUM_IS_VALID(disc, i)); + + if (!disc->success || !TRACK_NUM_IS_VALID(disc, i)) + return -1; + else 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); + assert(disc->success); + + if (!disc->success) + return NULL; + else + return disc->mcn; +} + +char* discid_get_track_isrc(DiscId *d, int i) { + mb_disc_private *disc = (mb_disc_private *) d; + assert(disc != NULL); + assert(disc->success); + assert(TRACK_NUM_IS_VALID(disc, i)); + + if (!disc->success || i == 0 || !TRACK_NUM_IS_VALID(disc, i)) + return NULL; + else + 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 + 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); + assert(d->success); + + 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); + assert(d->success); + + 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 string based on the TOC data found in the mb_disc_private + * object. The returned string is allocated, caller has to free() it. + * On failure, it returns NULL. + * + * Format is: + * [1st track num][sep][last track num][sep][length in sectors][sep][1st track offset][sep]... + */ +static char *create_toc_string(mb_disc_private *d, char *sep) { + char tmp[16]; + char *toc; + int i, size; + + assert( d != NULL ); + + /* number of tracks */ + size = 1 + d->last_track_num - d->first_track_num; + /* first&last track num and total length */ + size += 3; + /* number + separator */ + size *= (6 + strlen(sep)); + /* nul */ + size++; + + toc = calloc(size, sizeof(char)); + if (!toc) return NULL; + + sprintf(toc, "%d%s%d%s%d", + d->first_track_num, + sep, + d->last_track_num, + sep, + d->track_offsets[0]); + + for (i = d->first_track_num; i <= d->last_track_num; i++) { + sprintf(tmp, "%s%d", sep, d->track_offsets[i]); + strcat(toc, tmp); + } + + return toc; +} + +/* Append &toc=... to buf, calling create_toc_string() */ +static void cat_toc_param(mb_disc_private *d, char *buf) { + char *toc = create_toc_string(d, "+"); + if (toc) { + strcat(buf, "&toc="); + strcat(buf, toc); + free(toc); + } +} + +/* + * 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[16]; + + assert(d != NULL); + assert(d->success); + + 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); + + cat_toc_param(d, buf); +} + +/* + * 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[]) { + assert(d != NULL); + assert(d->success); + + strcpy(buf, MB_WEBSERVICE_URL); + + strcat(buf, "?type=xml&discid="); + strcat(buf, discid_get_id((DiscId *) d)); + + cat_toc_param(d, buf); +} + +/* EOF */ |