aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/libdiscid-0.6.2/src
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/external_dependencies/libdiscid-0.6.2/src
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/external_dependencies/libdiscid-0.6.2/src')
-rw-r--r--Src/external_dependencies/libdiscid-0.6.2/src/base64.c110
-rw-r--r--Src/external_dependencies/libdiscid-0.6.2/src/base64.h74
-rw-r--r--Src/external_dependencies/libdiscid-0.6.2/src/disc.c508
-rw-r--r--Src/external_dependencies/libdiscid-0.6.2/src/disc_bsd.c194
-rw-r--r--Src/external_dependencies/libdiscid-0.6.2/src/disc_darwin.c242
-rw-r--r--Src/external_dependencies/libdiscid-0.6.2/src/disc_generic.c43
-rw-r--r--Src/external_dependencies/libdiscid-0.6.2/src/disc_linux.c275
-rw-r--r--Src/external_dependencies/libdiscid-0.6.2/src/disc_solaris.c108
-rw-r--r--Src/external_dependencies/libdiscid-0.6.2/src/disc_win32.c247
-rw-r--r--Src/external_dependencies/libdiscid-0.6.2/src/ntddcdrm.h320
-rw-r--r--Src/external_dependencies/libdiscid-0.6.2/src/sha1.c329
-rw-r--r--Src/external_dependencies/libdiscid-0.6.2/src/sha1.h63
-rw-r--r--Src/external_dependencies/libdiscid-0.6.2/src/toc.c116
-rw-r--r--Src/external_dependencies/libdiscid-0.6.2/src/unix.c151
-rw-r--r--Src/external_dependencies/libdiscid-0.6.2/src/unix.h103
15 files changed, 2883 insertions, 0 deletions
diff --git a/Src/external_dependencies/libdiscid-0.6.2/src/base64.c b/Src/external_dependencies/libdiscid-0.6.2/src/base64.c
new file mode 100644
index 00000000..99a13ae6
--- /dev/null
+++ b/Src/external_dependencies/libdiscid-0.6.2/src/base64.c
@@ -0,0 +1,110 @@
+/* --------------------------------------------------------------------------
+
+ MusicBrainz -- The Internet music metadatabase
+
+ Copyright (C) 2000 Robert Kaye
+
+ 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$
+
+----------------------------------------------------------------------------*/
+/*
+ * Program: RFC-822 routines (originally from SMTP)
+ *
+ * Author: Mark Crispin
+ * Networks and Distributed Computing
+ * Computing & Communications
+ * University of Washington
+ * Administration Building, AG-44
+ * Seattle, WA 98195
+ * Internet: MRC@CAC.Washington.EDU
+ *
+ * Date: 27 July 1988
+ * Last Edited: 10 September 1998
+ *
+ * Sponsorship: The original version of this work was developed in the
+ * Symbolic Systems Resources Group of the Knowledge Systems
+ * Laboratory at Stanford University in 1987-88, and was funded
+ * by the Biomedical Research Technology Program of the National
+ * Institutes of Health under grant number RR-00785.
+ *
+ * Original version Copyright 1988 by The Leland Stanford Junior University
+ * Copyright 1998 by the University of Washington
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notices appear in all copies and that both the
+ * above copyright notices and this permission notice appear in supporting
+ * documentation, and that the name of the University of Washington or The
+ * Leland Stanford Junior University not be used in advertising or publicity
+ * pertaining to distribution of the software without specific, written prior
+ * permission. This software is made available "as is", and
+ * THE UNIVERSITY OF WASHINGTON AND THE LELAND STANFORD JUNIOR UNIVERSITY
+ * DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE UNIVERSITY OF
+ * WASHINGTON OR THE LELAND STANFORD JUNIOR UNIVERSITY BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+#include "base64.h"
+
+/* NOTE: This is not true RFC822 anymore. The use of the characters
+ '/', '+', and '=' is no bueno when the ID will be used as part of a URL.
+ '_', '.', and '-' have been used instead
+*/
+
+/* Convert binary contents to BASE64
+ * Accepts: source
+ * length of source
+ * pointer to return destination length
+ * Returns: destination as BASE64
+ */
+
+unsigned char *rfc822_binary (void *src,unsigned long srcl,unsigned long *len)
+{
+ unsigned char *ret,*d;
+ unsigned char *s = (unsigned char *) src;
+ char *v = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._";
+ unsigned long i = ((srcl + 2) / 3) * 4;
+ *len = i += 2 * ((i / 60) + 1);
+ d = ret = (unsigned char *) malloc ((size_t) ++i);
+ for (i = 0; srcl; s += 3) { /* process tuplets */
+ *d++ = v[s[0] >> 2]; /* byte 1: high 6 bits (1) */
+ /* byte 2: low 2 bits (1), high 4 bits (2) */
+ *d++ = v[((s[0] << 4) + (--srcl ? (s[1] >> 4) : 0)) & 0x3f];
+ /* byte 3: low 4 bits (2), high 2 bits (3) */
+ *d++ = srcl ? v[((s[1] << 2) + (--srcl ? (s[2] >> 6) : 0)) & 0x3f] : '-';
+ /* byte 4: low 6 bits (3) */
+ *d++ = srcl ? v[s[2] & 0x3f] : '-';
+ if (srcl) srcl--; /* count third character if processed */
+ if ((++i) == 15) { /* output 60 characters? */
+ i = 0; /* restart line break count, insert CRLF */
+ *d++ = '\015'; *d++ = '\012';
+ }
+ }
+ *d = '\0'; /* tie off string */
+
+ return ret; /* return the resulting string */
+}
diff --git a/Src/external_dependencies/libdiscid-0.6.2/src/base64.h b/Src/external_dependencies/libdiscid-0.6.2/src/base64.h
new file mode 100644
index 00000000..d22e43e1
--- /dev/null
+++ b/Src/external_dependencies/libdiscid-0.6.2/src/base64.h
@@ -0,0 +1,74 @@
+/* --------------------------------------------------------------------------
+
+ MusicBrainz -- The Internet music metadatabase
+
+ Copyright (C) 2000 Robert Kaye
+
+ 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$
+
+----------------------------------------------------------------------------*/
+/*
+ * Program: RFC-822 routines (originally from SMTP)
+ *
+ * Author: Mark Crispin
+ * Networks and Distributed Computing
+ * Computing & Communications
+ * University of Washington
+ * Administration Building, AG-44
+ * Seattle, WA 98195
+ * Internet: MRC@CAC.Washington.EDU
+ *
+ * Date: 27 July 1988
+ * Last Edited: 10 September 1998
+ *
+ * Sponsorship: The original version of this work was developed in the
+ * Symbolic Systems Resources Group of the Knowledge Systems
+ * Laboratory at Stanford University in 1987-88, and was funded
+ * by the Biomedical Research Technology Program of the National
+ * Institutes of Health under grant number RR-00785.
+ *
+ * Original version Copyright 1988 by The Leland Stanford Junior University
+ * Copyright 1998 by the University of Washington
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notices appear in all copies and that both the
+ * above copyright notices and this permission notice appear in supporting
+ * documentation, and that the name of the University of Washington or The
+ * Leland Stanford Junior University not be used in advertising or publicity
+ * pertaining to distribution of the software without specific, written prior
+ * permission. This software is made available "as is", and
+ * THE UNIVERSITY OF WASHINGTON AND THE LELAND STANFORD JUNIOR UNIVERSITY
+ * DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE UNIVERSITY OF
+ * WASHINGTON OR THE LELAND STANFORD JUNIOR UNIVERSITY BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef BASE64_H
+#define BASE64_H
+
+#include "discid/discid.h" /* for LIBDISCID_INTERNAL */
+
+LIBDISCID_INTERNAL unsigned char *rfc822_binary (void *src,unsigned long srcl,unsigned long *len);
+
+#endif
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 */
diff --git a/Src/external_dependencies/libdiscid-0.6.2/src/disc_bsd.c b/Src/external_dependencies/libdiscid-0.6.2/src/disc_bsd.c
new file mode 100644
index 00000000..cc749767
--- /dev/null
+++ b/Src/external_dependencies/libdiscid-0.6.2/src/disc_bsd.c
@@ -0,0 +1,194 @@
+/* --------------------------------------------------------------------------
+
+ MusicBrainz -- The Internet music metadatabase
+
+ Copyright (C) 2008 Patrick Hurrelmann
+ 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
+
+--------------------------------------------------------------------------- */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/cdio.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#if defined(__FreeBSD__)
+#include <netinet/in.h> /* for ntohl() */
+#else
+#include <util.h> /* for getrawpartition() */
+#endif
+
+#include "discid/discid_private.h"
+#include "unix.h"
+
+#define MAX_DEV_LEN 15
+
+static int get_device(int n, char* device_name, size_t device_name_length) {
+#if !defined(__FreeBSD__) /* /dev/rcdNX, where X is the letter for the raw partition */
+ snprintf(device_name, device_name_length, "/dev/rcd%d%c", n - 1, 'a' + getrawpartition());
+#else /* on FreeBSD it's just /dev/cdN */
+ snprintf(device_name, device_name_length, "/dev/cd%d", n - 1);
+#endif
+ return mb_disc_unix_exists(device_name);
+}
+
+int mb_disc_unix_read_toc_header(int fd, mb_disc_toc *toc) {
+ struct ioc_toc_header th;
+ struct cd_toc_entry te[100];
+ struct ioc_read_toc_entry rte;
+ int i;
+
+ memset(&th, 0, sizeof th);
+ if (ioctl(fd, CDIOREADTOCHEADER, &th) < 0)
+ return 0; /* error */
+
+ toc->first_track_num = th.starting_track;
+ toc->last_track_num = th.ending_track;
+
+ if (toc->last_track_num == 0)
+ return 1; /* no entries to read */
+
+ /* Read all the TOC entries in one icotl() call */
+
+ memset(&te, 0, sizeof te);
+ memset(&rte, 0, sizeof rte);
+ rte.address_format = CD_LBA_FORMAT;
+ rte.data = &te[0];
+ rte.data_len = sizeof te;
+ rte.starting_track = toc->first_track_num;
+
+ if (ioctl(fd, CDIOREADTOCENTRYS, &rte) < 0)
+ return 0; /* error */
+
+ for (i = toc->first_track_num; i <= toc->last_track_num; ++i) {
+ assert(te[i - toc->first_track_num].track == i);
+#if defined(__FreeBSD__) /* LBA address is in network byte order */
+ toc->tracks[i].address = ntohl(te[i - toc->first_track_num].addr.lba);
+#else
+ toc->tracks[i].address = te[i - toc->first_track_num].addr.lba;
+#endif
+ toc->tracks[i].control = te[i - toc->first_track_num].control;
+ }
+ /* leadout - track number 170 (0xAA) */
+ assert(te[i - toc->first_track_num].track == 0xAA);
+#if defined(__FreeBSD__) /* LBA address is in network byte order */
+ toc->tracks[0].address = ntohl(te[i - toc->first_track_num].addr.lba);
+#else
+ toc->tracks[0].address = te[i - toc->first_track_num].addr.lba;
+#endif
+ toc->tracks[0].control = te[i - toc->first_track_num].control;
+
+ return 1;
+}
+
+int mb_disc_unix_read_toc_entry(int fd, int track_num, mb_disc_toc_track *track) {
+ /* All TOC entries were already read by mb_disc_unix_read_toc_header() */
+ return 1;
+}
+
+void mb_disc_unix_read_mcn(int fd, mb_disc_private *disc) {
+ struct cd_sub_channel_info sci;
+ struct ioc_read_subchannel rsc;
+
+ memset(&sci, 0, sizeof sci);
+ memset(&rsc, 0, sizeof rsc);
+ rsc.address_format = CD_LBA_FORMAT; /* not technically relevant */
+ rsc.data_format = CD_MEDIA_CATALOG;
+ rsc.data_len = sizeof sci;
+ rsc.data = &sci;
+
+ if ( ioctl(fd, CDIOCREADSUBCHANNEL, &rsc) < 0 )
+ perror ("Warning: Unable to read the disc's media catalog number");
+ else {
+ if (sci.what.media_catalog.mc_valid)
+ strncpy( disc->mcn,
+ (const char *) sci.what.media_catalog.mc_number,
+ MCN_STR_LENGTH );
+ else
+ memset( disc->mcn, 0, MCN_STR_LENGTH );
+ }
+}
+
+void mb_disc_unix_read_isrc(int fd, mb_disc_private *disc, int track_num) {
+ struct cd_sub_channel_info sci;
+ struct ioc_read_subchannel rsc;
+
+ memset(&sci, 0, sizeof sci);
+ memset(&rsc, 0, sizeof rsc);
+ rsc.address_format = CD_LBA_FORMAT; /* not technically relevant */
+ rsc.data_format = CD_TRACK_INFO;
+ rsc.track = track_num;
+ rsc.data_len = sizeof sci;
+ rsc.data = &sci;
+
+ if ( ioctl(fd, CDIOCREADSUBCHANNEL, &rsc) < 0 )
+ perror ("Warning: Unable to read track info (ISRC)");
+ else {
+ if (sci.what.track_info.ti_valid)
+ strncpy( disc->isrc[track_num],
+ (const char *) sci.what.track_info.ti_number,
+ ISRC_STR_LENGTH );
+ else
+ memset( disc->isrc[track_num], 0, ISRC_STR_LENGTH );
+ }
+}
+
+int mb_disc_has_feature_unportable(enum discid_feature feature) {
+ switch(feature) {
+ case DISCID_FEATURE_READ:
+ case DISCID_FEATURE_MCN:
+ case DISCID_FEATURE_ISRC:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int mb_disc_read_unportable(mb_disc_private *disc, const char *device,
+ unsigned int features) {
+ char device_name[MAX_DEV_LEN] = "";
+ int device_number;
+
+ device_number = (int) strtol(device, NULL, 10);
+
+ if (device_number > 0) {
+ if(!get_device(device_number, device_name, MAX_DEV_LEN)) {
+ snprintf(disc->error_msg, MB_ERROR_MSG_LENGTH,
+ "cannot find cd device with the number '%d'",
+ device_number);
+ return 0; /* error */
+ }
+ device = device_name;
+ }
+
+ return mb_disc_unix_read(disc, device, features);
+}
+
+char *mb_disc_get_default_device_unportable(void) {
+ static char result[MAX_DEV_LEN + 1];
+ /* No error check here, so we always return the appropriate device for cd0 */
+ get_device(1, result, sizeof result);
+ return result;
+}
+
+/* EOF */
diff --git a/Src/external_dependencies/libdiscid-0.6.2/src/disc_darwin.c b/Src/external_dependencies/libdiscid-0.6.2/src/disc_darwin.c
new file mode 100644
index 00000000..c0cc553a
--- /dev/null
+++ b/Src/external_dependencies/libdiscid-0.6.2/src/disc_darwin.c
@@ -0,0 +1,242 @@
+/* --------------------------------------------------------------------------
+
+ MusicBrainz -- The Internet music metadatabase
+
+ Copyright (C) 2013 Johannes Dewender
+ Copyright (C) 2006 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
+
+----------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <paths.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOBSD.h>
+#include <IOKit/storage/IOCDBlockStorageDevice.h>
+#include <IOKit/storage/IOCDMediaBSDClient.h>
+
+#include "discid/discid.h"
+#include "discid/discid_private.h"
+#include "unix.h"
+
+#define MB_DEFAULT_DEVICE "1" /* first disc drive (empty or not) */
+#define TOC_BUFFER_LEN 2048
+
+
+static int find_cd_block_devices(io_iterator_t *device_iterator)
+{
+ mach_port_t master_port;
+ CFMutableDictionaryRef matching_dictionary;
+
+ if (IOMasterPort(MACH_PORT_NULL, &master_port) != KERN_SUCCESS)
+ return 0;
+
+ matching_dictionary = IOServiceMatching(kIOCDBlockStorageDeviceClass);
+
+ if (IOServiceGetMatchingServices(master_port, matching_dictionary,
+ device_iterator) != KERN_SUCCESS)
+ return 0;
+ else
+ return 1;
+}
+
+static int get_device_from_entry(io_registry_entry_t entry,
+ char *device_path, int max_len)
+{
+ int return_value = 0;
+ size_t dev_path_len;;
+ CFStringRef cf_device_name;;
+ *device_path = '\0';
+
+ cf_device_name = IORegistryEntrySearchCFProperty(entry,
+ kIOServicePlane, CFSTR(kIOBSDNameKey),
+ kCFAllocatorDefault, kIORegistryIterateRecursively);
+
+ if (cf_device_name) {
+ strcpy(device_path, _PATH_DEV);
+ /* Add "r" before the device name to use the raw disk node
+ * without the buffering cache. */
+ strcat(device_path, "r");
+ dev_path_len = strlen(device_path);
+ if (CFStringGetCString(cf_device_name,
+ device_path + dev_path_len,
+ max_len - dev_path_len - 1,
+ kCFStringEncodingASCII))
+ return_value = 1;
+
+ CFRelease(cf_device_name);
+ }
+ return return_value;
+}
+
+static int get_device_from_number(int device_number,
+ char * buffer, int buffer_len) {
+ int return_value = 0;
+ int index = 0;
+ io_iterator_t device_iterator;
+ io_object_t device_object = IO_OBJECT_NULL;
+
+ if (!find_cd_block_devices(&device_iterator))
+ return 0;
+
+ while (index < device_number
+ && (device_object = IOIteratorNext(device_iterator)))
+ index++;
+
+ if (index != device_number) {
+ return_value = 0;
+ } else {
+ return_value = get_device_from_entry(device_object,
+ buffer, buffer_len);
+ }
+
+ IOObjectRelease(device_object);
+ IOObjectRelease(device_iterator);
+
+ return return_value;
+}
+
+void mb_disc_unix_read_mcn(int fd, mb_disc_private *disc)
+{
+ dk_cd_read_mcn_t cd_read_mcn;
+ bzero(&cd_read_mcn, sizeof(cd_read_mcn));
+
+ if(ioctl(fd, DKIOCCDREADMCN, &cd_read_mcn) == -1) {
+ fprintf(stderr, "Warning: Unable to read the disc's media catalog number.\n");
+ } else {
+ strncpy( disc->mcn, cd_read_mcn.mcn, MCN_STR_LENGTH );
+ }
+}
+
+void mb_disc_unix_read_isrc(int fd, mb_disc_private *disc, int track)
+{
+ dk_cd_read_isrc_t cd_read_isrc;
+ bzero(&cd_read_isrc, sizeof(cd_read_isrc));
+ cd_read_isrc.track = track;
+
+ if(ioctl(fd, DKIOCCDREADISRC, &cd_read_isrc) == -1) {
+ fprintf(stderr, "Warning: Unable to read the international standard recording code (ISRC) for track %i\n", track);
+ return;
+ } else {
+ strncpy( disc->isrc[track], cd_read_isrc.isrc, ISRC_STR_LENGTH );
+ }
+}
+
+int mb_disc_has_feature_unportable(enum discid_feature feature) {
+ switch(feature) {
+ case DISCID_FEATURE_READ:
+ case DISCID_FEATURE_MCN:
+ case DISCID_FEATURE_ISRC:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+char *mb_disc_get_default_device_unportable(void)
+{
+ return MB_DEFAULT_DEVICE;
+}
+
+int mb_disc_unix_read_toc_header(int fd, mb_disc_toc *mb_toc) {
+ dk_cd_read_toc_t toc;
+ CDTOC *cdToc;
+ mb_disc_toc_track *track;
+ int i, numDesc;
+ int track_num, min_track, max_track;
+
+ memset(&toc, 0, sizeof(toc));
+ toc.format = kCDTOCFormatTOC;
+ toc.formatAsTime = 0;
+ toc.buffer = (char *)malloc(TOC_BUFFER_LEN);
+ toc.bufferLength = TOC_BUFFER_LEN;
+ if (ioctl(fd, DKIOCCDREADTOC, &toc) < 0) {
+ return 0;
+ }
+ if (toc.bufferLength < sizeof(CDTOC)) {
+ return 0;
+ }
+
+ cdToc = (CDTOC *)toc.buffer;
+ numDesc = CDTOCGetDescriptorCount(cdToc);
+ min_track = -1;
+ max_track = -1;
+ for(i = 0; i < numDesc; i++) {
+ CDTOCDescriptor *desc = &cdToc->descriptors[i];
+ track = NULL;
+
+ /* A2 is the code for the lead-out position in the lead-in */
+ if (desc->point == 0xA2 && desc->adr == 1) {
+ track = &mb_toc->tracks[0];
+ }
+
+ /* actual track data, (adr 2-3 are for MCN and ISRC data) */
+ if (desc->point <= 99 && desc->adr == 1) {
+ track_num = desc->point;
+ track = &mb_toc->tracks[track_num];
+ if (min_track < 0 || min_track > track_num) {
+ min_track = track_num;
+ }
+ if (max_track < track_num) {
+ max_track = track_num;
+ }
+ }
+
+ if (track) {
+ track->address = CDConvertMSFToLBA(desc->p);
+ track->control = desc->control;
+ }
+ }
+
+ mb_toc->first_track_num = min_track;
+ mb_toc->last_track_num = max_track;
+
+ free(toc.buffer);
+
+ return 1;
+}
+
+int mb_disc_unix_read_toc_entry(int fd, int track_num, mb_disc_toc_track *toc) {
+ /* On Darwin the tracks are already filled along with the header */
+ return 1;
+}
+
+int mb_disc_read_unportable(mb_disc_private *disc, const char *device,
+ unsigned int features) {
+ int device_number;
+ char device_name[MAXPATHLEN] = "\0";
+
+ device_number = (int) strtol(device, NULL, 10);
+ if (device_number > 0) {
+ if (!get_device_from_number(device_number,
+ device_name, MAXPATHLEN)) {
+ snprintf(disc->error_msg, MB_ERROR_MSG_LENGTH,
+ "no disc in drive number: %d", device_number);
+ return 0;
+ } else {
+ return mb_disc_unix_read(disc, device_name, features);
+ }
+ } else {
+ return mb_disc_unix_read(disc, device, features);
+ }
+}
diff --git a/Src/external_dependencies/libdiscid-0.6.2/src/disc_generic.c b/Src/external_dependencies/libdiscid-0.6.2/src/disc_generic.c
new file mode 100644
index 00000000..58c31673
--- /dev/null
+++ b/Src/external_dependencies/libdiscid-0.6.2/src/disc_generic.c
@@ -0,0 +1,43 @@
+/* --------------------------------------------------------------------------
+
+ MusicBrainz -- The Internet music metadatabase
+
+ Copyright (C) 2013 Johannes Dewender
+
+ 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
+
+--------------------------------------------------------------------------- */
+#include <stdio.h>
+
+#include "discid/discid.h"
+#include "discid/discid_private.h"
+
+
+char *mb_disc_get_default_device_unportable(void) {
+ return "/dev/null";
+}
+
+
+int mb_disc_has_feature_unportable(enum discid_feature feature) {
+ return 0;
+}
+
+int mb_disc_read_unportable(mb_disc_private *disc, const char *device, unsigned int features) {
+ snprintf(disc->error_msg, MB_ERROR_MSG_LENGTH,
+ "disc reading not implemented on this platform");
+ return 0;
+}
+
+/* EOF */
diff --git a/Src/external_dependencies/libdiscid-0.6.2/src/disc_linux.c b/Src/external_dependencies/libdiscid-0.6.2/src/disc_linux.c
new file mode 100644
index 00000000..2749bc07
--- /dev/null
+++ b/Src/external_dependencies/libdiscid-0.6.2/src/disc_linux.c
@@ -0,0 +1,275 @@
+/* --------------------------------------------------------------------------
+
+ MusicBrainz -- The Internet music metadatabase
+
+ Copyright (C) 2013 Johannes Dewender
+ 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
+
+--------------------------------------------------------------------------- */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/cdrom.h>
+#include <scsi/sg.h>
+
+
+#include "discid/discid.h"
+#include "discid/discid_private.h"
+#include "unix.h"
+
+
+/* timeout better shouldn't happen for scsi commands -> device is reset */
+#define DEFAULT_TIMEOUT 30000 /* in ms */
+
+#ifndef SG_MAX_SENSE
+#define SG_MAX_SENSE 16
+#endif
+
+#define MB_DEFAULT_DEVICE "/dev/cdrom"
+#define MAX_DEV_LEN 50
+
+#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
+# define THREAD_LOCAL __thread
+#else
+# define THREAD_LOCAL
+#endif
+
+static THREAD_LOCAL char default_device[MAX_DEV_LEN] = "";
+
+
+static int get_device(int number, char *device, int device_len) {
+ FILE *proc_file;
+ char *current_device;
+ char *lineptr = NULL;
+ char *saveptr = NULL;
+ size_t bufflen;
+ int i, count, counter;
+ int return_value = 0;
+
+ proc_file = fopen("/proc/sys/dev/cdrom/info", "r");
+ if (proc_file != NULL) {
+ /* skip to line containing device names */
+ do {
+ if (getline(&lineptr, &bufflen, proc_file) < 0) {
+ return 0;
+ }
+ } while (strstr(lineptr, "drive name:") == NULL);
+
+ /* count number of devices = number of tabs - 1*/
+ count = -1;
+ for (i = 0; i < strlen(lineptr); i++) {
+ if (lineptr[i] == '\t') count++;
+ }
+
+ /* go through devices, they are in reverse order */
+ current_device = strtok_r(lineptr, "\t", &saveptr);
+ /* skip column title */
+ current_device = strtok_r(NULL, "\t", &saveptr);
+ counter = count;
+ while (current_device != NULL && counter >= number) {
+ if (counter == number) {
+ snprintf(device, device_len,
+ "/dev/%s", current_device);
+ return_value = 1;
+ }
+ /* go to next in list */
+ current_device = strtok_r(NULL, "\t", &saveptr);
+ counter--;
+ }
+
+ /* trim the trailing \n for the last entry = first device */
+ if (return_value && device[strlen(device)-1] == '\n') {
+ device[strlen(device)-1] = '\0';
+ }
+ free(lineptr);
+ fclose(proc_file);
+ }
+ return return_value;
+}
+
+int mb_disc_unix_read_toc_header(int fd, mb_disc_toc *toc) {
+ struct cdrom_tochdr th;
+
+ int ret = ioctl(fd, CDROMREADTOCHDR, &th);
+
+ if ( ret < 0 )
+ return 0; /* error */
+
+ toc->first_track_num = th.cdth_trk0;
+ toc->last_track_num = th.cdth_trk1;
+
+ return 1;
+}
+
+
+int mb_disc_unix_read_toc_entry(int fd, int track_num, mb_disc_toc_track *track) {
+ struct cdrom_tocentry te;
+ int ret;
+
+ te.cdte_track = track_num;
+ te.cdte_format = CDROM_LBA;
+
+ ret = ioctl(fd, CDROMREADTOCENTRY, &te);
+ assert( te.cdte_format == CDROM_LBA );
+
+ if ( ret < 0 )
+ return 0; /* error */
+
+ track->address = te.cdte_addr.lba;
+ track->control = te.cdte_ctrl;
+
+ return 1;
+}
+
+char *mb_disc_get_default_device_unportable(void) {
+ /* prefer the default device symlink to the internal names */
+ if (mb_disc_unix_exists(MB_DEFAULT_DEVICE)) {
+ return MB_DEFAULT_DEVICE;
+ } else {
+ if (get_device(1, default_device, MAX_DEV_LEN)) {
+ return default_device;
+ } else {
+ return MB_DEFAULT_DEVICE;
+ }
+ }
+}
+
+void mb_disc_unix_read_mcn(int fd, mb_disc_private *disc) {
+ struct cdrom_mcn mcn;
+ memset(&mcn, 0, sizeof mcn);
+
+ if(ioctl(fd, CDROM_GET_MCN, &mcn) == -1) {
+ fprintf(stderr, "Warning: Unable to read the disc's media catalog number.\n");
+ } else {
+ strncpy( disc->mcn,
+ (const char *)mcn.medium_catalog_number,
+ MCN_STR_LENGTH );
+ }
+}
+
+/* Send a scsi command and receive data. */
+static int scsi_cmd(int fd, unsigned char *cmd, int cmd_len,
+ unsigned char *data, int data_len) {
+ unsigned char sense_buffer[SG_MAX_SENSE]; /* for "error situations" */
+ sg_io_hdr_t io_hdr;
+
+ memset(&io_hdr, 0, sizeof io_hdr);
+
+ assert(cmd_len <= 16);
+
+ io_hdr.interface_id = 'S'; /* must always be 'S' (SCSI generic) */
+ io_hdr.cmd_len = cmd_len;
+ io_hdr.cmdp = cmd;
+ io_hdr.timeout = DEFAULT_TIMEOUT; /* timeout in ms */
+ io_hdr.sbp = sense_buffer;/* only used when status is CHECK_CONDITION */
+ io_hdr.mx_sb_len = sizeof sense_buffer;
+ io_hdr.flags = SG_FLAG_DIRECT_IO;
+
+ io_hdr.dxferp = (void*)data;
+ io_hdr.dxfer_len = data_len;
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+
+ if (ioctl(fd, SG_IO, &io_hdr) != 0) {
+ return errno;
+ } else {
+ return io_hdr.status; /* 0 = success */
+ }
+}
+
+void mb_disc_unix_read_isrc(int fd, mb_disc_private *disc, int track_num) {
+ int i;
+ unsigned char cmd[10];
+ unsigned char data[24];
+ char buffer[ISRC_STR_LENGTH+1];
+
+ memset(cmd, 0, sizeof cmd);
+ memset(data, 0, sizeof data);
+ memset(buffer, 0, sizeof buffer);
+
+ /* data read from the last appropriate sector encountered
+ * by a current or previous media access operation.
+ * The Logical Unit accesses the media when there is/was no access.
+ * TODO: force access at a specific block? -> no duplicate ISRCs?
+ */
+ cmd[0] = 0x42; /* READ SUB-CHANNEL */
+ /* cmd[1] reserved / MSF bit (unused) */
+ cmd[2] = 1 << 6; /* 6th bit set (SUBQ) -> get sub-channel data */
+ cmd[3] = 0x03; /* get ISRC (ADR 3, Q sub-channel Mode-3) */
+ /* 4+5 reserved */
+ cmd[6] = track_num;
+ /* cmd[7] = upper byte of the transfer length */
+ cmd[8] = sizeof data; /* transfer length in bytes (4 header, 20 data)*/
+ /* cmd[9] = control byte */
+
+ if (scsi_cmd(fd, cmd, sizeof cmd, data, sizeof data) != 0) {
+ fprintf(stderr, "Warning: Cannot get ISRC code for track %d\n",
+ track_num);
+ return;
+ }
+
+ /* data[1:4] = sub-q channel data header (audio status, data length) */
+ if (data[8] & (1 << 7)) { /* TCVAL is set -> ISRCs valid */
+ for (i = 0; i < ISRC_STR_LENGTH; i++) {
+ buffer[i] = data[9 + i];
+ }
+ buffer[ISRC_STR_LENGTH] = 0;
+ strncpy(disc->isrc[track_num], buffer, ISRC_STR_LENGTH);
+ }
+ /* data[21:23] = zero, AFRAME, reserved */
+}
+
+int mb_disc_has_feature_unportable(enum discid_feature feature) {
+ switch(feature) {
+ case DISCID_FEATURE_READ:
+ case DISCID_FEATURE_MCN:
+ case DISCID_FEATURE_ISRC:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int mb_disc_read_unportable(mb_disc_private *disc, const char *device,
+ unsigned int features) {
+ char device_name[MAX_DEV_LEN] = "";
+ int device_number;
+
+ device_number = (int) strtol(device, NULL, 10);
+ if (device_number > 0) {
+ if(!get_device(device_number, device_name, MAX_DEV_LEN)) {
+ snprintf(disc->error_msg, MB_ERROR_MSG_LENGTH,
+ "cannot find cd device with the number '%d'",
+ device_number);
+ return 0;
+ } else {
+ return mb_disc_unix_read(disc, device_name, features);
+ }
+ } else {
+ return mb_disc_unix_read(disc, device, features);
+ }
+}
+
+/* EOF */
diff --git a/Src/external_dependencies/libdiscid-0.6.2/src/disc_solaris.c b/Src/external_dependencies/libdiscid-0.6.2/src/disc_solaris.c
new file mode 100644
index 00000000..7d74dcdb
--- /dev/null
+++ b/Src/external_dependencies/libdiscid-0.6.2/src/disc_solaris.c
@@ -0,0 +1,108 @@
+/* --------------------------------------------------------------------------
+
+ MusicBrainz -- The Internet music metadatabase
+
+ Copyright (C) 2009 Shunsuke Kuroda
+ 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
+
+--------------------------------------------------------------------------- */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/cdio.h>
+
+
+#include "discid/discid.h"
+#include "discid/discid_private.h"
+#include "unix.h"
+
+#define NUM_CANDIDATES 2
+
+static char *device_candidates[NUM_CANDIDATES] = {"/vol/dev/aliases/cdrom0",
+ "/volumes/dev/aliases/cdrom0"};
+
+int mb_disc_unix_read_toc_header(int fd, mb_disc_toc *toc) {
+ struct cdrom_tochdr th;
+
+ int ret = ioctl(fd, CDROMREADTOCHDR, &th);
+
+ if ( ret < 0 )
+ return ret; /* error */
+
+ toc->first_track_num = th.cdth_trk0;
+ toc->last_track_num = th.cdth_trk1;
+
+ return ret;
+}
+
+
+int mb_disc_unix_read_toc_entry(int fd, int track_num, mb_disc_toc_track *track) {
+ struct cdrom_tocentry te;
+ int ret;
+
+ memset(&te, 0, sizeof te);
+ te.cdte_track = track_num;
+ te.cdte_format = CDROM_LBA;
+
+ ret = ioctl(fd, CDROMREADTOCENTRY, &te);
+
+ if ( ret < 0 )
+ return 0; /* error */
+
+ assert( te.cdte_format == CDROM_LBA );
+ track->address = te.cdte_addr.lba;
+ track->control = te.cdte_ctrl;
+
+ return 1;
+}
+
+void mb_disc_unix_read_mcn(int fd, mb_disc_private *disc) {
+ return;
+}
+
+void mb_disc_unix_read_isrc(int fd, mb_disc_private *disc, int track_num) {
+ return;
+}
+
+char *mb_disc_get_default_device_unportable(void) {
+ return mb_disc_unix_find_device(device_candidates, NUM_CANDIDATES);
+}
+
+int mb_disc_has_feature_unportable(enum discid_feature feature) {
+ switch(feature) {
+ case DISCID_FEATURE_READ:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int mb_disc_read_unportable(mb_disc_private *disc, const char *device,
+ unsigned int features) {
+ return mb_disc_unix_read(disc, device, features);
+}
+
+/* EOF */
diff --git a/Src/external_dependencies/libdiscid-0.6.2/src/disc_win32.c b/Src/external_dependencies/libdiscid-0.6.2/src/disc_win32.c
new file mode 100644
index 00000000..df9409d6
--- /dev/null
+++ b/Src/external_dependencies/libdiscid-0.6.2/src/disc_win32.c
@@ -0,0 +1,247 @@
+/* --------------------------------------------------------------------------
+
+ MusicBrainz -- The Internet music metadatabase
+
+ Copyright (C) 2007-2008 Lukas Lalinsky
+
+ 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 _MSC_VER
+ #define _CRT_SECURE_NO_WARNINGS
+ #if (_MSC_VER < 1900)
+ #define snprintf _snprintf
+ #endif
+#endif
+
+#include <windows.h>
+#include <string.h>
+#include <stdio.h>
+
+#if defined(__CYGWIN__)
+#include <ntddcdrm.h>
+#elif defined(__MINGW32__)
+#include <ddk/ntddcdrm.h>
+#else
+#include "ntddcdrm.h"
+#endif
+
+#include "discid/discid.h"
+#include "discid/discid_private.h"
+
+
+#define MB_DEFAULT_DEVICE "D:"
+#define MAX_DEV_LEN 3
+
+#if defined(_MSC_VER)
+# define THREAD_LOCAL __declspec(thread)
+#elif (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
+# define THREAD_LOCAL __thread
+#else
+# define THREAD_LOCAL
+#endif
+
+static THREAD_LOCAL char default_device[MAX_DEV_LEN] = "\0";
+
+static int address_to_sectors(UCHAR address[4]) {
+ return address[1] * 4500 + address[2] * 75 + address[3];
+}
+
+static HANDLE create_device_handle(mb_disc_private *disc, const char *device) {
+ HANDLE hDevice;
+ char filename[128];
+ const char* colon;
+ size_t len;
+
+ strcpy(filename, "\\\\.\\");
+ len = strlen(device);
+ colon = strchr(device, ':');
+ if (colon) {
+ len = colon - device + 1;
+ }
+ strncat(filename, device, len > 120 ? 120 : len);
+
+ hDevice = CreateFile(filename, GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, NULL);
+ if (hDevice == INVALID_HANDLE_VALUE) {
+ snprintf(disc->error_msg, MB_ERROR_MSG_LENGTH,
+ "cannot open the CD audio device '%s'", device);
+ return 0;
+ }
+
+ return hDevice;
+}
+
+static void read_disc_mcn(HANDLE hDevice, mb_disc_private *disc) {
+ DWORD dwReturned;
+ BOOL bResult;
+ CDROM_SUB_Q_DATA_FORMAT format;
+ SUB_Q_CHANNEL_DATA data;
+
+ format.Track = 0;
+ format.Format = IOCTL_CDROM_MEDIA_CATALOG;
+ bResult = DeviceIoControl(hDevice, IOCTL_CDROM_READ_Q_CHANNEL,
+ &format, sizeof(format),
+ &data, sizeof(data),
+ &dwReturned, NULL);
+ if (bResult == FALSE) {
+ fprintf(stderr, "Warning: Unable to read the disc's media catalog number.\n");
+ } else {
+ strncpy(disc->mcn, (char *) data.MediaCatalog.MediaCatalog,
+ MCN_STR_LENGTH);
+ }
+}
+
+static void read_disc_isrc(HANDLE hDevice, mb_disc_private *disc, int track) {
+ DWORD dwReturned;
+ BOOL bResult;
+ CDROM_SUB_Q_DATA_FORMAT format;
+ SUB_Q_CHANNEL_DATA data;
+
+ format.Track = track;
+ format.Format = IOCTL_CDROM_TRACK_ISRC;
+ bResult = DeviceIoControl(hDevice, IOCTL_CDROM_READ_Q_CHANNEL,
+ &format, sizeof(format),
+ &data, sizeof(data),
+ &dwReturned, NULL);
+ if (bResult == FALSE) {
+ fprintf(stderr, "Warning: Unable to read the international standard recording code (ISRC) for track %i\n", track);
+ } else {
+ strncpy(disc->isrc[track], (char *) data.TrackIsrc.TrackIsrc,
+ ISRC_STR_LENGTH);
+ }
+}
+
+static int get_nth_device(int number, char* device, int device_length) {
+ int i, counter = 0;
+ char tmpDevice[MAX_DEV_LEN];
+ DWORD mask = GetLogicalDrives();
+
+ for (i = 0; i <= 25; i++) {
+ if (mask >> i & 1) {
+ snprintf(tmpDevice, MAX_DEV_LEN, "%c:", i + 'A');
+ if (GetDriveType(tmpDevice) == DRIVE_CDROM) {
+ counter++;
+ if (counter == number) {
+ strncpy(device, tmpDevice, device_length);
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+char *mb_disc_get_default_device_unportable(void) {
+ if (!get_nth_device(1, default_device, MAX_DEV_LEN)) {
+ return MB_DEFAULT_DEVICE;
+ }
+
+ return default_device;
+}
+
+int mb_disc_has_feature_unportable(enum discid_feature feature) {
+ switch(feature) {
+ case DISCID_FEATURE_READ:
+ case DISCID_FEATURE_MCN:
+ case DISCID_FEATURE_ISRC:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int mb_disc_winnt_read_toc(HANDLE device, mb_disc_private *disc, mb_disc_toc *toc) {
+ DWORD dwReturned;
+ BOOL bResult;
+ CDROM_TOC cd;
+ int i;
+
+ bResult = DeviceIoControl(device, IOCTL_CDROM_READ_TOC,
+ NULL, 0,
+ &cd, sizeof(cd),
+ &dwReturned, NULL);
+ if (bResult == FALSE) {
+ snprintf(disc->error_msg, MB_ERROR_MSG_LENGTH,
+ "error while reading the CD TOC");
+ return 0;
+ }
+
+ toc->first_track_num = cd.FirstTrack;
+ toc->last_track_num = cd.LastTrack;
+
+ /* Get info about all tracks */
+ for (i = toc->first_track_num; i <= toc->last_track_num; i++) {
+ toc->tracks[i].address = address_to_sectors(cd.TrackData[i - 1].Address) - 150;
+ toc->tracks[i].control = cd.TrackData[i - 1].Control;
+ }
+
+ /* Lead-out is stored after the last track */
+ toc->tracks[0].address = address_to_sectors(cd.TrackData[toc->last_track_num].Address) - 150;
+ toc->tracks[0].control = cd.TrackData[toc->last_track_num].Control;
+
+ return 1;
+}
+
+int mb_disc_read_unportable(mb_disc_private *disc, const char *device,
+ unsigned int features) {
+ mb_disc_toc toc;
+ char tmpDevice[MAX_DEV_LEN];
+ HANDLE hDevice;
+ int i, device_number;
+
+ device_number = (int) strtol(device, NULL, 10);
+
+ if (device_number > 0) {
+ if (!get_nth_device(device_number, tmpDevice, MAX_DEV_LEN)) {
+ snprintf(disc->error_msg, MB_ERROR_MSG_LENGTH,
+ "cannot find the CD audio device '%i'", device_number);
+ return 0;
+ }
+ device = tmpDevice;
+ }
+
+ hDevice = create_device_handle(disc, device);
+ if (hDevice == 0)
+ return 0;
+
+ if (!mb_disc_winnt_read_toc(hDevice, disc, &toc)) {
+ CloseHandle(hDevice);
+ return 0;
+ }
+
+ if (!mb_disc_load_toc(disc, &toc)) {
+ CloseHandle(hDevice);
+ return 0;
+ }
+
+ if (features & DISCID_FEATURE_MCN) {
+ read_disc_mcn(hDevice, disc);
+ }
+
+ for (i = disc->first_track_num; i <= disc->last_track_num; i++) {
+ if (features & DISCID_FEATURE_ISRC) {
+ read_disc_isrc(hDevice, disc, i);
+ }
+ }
+
+ CloseHandle(hDevice);
+ return 1;
+}
+
+/* EOF */
diff --git a/Src/external_dependencies/libdiscid-0.6.2/src/ntddcdrm.h b/Src/external_dependencies/libdiscid-0.6.2/src/ntddcdrm.h
new file mode 100644
index 00000000..defb5bd9
--- /dev/null
+++ b/Src/external_dependencies/libdiscid-0.6.2/src/ntddcdrm.h
@@ -0,0 +1,320 @@
+/*
+ * ntddcdrm.h
+ *
+ * CDROM IOCTL interface.
+ *
+ * This file is part of the w32api package.
+ *
+ * Contributors:
+ * Created by Casper S. Hornstrup <chorns@users.sourceforge.net>
+ *
+ * THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ * This source code is offered for use in the public domain. You may
+ * use, modify or distribute it freely.
+ *
+ * This code is distributed in the hope that it will be useful but
+ * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ * DISCLAIMED. This includes but is not limited to warranties of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#ifndef __NTDDCDRM_H
+#define __NTDDCDRM_H
+
+#if __GNUC__ >=3
+#pragma GCC system_header
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#pragma pack(push,4)
+
+#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM
+
+#define IOCTL_CDROM_CHECK_VERIFY \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_FIND_NEW_DEVICES \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_GET_CONTROL \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x000D, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_GET_DRIVE_GEOMETRY \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_GET_LAST_SESSION \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x000E, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_GET_VOLUME \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0005, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_PAUSE_AUDIO \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_PLAY_AUDIO_MSF \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_RAW_READ \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x000F, METHOD_OUT_DIRECT, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_READ_Q_CHANNEL \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x000B, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_READ_TOC \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_READ_TOC_EX \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0015, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_RESUME_AUDIO \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_SEEK_AUDIO_MSF \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_SET_VOLUME \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x000A, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_SIMBAD \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x1003, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_STOP_AUDIO \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+
+#define MAXIMUM_NUMBER_TRACKS 100
+#define MAXIMUM_CDROM_SIZE 804
+#define MINIMUM_CDROM_READ_TOC_EX_SIZE 2
+
+typedef struct _TRACK_DATA {
+ UCHAR Reserved;
+ UCHAR Control : 4;
+ UCHAR Adr : 4;
+ UCHAR TrackNumber;
+ UCHAR Reserved1;
+ UCHAR Address[4];
+} TRACK_DATA, *PTRACK_DATA;
+
+/* CDROM_DISK_DATA.DiskData flags */
+#define CDROM_DISK_AUDIO_TRACK 0x00000001
+#define CDROM_DISK_DATA_TRACK 0x00000002
+
+typedef struct _CDROM_DISK_DATA {
+ ULONG DiskData;
+} CDROM_DISK_DATA, *PCDROM_DISK_DATA;
+
+typedef struct _CDROM_PLAY_AUDIO_MSF {
+ UCHAR StartingM;
+ UCHAR StartingS;
+ UCHAR StartingF;
+ UCHAR EndingM;
+ UCHAR EndingS;
+ UCHAR EndingF;
+} CDROM_PLAY_AUDIO_MSF, *PCDROM_PLAY_AUDIO_MSF;
+
+/* CDROM_READ_TOC_EX.Format constants */
+#define CDROM_READ_TOC_EX_FORMAT_TOC 0x00
+#define CDROM_READ_TOC_EX_FORMAT_SESSION 0x01
+#define CDROM_READ_TOC_EX_FORMAT_FULL_TOC 0x02
+#define CDROM_READ_TOC_EX_FORMAT_PMA 0x03
+#define CDROM_READ_TOC_EX_FORMAT_ATIP 0x04
+#define CDROM_READ_TOC_EX_FORMAT_CDTEXT 0x05
+
+typedef struct _CDROM_READ_TOC_EX {
+ UCHAR Format : 4;
+ UCHAR Reserved1 : 3;
+ UCHAR Msf : 1;
+ UCHAR SessionTrack;
+ UCHAR Reserved2;
+ UCHAR Reserved3;
+} CDROM_READ_TOC_EX, *PCDROM_READ_TOC_EX;
+
+typedef struct _CDROM_SEEK_AUDIO_MSF {
+ UCHAR M;
+ UCHAR S;
+ UCHAR F;
+} CDROM_SEEK_AUDIO_MSF, *PCDROM_SEEK_AUDIO_MSF;
+
+/* CDROM_SUB_Q_DATA_FORMAT.Format constants */
+#define IOCTL_CDROM_SUB_Q_CHANNEL 0x00
+#define IOCTL_CDROM_CURRENT_POSITION 0x01
+#define IOCTL_CDROM_MEDIA_CATALOG 0x02
+#define IOCTL_CDROM_TRACK_ISRC 0x03
+
+typedef struct _CDROM_SUB_Q_DATA_FORMAT {
+ UCHAR Format;
+ UCHAR Track;
+} CDROM_SUB_Q_DATA_FORMAT, *PCDROM_SUB_Q_DATA_FORMAT;
+
+typedef struct _CDROM_TOC {
+ UCHAR Length[2];
+ UCHAR FirstTrack;
+ UCHAR LastTrack;
+ TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS];
+} CDROM_TOC, *PCDROM_TOC;
+
+#define CDROM_TOC_SIZE sizeof(CDROM_TOC)
+
+typedef struct _CDROM_TOC_ATIP_DATA_BLOCK {
+ UCHAR CdrwReferenceSpeed : 3;
+ UCHAR Reserved3 : 1;
+ UCHAR WritePower : 3;
+ UCHAR True1 : 1;
+ UCHAR Reserved4 : 6;
+ UCHAR UnrestrictedUse : 1;
+ UCHAR Reserved5 : 1;
+ UCHAR A3Valid : 1;
+ UCHAR A2Valid : 1;
+ UCHAR A1Valid : 1;
+ UCHAR Reserved6 : 3;
+ UCHAR IsCdrw : 1;
+ UCHAR True2 : 1;
+ UCHAR Reserved7;
+ UCHAR LeadInMsf[3];
+ UCHAR Reserved8;
+ UCHAR LeadOutMsf[3];
+ UCHAR Reserved9;
+ UCHAR A1Values[3];
+ UCHAR Reserved10;
+ UCHAR A2Values[3];
+ UCHAR Reserved11;
+ UCHAR A3Values[3];
+ UCHAR Reserved12;
+} CDROM_TOC_ATIP_DATA_BLOCK, *PCDROM_TOC_ATIP_DATA_BLOCK;
+
+/* CDROM_TOC_CD_TEXT_DATA_BLOCK.PackType constants */
+#define CDROM_CD_TEXT_PACK_ALBUM_NAME 0x80
+#define CDROM_CD_TEXT_PACK_PERFORMER 0x81
+#define CDROM_CD_TEXT_PACK_SONGWRITER 0x82
+#define CDROM_CD_TEXT_PACK_COMPOSER 0x83
+#define CDROM_CD_TEXT_PACK_ARRANGER 0x84
+#define CDROM_CD_TEXT_PACK_MESSAGES 0x85
+#define CDROM_CD_TEXT_PACK_DISC_ID 0x86
+#define CDROM_CD_TEXT_PACK_GENRE 0x87
+#define CDROM_CD_TEXT_PACK_TOC_INFO 0x88
+#define CDROM_CD_TEXT_PACK_TOC_INFO2 0x89
+#define CDROM_CD_TEXT_PACK_UPC_EAN 0x8e
+#define CDROM_CD_TEXT_PACK_SIZE_INFO 0x8f
+
+typedef struct _CDROM_TOC_CD_TEXT_DATA_BLOCK {
+ UCHAR PackType;
+ UCHAR TrackNumber : 7;
+ UCHAR ExtensionFlag : 1;
+ UCHAR SequenceNumber;
+ UCHAR CharacterPosition : 4;
+ UCHAR BlockNumber : 3;
+ UCHAR Unicode : 1;
+ union {
+ UCHAR Text[12];
+ WCHAR WText[6];
+ };
+ UCHAR CRC[2];
+} CDROM_TOC_CD_TEXT_DATA_BLOCK, *PCDROM_TOC_CD_TEXT_DATA_BLOCK;
+
+/* CDROM_TOC_FULL_TOC_DATA_BLOCK.Adr constants */
+#define ADR_NO_MODE_INFORMATION 0x0
+#define ADR_ENCODES_CURRENT_POSITION 0x1
+#define ADR_ENCODES_MEDIA_CATALOG 0x2
+#define ADR_ENCODES_ISRC 0x3
+
+typedef struct _CDROM_TOC_FULL_TOC_DATA_BLOCK {
+ UCHAR SessionNumber;
+ UCHAR Control : 4;
+ UCHAR Adr : 4;
+ UCHAR Reserved1;
+ UCHAR Point;
+ UCHAR MsfExtra[3];
+ UCHAR Zero;
+ UCHAR Msf[3];
+} CDROM_TOC_FULL_TOC_DATA_BLOCK, *PCDROM_TOC_FULL_TOC_DATA_BLOCK;
+
+/* SUB_Q_HEADER.AudioStatus constants */
+#define AUDIO_STATUS_NOT_SUPPORTED 0x00
+#define AUDIO_STATUS_IN_PROGRESS 0x11
+#define AUDIO_STATUS_PAUSED 0x12
+#define AUDIO_STATUS_PLAY_COMPLETE 0x13
+#define AUDIO_STATUS_PLAY_ERROR 0x14
+#define AUDIO_STATUS_NO_STATUS 0x15
+
+typedef struct _SUB_Q_HEADER {
+ UCHAR Reserved;
+ UCHAR AudioStatus;
+ UCHAR DataLength[2];
+} SUB_Q_HEADER, *PSUB_Q_HEADER;
+
+typedef struct _SUB_Q_MEDIA_CATALOG_NUMBER {
+ SUB_Q_HEADER Header;
+ UCHAR FormatCode;
+ UCHAR Reserved[3];
+ UCHAR Reserved1 : 7;
+ UCHAR Mcval :1;
+ UCHAR MediaCatalog[15];
+} SUB_Q_MEDIA_CATALOG_NUMBER, *PSUB_Q_MEDIA_CATALOG_NUMBER;
+
+typedef struct _SUB_Q_TRACK_ISRC {
+ SUB_Q_HEADER Header;
+ UCHAR FormatCode;
+ UCHAR Reserved0;
+ UCHAR Track;
+ UCHAR Reserved1;
+ UCHAR Reserved2 : 7;
+ UCHAR Tcval : 1;
+ UCHAR TrackIsrc[15];
+} SUB_Q_TRACK_ISRC, *PSUB_Q_TRACK_ISRC;
+
+typedef struct _SUB_Q_CURRENT_POSITION {
+ SUB_Q_HEADER Header;
+ UCHAR FormatCode;
+ UCHAR Control : 4;
+ UCHAR ADR : 4;
+ UCHAR TrackNumber;
+ UCHAR IndexNumber;
+ UCHAR AbsoluteAddress[4];
+ UCHAR TrackRelativeAddress[4];
+} SUB_Q_CURRENT_POSITION, *PSUB_Q_CURRENT_POSITION;
+
+typedef union _SUB_Q_CHANNEL_DATA {
+ SUB_Q_CURRENT_POSITION CurrentPosition;
+ SUB_Q_MEDIA_CATALOG_NUMBER MediaCatalog;
+ SUB_Q_TRACK_ISRC TrackIsrc;
+} SUB_Q_CHANNEL_DATA, *PSUB_Q_CHANNEL_DATA;
+
+/* CDROM_AUDIO_CONTROL.LbaFormat constants */
+#define AUDIO_WITH_PREEMPHASIS 0x1
+#define DIGITAL_COPY_PERMITTED 0x2
+#define AUDIO_DATA_TRACK 0x4
+#define TWO_FOUR_CHANNEL_AUDIO 0x8
+
+typedef struct _CDROM_AUDIO_CONTROL {
+ UCHAR LbaFormat;
+ USHORT LogicalBlocksPerSecond;
+} CDROM_AUDIO_CONTROL, *PCDROM_AUDIO_CONTROL;
+
+typedef struct _VOLUME_CONTROL {
+ UCHAR PortVolume[4];
+} VOLUME_CONTROL, *PVOLUME_CONTROL;
+
+typedef enum _TRACK_MODE_TYPE {
+ YellowMode2,
+ XAForm2,
+ CDDA
+} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE;
+
+typedef struct __RAW_READ_INFO {
+ LARGE_INTEGER DiskOffset;
+ ULONG SectorCount;
+ TRACK_MODE_TYPE TrackMode;
+} RAW_READ_INFO, *PRAW_READ_INFO;
+
+#pragma pack(pop)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __NTDDCDRM_H */
diff --git a/Src/external_dependencies/libdiscid-0.6.2/src/sha1.c b/Src/external_dependencies/libdiscid-0.6.2/src/sha1.c
new file mode 100644
index 00000000..7e154f8e
--- /dev/null
+++ b/Src/external_dependencies/libdiscid-0.6.2/src/sha1.c
@@ -0,0 +1,329 @@
+/* (PD) 2001 The Bitzi Corporation
+ * Please see file COPYING or http://bitzi.com/publicdomain
+ * for more info.
+ *
+ * NIST Secure Hash Algorithm
+ * heavily modified by Uwe Hollerbach <uh@alumni.caltech edu>
+ * from Peter C. Gutmann's implementation as found in
+ * Applied Cryptography by Bruce Schneier
+ * Further modifications to include the "UNRAVEL" stuff, below
+ *
+ * This code is in the public domain
+ *
+ * $Id$
+ */
+
+#include <string.h>
+#include "sha1.h"
+
+/* UNRAVEL should be fastest & biggest */
+/* UNROLL_LOOPS should be just as big, but slightly slower */
+/* both undefined should be smallest and slowest */
+
+#define UNRAVEL
+/* #define UNROLL_LOOPS */
+
+/* SHA f()-functions */
+
+#define f1(x,y,z) ((x & y) | (~x & z))
+#define f2(x,y,z) (x ^ y ^ z)
+#define f3(x,y,z) ((x & y) | (x & z) | (y & z))
+#define f4(x,y,z) (x ^ y ^ z)
+
+/* SHA constants */
+
+#define CONST1 0x5a827999L
+#define CONST2 0x6ed9eba1L
+#define CONST3 0x8f1bbcdcL
+#define CONST4 0xca62c1d6L
+
+/* truncate to 32 bits -- should be a null op on 32-bit machines */
+
+#define T32(x) ((x) & 0xffffffffL)
+
+/* 32-bit rotate */
+
+#define R32(x,n) T32(((x << n) | (x >> (32 - n))))
+
+/* the generic case, for when the overall rotation is not unraveled */
+
+#define FG(n) \
+ T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n); \
+ E = D; D = C; C = R32(B,30); B = A; A = T
+
+/* specific cases, for when the overall rotation is unraveled */
+
+#define FA(n) \
+ T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n); B = R32(B,30)
+
+#define FB(n) \
+ E = T32(R32(T,5) + f##n(A,B,C) + D + *WP++ + CONST##n); A = R32(A,30)
+
+#define FC(n) \
+ D = T32(R32(E,5) + f##n(T,A,B) + C + *WP++ + CONST##n); T = R32(T,30)
+
+#define FD(n) \
+ C = T32(R32(D,5) + f##n(E,T,A) + B + *WP++ + CONST##n); E = R32(E,30)
+
+#define FE(n) \
+ B = T32(R32(C,5) + f##n(D,E,T) + A + *WP++ + CONST##n); D = R32(D,30)
+
+#define FT(n) \
+ A = T32(R32(B,5) + f##n(C,D,E) + T + *WP++ + CONST##n); C = R32(C,30)
+
+/* do SHA transformation */
+
+static void sha_transform(SHA_INFO *sha_info)
+{
+ int i;
+ SHA_BYTE *dp;
+ SHA_LONG T, A, B, C, D, E, W[80], *WP;
+
+ dp = sha_info->data;
+
+/*
+the following makes sure that at least one code block below is
+traversed or an error is reported, without the necessity for nested
+preprocessor if/else/endif blocks, which are a great pain in the
+nether regions of the anatomy...
+*/
+#undef SWAP_DONE
+
+#if (SHA_BYTE_ORDER == 1234)
+#define SWAP_DONE
+ for (i = 0; i < 16; ++i) {
+ T = *((SHA_LONG *) dp);
+ dp += 4;
+ W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
+ ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
+ }
+#endif /* SHA_BYTE_ORDER == 1234 */
+
+#if (SHA_BYTE_ORDER == 4321)
+#define SWAP_DONE
+ for (i = 0; i < 16; ++i) {
+ T = *((SHA_LONG *) dp);
+ dp += 4;
+ W[i] = T32(T);
+ }
+#endif /* SHA_BYTE_ORDER == 4321 */
+
+#if (SHA_BYTE_ORDER == 12345678)
+#define SWAP_DONE
+ for (i = 0; i < 16; i += 2) {
+ T = *((SHA_LONG *) dp);
+ dp += 8;
+ W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
+ ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
+ T >>= 32;
+ W[i+1] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
+ ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
+ }
+#endif /* SHA_BYTE_ORDER == 12345678 */
+
+#if (SHA_BYTE_ORDER == 87654321)
+#define SWAP_DONE
+ for (i = 0; i < 16; i += 2) {
+ T = *((SHA_LONG *) dp);
+ dp += 8;
+ W[i] = T32(T >> 32);
+ W[i+1] = T32(T);
+ }
+#endif /* SHA_BYTE_ORDER == 87654321 */
+
+#ifndef SWAP_DONE
+#error Unknown byte order -- you need to add code here
+#endif /* SWAP_DONE */
+
+ for (i = 16; i < 80; ++i) {
+ W[i] = W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16];
+#if (SHA_VERSION == 1)
+ W[i] = R32(W[i], 1);
+#endif /* SHA_VERSION */
+ }
+ A = sha_info->digest[0];
+ B = sha_info->digest[1];
+ C = sha_info->digest[2];
+ D = sha_info->digest[3];
+ E = sha_info->digest[4];
+ WP = W;
+#ifdef UNRAVEL
+ FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1); FC(1); FD(1);
+ FE(1); FT(1); FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1);
+ FC(2); FD(2); FE(2); FT(2); FA(2); FB(2); FC(2); FD(2); FE(2); FT(2);
+ FA(2); FB(2); FC(2); FD(2); FE(2); FT(2); FA(2); FB(2); FC(2); FD(2);
+ FE(3); FT(3); FA(3); FB(3); FC(3); FD(3); FE(3); FT(3); FA(3); FB(3);
+ FC(3); FD(3); FE(3); FT(3); FA(3); FB(3); FC(3); FD(3); FE(3); FT(3);
+ FA(4); FB(4); FC(4); FD(4); FE(4); FT(4); FA(4); FB(4); FC(4); FD(4);
+ FE(4); FT(4); FA(4); FB(4); FC(4); FD(4); FE(4); FT(4); FA(4); FB(4);
+ sha_info->digest[0] = T32(sha_info->digest[0] + E);
+ sha_info->digest[1] = T32(sha_info->digest[1] + T);
+ sha_info->digest[2] = T32(sha_info->digest[2] + A);
+ sha_info->digest[3] = T32(sha_info->digest[3] + B);
+ sha_info->digest[4] = T32(sha_info->digest[4] + C);
+#else /* !UNRAVEL */
+#ifdef UNROLL_LOOPS
+ FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1);
+ FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1);
+ FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2);
+ FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2);
+ FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3);
+ FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3);
+ FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4);
+ FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4);
+#else /* !UNROLL_LOOPS */
+ for (i = 0; i < 20; ++i) { FG(1); }
+ for (i = 20; i < 40; ++i) { FG(2); }
+ for (i = 40; i < 60; ++i) { FG(3); }
+ for (i = 60; i < 80; ++i) { FG(4); }
+#endif /* !UNROLL_LOOPS */
+ sha_info->digest[0] = T32(sha_info->digest[0] + A);
+ sha_info->digest[1] = T32(sha_info->digest[1] + B);
+ sha_info->digest[2] = T32(sha_info->digest[2] + C);
+ sha_info->digest[3] = T32(sha_info->digest[3] + D);
+ sha_info->digest[4] = T32(sha_info->digest[4] + E);
+#endif /* !UNRAVEL */
+}
+
+/* initialize the SHA digest */
+
+void sha_init(SHA_INFO *sha_info)
+{
+ sha_info->digest[0] = 0x67452301L;
+ sha_info->digest[1] = 0xefcdab89L;
+ sha_info->digest[2] = 0x98badcfeL;
+ sha_info->digest[3] = 0x10325476L;
+ sha_info->digest[4] = 0xc3d2e1f0L;
+ sha_info->count_lo = 0L;
+ sha_info->count_hi = 0L;
+ sha_info->local = 0;
+}
+
+/* update the SHA digest */
+
+void sha_update(SHA_INFO *sha_info, SHA_BYTE *buffer, size_t count)
+{
+ size_t i;
+ SHA_LONG clo;
+
+ clo = T32(sha_info->count_lo + ((SHA_LONG) count << 3));
+ if (clo < sha_info->count_lo) {
+ ++sha_info->count_hi;
+ }
+ sha_info->count_lo = clo;
+ sha_info->count_hi += (SHA_LONG) count >> 29;
+ if (sha_info->local) {
+ i = SHA_BLOCKSIZE - sha_info->local;
+ if (i > count) {
+ i = count;
+ }
+ memcpy(((SHA_BYTE *) sha_info->data) + sha_info->local, buffer, i);
+ count -= i;
+ buffer += i;
+ sha_info->local += i;
+ if (sha_info->local == SHA_BLOCKSIZE) {
+ sha_transform(sha_info);
+ } else {
+ return;
+ }
+ }
+ while (count >= SHA_BLOCKSIZE) {
+ memcpy(sha_info->data, buffer, SHA_BLOCKSIZE);
+ buffer += SHA_BLOCKSIZE;
+ count -= SHA_BLOCKSIZE;
+ sha_transform(sha_info);
+ }
+ memcpy(sha_info->data, buffer, count);
+ sha_info->local = count;
+}
+
+/* finish computing the SHA digest */
+
+void sha_final(unsigned char digest[20], SHA_INFO *sha_info)
+{
+ int count;
+ SHA_LONG lo_bit_count, hi_bit_count;
+
+ lo_bit_count = sha_info->count_lo;
+ hi_bit_count = sha_info->count_hi;
+ count = (int) ((lo_bit_count >> 3) & 0x3f);
+ ((SHA_BYTE *) sha_info->data)[count++] = 0x80;
+ if (count > SHA_BLOCKSIZE - 8) {
+ memset(((SHA_BYTE *) sha_info->data) + count, 0, SHA_BLOCKSIZE - count);
+ sha_transform(sha_info);
+ memset((SHA_BYTE *) sha_info->data, 0, SHA_BLOCKSIZE - 8);
+ } else {
+ memset(((SHA_BYTE *) sha_info->data) + count, 0,
+ SHA_BLOCKSIZE - 8 - count);
+ }
+ sha_info->data[56] = (unsigned char) ((hi_bit_count >> 24) & 0xff);
+ sha_info->data[57] = (unsigned char) ((hi_bit_count >> 16) & 0xff);
+ sha_info->data[58] = (unsigned char) ((hi_bit_count >> 8) & 0xff);
+ sha_info->data[59] = (unsigned char) ((hi_bit_count >> 0) & 0xff);
+ sha_info->data[60] = (unsigned char) ((lo_bit_count >> 24) & 0xff);
+ sha_info->data[61] = (unsigned char) ((lo_bit_count >> 16) & 0xff);
+ sha_info->data[62] = (unsigned char) ((lo_bit_count >> 8) & 0xff);
+ sha_info->data[63] = (unsigned char) ((lo_bit_count >> 0) & 0xff);
+ sha_transform(sha_info);
+ digest[ 0] = (unsigned char) ((sha_info->digest[0] >> 24) & 0xff);
+ digest[ 1] = (unsigned char) ((sha_info->digest[0] >> 16) & 0xff);
+ digest[ 2] = (unsigned char) ((sha_info->digest[0] >> 8) & 0xff);
+ digest[ 3] = (unsigned char) ((sha_info->digest[0] ) & 0xff);
+ digest[ 4] = (unsigned char) ((sha_info->digest[1] >> 24) & 0xff);
+ digest[ 5] = (unsigned char) ((sha_info->digest[1] >> 16) & 0xff);
+ digest[ 6] = (unsigned char) ((sha_info->digest[1] >> 8) & 0xff);
+ digest[ 7] = (unsigned char) ((sha_info->digest[1] ) & 0xff);
+ digest[ 8] = (unsigned char) ((sha_info->digest[2] >> 24) & 0xff);
+ digest[ 9] = (unsigned char) ((sha_info->digest[2] >> 16) & 0xff);
+ digest[10] = (unsigned char) ((sha_info->digest[2] >> 8) & 0xff);
+ digest[11] = (unsigned char) ((sha_info->digest[2] ) & 0xff);
+ digest[12] = (unsigned char) ((sha_info->digest[3] >> 24) & 0xff);
+ digest[13] = (unsigned char) ((sha_info->digest[3] >> 16) & 0xff);
+ digest[14] = (unsigned char) ((sha_info->digest[3] >> 8) & 0xff);
+ digest[15] = (unsigned char) ((sha_info->digest[3] ) & 0xff);
+ digest[16] = (unsigned char) ((sha_info->digest[4] >> 24) & 0xff);
+ digest[17] = (unsigned char) ((sha_info->digest[4] >> 16) & 0xff);
+ digest[18] = (unsigned char) ((sha_info->digest[4] >> 8) & 0xff);
+ digest[19] = (unsigned char) ((sha_info->digest[4] ) & 0xff);
+}
+
+/* compute the SHA digest of a FILE stream */
+
+#define BLOCK_SIZE 8192
+
+void sha_stream(unsigned char digest[20], SHA_INFO *sha_info, FILE *fin)
+{
+ size_t i;
+ SHA_BYTE data[BLOCK_SIZE];
+
+ sha_init(sha_info);
+ while ((i = fread(data, 1, BLOCK_SIZE, fin)) > 0) {
+ sha_update(sha_info, data, i);
+ }
+ sha_final(digest, sha_info);
+}
+
+/* print a SHA digest */
+
+void sha_print(unsigned char digest[20])
+{
+ int i, j;
+
+ for (j = 0; j < 5; ++j) {
+ for (i = 0; i < 4; ++i) {
+ printf("%02x", *digest++);
+ }
+ printf("%c", (j < 4) ? ' ' : '\n');
+ }
+}
+
+char *sha_version(void)
+{
+#if (SHA_VERSION == 1)
+ static char *version = "SHA-1";
+#else
+ static char *version = "SHA";
+#endif
+ return(version);
+}
+
diff --git a/Src/external_dependencies/libdiscid-0.6.2/src/sha1.h b/Src/external_dependencies/libdiscid-0.6.2/src/sha1.h
new file mode 100644
index 00000000..16e563b3
--- /dev/null
+++ b/Src/external_dependencies/libdiscid-0.6.2/src/sha1.h
@@ -0,0 +1,63 @@
+/* NIST Secure Hash Algorithm */
+/* heavily modified by Uwe Hollerbach <uh@alumni.caltech edu> */
+/* from Peter C. Gutmann's implementation as found in */
+/* Applied Cryptography by Bruce Schneier */
+/* This code is in the public domain */
+/* $Id$ */
+
+#ifndef SHA_H
+#define SHA_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "discid/discid.h" /* for LIBDISCID_INTERNAL */
+
+/* Useful defines & typedefs */
+typedef unsigned char SHA_BYTE; /* 8-bit quantity */
+typedef unsigned long SHA_LONG; /* 32-or-more-bit quantity */
+
+#define SHA_BLOCKSIZE 64
+#define SHA_DIGESTSIZE 20
+
+typedef struct {
+ SHA_LONG digest[5]; /* message digest */
+ SHA_LONG count_lo, count_hi; /* 64-bit bit count */
+ SHA_BYTE data[SHA_BLOCKSIZE]; /* SHA data buffer */
+ size_t local; /* unprocessed amount in data */
+} SHA_INFO;
+
+LIBDISCID_INTERNAL void sha_init(SHA_INFO *);
+LIBDISCID_INTERNAL void sha_update(SHA_INFO *, SHA_BYTE *, size_t);
+LIBDISCID_INTERNAL void sha_final(unsigned char [20], SHA_INFO *);
+
+LIBDISCID_INTERNAL void sha_stream(unsigned char [20], SHA_INFO *, FILE *);
+LIBDISCID_INTERNAL void sha_print(unsigned char [20]);
+LIBDISCID_INTERNAL char *sha_version(void);
+
+#define SHA_VERSION 1
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+
+
+#ifdef WORDS_BIGENDIAN
+# if SIZEOF_LONG == 4
+# define SHA_BYTE_ORDER 4321
+# elif SIZEOF_LONG == 8
+# define SHA_BYTE_ORDER 87654321
+# endif
+#else
+# if SIZEOF_LONG == 4
+# define SHA_BYTE_ORDER 1234
+# elif SIZEOF_LONG == 8
+# define SHA_BYTE_ORDER 12345678
+# endif
+#endif
+
+#else
+
+#define SHA_BYTE_ORDER 1234
+
+#endif
+
+#endif /* SHA_H */
diff --git a/Src/external_dependencies/libdiscid-0.6.2/src/toc.c b/Src/external_dependencies/libdiscid-0.6.2/src/toc.c
new file mode 100644
index 00000000..b1ec59f2
--- /dev/null
+++ b/Src/external_dependencies/libdiscid-0.6.2/src/toc.c
@@ -0,0 +1,116 @@
+/* --------------------------------------------------------------------------
+
+ MusicBrainz -- The Internet music metadatabase
+
+ Copyright (C) 2006 Lukas Lalinsky
+
+ 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 _MSC_VER
+ #define _CRT_SECURE_NO_WARNINGS
+ #if (_MSC_VER < 1900)
+ #define snprintf _snprintf
+ #endif
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "discid/discid_private.h"
+
+#define XA_INTERVAL ((60 + 90 + 2) * 75)
+#define DATA_TRACK 0x04
+
+
+int mb_disc_load_toc(mb_disc_private *disc, mb_disc_toc *toc) {
+ int first_audio_track, last_audio_track, i;
+ mb_disc_toc_track *track;
+
+ if (toc->first_track_num < 1) {
+ snprintf(disc->error_msg, MB_ERROR_MSG_LENGTH,
+ "invalid CD TOC - first track number must be 1 or higher");
+ return 0;
+ }
+
+ if (toc->last_track_num < 1) {
+ snprintf(disc->error_msg, MB_ERROR_MSG_LENGTH,
+ "invalid CD TOC - last track number must be 99 or lower");
+ return 0;
+ }
+
+ /* we can't just skip data tracks at the front
+ * releases are always expected to start with track 1 by MusicBrainz
+ */
+ first_audio_track = toc->first_track_num;
+ last_audio_track = -1;
+ /* scan the TOC for audio tracks */
+ for (i = toc->first_track_num; i <= toc->last_track_num; i++) {
+ track = &toc->tracks[i];
+ if ( !(track->control & DATA_TRACK) ) {
+ last_audio_track = i;
+ }
+ }
+
+ if (last_audio_track < 0) {
+ snprintf(disc->error_msg, MB_ERROR_MSG_LENGTH,
+ "no actual audio tracks on disc: CDROM or DVD?");
+ return 0;
+ }
+
+ disc->first_track_num = first_audio_track;
+ disc->last_track_num = last_audio_track;
+
+ /* get offsets for all found data tracks */
+ for (i = first_audio_track; i <= last_audio_track; i++) {
+ track = &toc->tracks[i];
+ if (track->address > 0) {
+ disc->track_offsets[i] = track->address + 150;
+ } else {
+ /* this seems to happen on "copy-protected" discs */
+ disc->track_offsets[i] = 150;
+ }
+ }
+
+ /* if the last audio track is not the last track on the CD,
+ * use the offset of the next data track as the "lead-out" offset */
+ if (last_audio_track < toc->last_track_num) {
+ track = &toc->tracks[last_audio_track + 1];
+ disc->track_offsets[0] = track->address - XA_INTERVAL + 150;
+ } else {
+ /* use the regular lead-out track */
+ track = &toc->tracks[0];
+ disc->track_offsets[0] = track->address + 150;
+ }
+
+ /* as long as the lead-out isn't actually bigger than
+ * the position of the last track, the last track is invalid.
+ * This happens on "copy-protected"/invalid discs.
+ * The track is then neither a valid audio track, nor data track.
+ */
+ while (disc->track_offsets[0] < disc->track_offsets[last_audio_track]) {
+ disc->last_track_num = --last_audio_track;
+ disc->track_offsets[last_audio_track + 1] = 0;
+ track = &toc->tracks[last_audio_track + 1];
+ disc->track_offsets[0] = track->address - XA_INTERVAL + 150;
+ }
+
+ return 1;
+}
+
+/* EOF */
diff --git a/Src/external_dependencies/libdiscid-0.6.2/src/unix.c b/Src/external_dependencies/libdiscid-0.6.2/src/unix.c
new file mode 100644
index 00000000..a91c8e58
--- /dev/null
+++ b/Src/external_dependencies/libdiscid-0.6.2/src/unix.c
@@ -0,0 +1,151 @@
+/* --------------------------------------------------------------------------
+
+ 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
+
+--------------------------------------------------------------------------- */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "discid/discid_private.h"
+#include "unix.h"
+
+
+int mb_disc_unix_exists(const char *device) {
+ int fd;
+ fd = open(device, O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+ /* we only check for existance, access should fail later on */
+ if (errno == ENOENT) {
+ return 0;
+ } else {
+ return 1;
+ }
+ } else {
+ close(fd);
+ return 1;
+ }
+}
+
+char *mb_disc_unix_find_device(char *candidates[], int num_candidates) {
+ int i;
+
+ for (i = 0; i < num_candidates; i++) {
+ if (mb_disc_unix_exists(candidates[i])) {
+ return candidates[i];
+ }
+ }
+ /* use the first name for the error message later on */
+ return candidates[0];
+}
+
+int mb_disc_unix_open(mb_disc_private *disc, const char *device) {
+ int fd;
+
+ fd = open(device, O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+ snprintf(disc->error_msg, MB_ERROR_MSG_LENGTH,
+ "cannot open device `%s'", device);
+ }
+ /* fd < 0 check needs to be made by caller */
+ return fd;
+}
+
+int mb_disc_unix_read_toc(int fd, mb_disc_private *disc, mb_disc_toc *toc) {
+ int i;
+
+ /* Find the numbers of the first track (usually 1) and the last track. */
+ if ( !mb_disc_unix_read_toc_header(fd, toc) ) {
+ snprintf(disc->error_msg, MB_ERROR_MSG_LENGTH,
+ "cannot read table of contents");
+ return 0;
+ }
+
+ /* basic error checking */
+ if ( toc->last_track_num == 0 ) {
+ snprintf(disc->error_msg, MB_ERROR_MSG_LENGTH,
+ "this disc has no tracks");
+ return 0;
+ }
+
+ /*
+ * Read the TOC entry for every track.
+ */
+ for (i = toc->first_track_num; i <= toc->last_track_num; i++) {
+ if ( !mb_disc_unix_read_toc_entry(fd, i, &toc->tracks[i]) ) {
+ snprintf(disc->error_msg, MB_ERROR_MSG_LENGTH,
+ "cannot read TOC entry for track %d", i);
+ return 0;
+ }
+ }
+ if ( !mb_disc_unix_read_toc_entry(fd, 0xAA, &toc->tracks[0]) ) {
+ snprintf(disc->error_msg, MB_ERROR_MSG_LENGTH,
+ "cannot read TOC entry for lead-out");
+ return 0;
+ }
+
+ return 1;
+}
+
+int mb_disc_unix_read(mb_disc_private *disc, const char *device,
+ unsigned int features) {
+ mb_disc_toc toc;
+ int fd;
+ int i;
+
+ fd = mb_disc_unix_open(disc, device);
+ if (fd < 0)
+ return 0;
+
+
+ if ( !mb_disc_unix_read_toc(fd, disc, &toc) ) {
+ close(fd);
+ return 0;
+ }
+
+ if ( !mb_disc_load_toc(disc, &toc) ) {
+ close(fd);
+ return 0;
+ }
+
+ /* Read in the media catalog number */
+ if (features & DISCID_FEATURE_MCN
+ && mb_disc_has_feature_unportable(DISCID_FEATURE_MCN)) {
+ mb_disc_unix_read_mcn(fd, disc);
+ }
+
+ /* Read the ISRC for the track */
+ if (features & DISCID_FEATURE_ISRC
+ && mb_disc_has_feature_unportable(DISCID_FEATURE_ISRC)) {
+ for (i = disc->first_track_num; i <= disc->last_track_num; i++) {
+ mb_disc_unix_read_isrc(fd, disc, i);
+ }
+ }
+
+ close(fd);
+
+ return 1;
+}
+/* EOF */
diff --git a/Src/external_dependencies/libdiscid-0.6.2/src/unix.h b/Src/external_dependencies/libdiscid-0.6.2/src/unix.h
new file mode 100644
index 00000000..b6a059fc
--- /dev/null
+++ b/Src/external_dependencies/libdiscid-0.6.2/src/unix.h
@@ -0,0 +1,103 @@
+/* --------------------------------------------------------------------------
+
+ MusicBrainz -- The Internet music metadatabase
+
+ Copyright (C) 2013 Johannes Dewender
+
+ 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
+
+--------------------------------------------------------------------------- */
+
+#include "discid/discid_private.h"
+
+
+/*
+ * required functions
+ * ------------------
+ */
+
+/*
+ * Read the TOC header from disc
+ *
+ * THIS FUNCTION HAS TO BE IMPLEMENTED FOR THE PLATFORM
+ */
+LIBDISCID_INTERNAL int mb_disc_unix_read_toc_header(int fd, mb_disc_toc *toc);
+
+/*
+ * Read a TOC entry for a certain track from disc
+ *
+ * THIS FUNCTION HAS TO BE IMPLEMENTED FOR THE PLATFORM
+ */
+LIBDISCID_INTERNAL int mb_disc_unix_read_toc_entry(int fd, int track_num,
+ mb_disc_toc_track *track);
+
+/*
+ * Read the MCN from the disc
+ *
+ * THIS FUNCTION HAS TO BE IMPLEMENTED FOR THE PLATFORM
+ */
+LIBDISCID_INTERNAL void mb_disc_unix_read_mcn(int fd, mb_disc_private *disc);
+
+/*
+ * Read the ISRC for a certain track from disc
+ *
+ * THIS FUNCTION HAS TO BE IMPLEMENTED FOR THE PLATFORM
+ */
+LIBDISCID_INTERNAL void mb_disc_unix_read_isrc(int fd, mb_disc_private *disc,
+ int track_num);
+
+
+/*
+ * provided functions
+ * ------------------
+ */
+
+/*
+ * This function is implemented in unix.c and can be used
+ * for most platforms to implement mb_disc_read_unportable
+ * after the above functions are implemented on the platform.
+ * Returns 1 on success and 0 on failure.
+ */
+LIBDISCID_INTERNAL int mb_disc_unix_read(mb_disc_private *disc,
+ const char *device, unsigned int features);
+
+/*
+ * This function is implemented in unix.c and can be used
+ * after the above functions are implemented on the platform.
+ * This uses mb_disc_unix_read_toc_* and adds some error checking.
+ * Returns 1 on success and 0 on failure.
+ */
+LIBDISCID_INTERNAL int mb_disc_unix_read_toc(int fd, mb_disc_private *disc,
+ mb_disc_toc *toc);
+
+/*
+ * utility function to find an existing device from a candidate list
+ */
+LIBDISCID_INTERNAL int mb_disc_unix_exists(const char *device);
+
+/*
+ * utility function to find an existing device from a candidate list
+ */
+LIBDISCID_INTERNAL char *mb_disc_unix_find_device(char *candidates[],
+ int num_candidates);
+
+/*
+ * utility function to try opening the device with open()
+ * returns a non-negative file descriptor on success.
+ * On failure a negative integer is returned and error_msg filled
+ * with an appropriate string.
+ */
+LIBDISCID_INTERNAL int mb_disc_unix_open(mb_disc_private *disc,
+ const char *device);