Compare commits

..

No commits in common. "9c7f91496c56738fd707905f257643b792c05bb9" and "78cbcc9582cdc02fbe7e12b0b05787170f6a75b6" have entirely different histories.

21 changed files with 3652 additions and 4 deletions

View File

@ -16,10 +16,6 @@ Building of the Winamp desktop client is currently based around Visual Studio 20
### Dependencies ### Dependencies
#### libdiscid
We take libdiscid from https://github.com/metabrainz/libdiscid/tree/v0.6.2, copy it in /Src/external_dependencies/libdiscid-0.6.2/
#### libvpx #### libvpx
We take libvpx from [https://github.com/ShiftMediaProject/libvpx](https://github.com/ShiftMediaProject/libvpx), modify it, and pack it to archive. We take libvpx from [https://github.com/ShiftMediaProject/libvpx](https://github.com/ShiftMediaProject/libvpx), modify it, and pack it to archive.

View File

@ -0,0 +1,114 @@
libdiscid ChangeLog:
--------------------
libdiscid-0.6.2:
- ISRC and MCN support on BSD
- LIB-60: fix make check for default device on generic/unknown platform
- make Doxygen output reproducible (no timestamps)
- remove newline for Linux device "1" from proc
libdiscid-0.6.1:
- LIB-59: windows: fix bug preventing ISRC reads
libdiscid-0.6.0:
- LIB-41: add discid_get_troc_string() for fuzzy toc lookup
- LIB-54: add libmusicbrainz example with fuzzy toc lookup
- LIB-43: windows: the default drive is the first cd drive letter
- LIB-45: Linux/BSD/Solaris: try several possible default device names
- LIB-28: Mac: allow drive numbers as devices, default now "1"
- LIB-55, LIB-56: allow drive numbers for Windows and Linux
- LIB-53: discid_get_submission_url() returns the new NGS url
currently no functional change, the old url was redirected
- LIB-52: more validation for parameters of discid_put()
- LIB-48: assert successful read/put when API is used
- the discisrc example prints the name of the device used
libdiscid-0.5.2:
- LIB-51: fix ISRC reading on Mac OS X again
- LIB-50: fix segfault in mb_disc_load_toc on Solaris
- LIB-26: add a better test suite, including valgrind memcheck target
- print time information in the discid example
libdiscid-0.5.1:
- LIB-40: discid_get_webservice_url() (web service version 1) is deprecated
please use libmusicbrainz to gather metadata by disc ID
- LIB-7: rewrote data track handling, releases with multiple data tracks
This also fixes LIB-18 (no ID for DVDs) and LIB-9 (PS/PS2 CDs)
- LIB-44: fix invalid disc IDs on first read of multi-session discs
- LIB-37: Autotools optimization (non-recursive build etc.)
- LIB-42: remove Windows 9x platform code
- renamed openbsd platform code to netbsd, still used by both.
libdiscid-0.5.0:
- LIB-29: add read_sparse() for faster reading again
- LIB-35: add HAVE_SPARSE_READ and VERSION_* defines
- LIB-36: hide internal symbols on Linux/Unix
- LIB-34: distmac and distwin32 cmake targets
libdiscid-0.4.1:
- fix distribution: include disc_generic.c in Autotools dist
libdiscid-0.4.0:
- LIB-23: add has_feature() and get_feature_list() to API (platform check)
- add get_version_string() to API
- CMake : add FreeBSD, NetBSD, OpenBSD -> all platforms supported
- LIB-24: support generic platform (discid_put() only)
- Win32 : Added versioninfo resource to DLL
- LIB-32: change libtool from -version-info to -version-name
- LIB-27: fix (k)FreeBSD includes
- fix lots of compiler warnings
libdiscid-0.3.2:
- fix distribution so it works for autotools AND cmake
libdiscid-0.3.1:
- ISRC and MCN support on Linux
- Autotools: fix Windows, remove unneeded libs on SunOS
- CMake: add Cygwin, add SunOS, fix Mac OS X
- updated docs, created INSTALL file
libdiscid-0.3.0:
- Fixed reading of 99 track CDs on Mac OS X.
- Added API for reading ISRCs and MCNs (implemented on Windows and Mac OS X).
- Added Solaris, OpenBSD and kFreeBSD support.
libdiscid-0.2.2:
- Set libtool version number to 2:1:2 because it is backwards compatible
with versions 0.1.x. Thanks to Luks for spotting this.
libdiscid-0.2.1:
- Added code for automatic CD drive detection on darwin (Rob).
libdiscid-0.2.0:
- Use accurate TOC reading method for multi-session CDs on
Windows NT/2000/XP (Lukas).
- Replace custom MSVC makefile with CMake build system (Lukas).
- Added support for FreeBSD (Patrick Hurrelmann).
- Addded the discid_get_webservice_url() function (Rob).
libdiscid-0.1.1:
- Use generic 'cdaudio' device name on windows (Lukas).
libdiscid-0.1.0:
- Initial public release.

View File

@ -0,0 +1,30 @@
A Library for creating MusicBrainz DiscIDs
------------------------------------------
libdiscid is a C library for creating MusicBrainz DiscIDs from audio CDs.
It reads a CD's table of contents (TOC) and generates an identifier which
can be used to lookup the CD at MusicBrainz (http://musicbrainz.org).
Additionally, it provides a submission URL for adding the DiscID to the
database.
The library also provides FreeDB disc IDs, and MCN + ISRCs, if available.
The interface of this library is new, but the DiscID algorithm and the
operating system dependent CD-ROM/DVD-ROM access code have been ported
from libmusicbrainz version 2.
Please report all bugs you find via the MusicBrainz bug tracker.
Don't forget to state which OS and what version you are using:
http://tickets.musicbrainz.org/browse/LIB
Questions about this package may be posted to the MusicBrainz
development mailing list (mb-devel):
http://musicbrainz.org/doc/Communication/Mailing_Lists
More information can be found at the package's official homepage:
http://musicbrainz.org/doc/libdiscid

View File

@ -0,0 +1,486 @@
/* --------------------------------------------------------------------------
MusicBrainz -- The Internet music metadatabase
Copyright (C) 2013 Johannes Dewender
Copyright (C) 2006-2010 Lukas Lalinsky
Copyright (C) 2006 Matthias Friedrich
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
--------------------------------------------------------------------------- */
#ifndef MUSICBRAINZ_DISC_ID_H
#define MUSICBRAINZ_DISC_ID_H
#if (defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__))
# ifdef libdiscid_EXPORTS
# define LIBDISCID_API __declspec(dllexport)
# else
# define LIBDISCID_API __declspec(dllimport)
# endif
# define LIBDISCID_INTERNAL
#elif (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
# define LIBDISCID_API
# define LIBDISCID_INTERNAL __attribute__((visibility("hidden")))
#elif defined(__SUNPRO_C)
# define LIBDISCID_API __global
# define LIBDISCID_INTERNAL __hidden
#else
# define LIBDISCID_API
# define LIBDISCID_INTERNAL
#endif
#if (defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__))
#define LIBDISCID_DEPRECATED __declspec(deprecated)
#elif (defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))) || defined(__clang__)
#define LIBDISCID_DEPRECATED __attribute__((deprecated))
#else
#define LIBDISCID_DEPRECATED
#endif
#define DISCID_VERSION_MAJOR @libdiscid_MAJOR@
#define DISCID_VERSION_MINOR @libdiscid_MINOR@
#define DISCID_VERSION_PATCH @libdiscid_PATCH@
#define DISCID_VERSION_NUM @libdiscid_VERSION_NUM@
#ifdef __cplusplus
extern "C" {
#endif
/*!
* \mainpage libdiscid
* \section intro Introduction
*
* Libdiscid is a C library for calculating DiscIDs
* (<a href="http://musicbrainz.org/doc/Disc ID">MusicBrainz</a>
* and <a href="http://freedb.org">freedb</a>)
* for Audio CDs.
* Additionally the library can extract the MCN/UPC/EAN and the
* <a href="http://musicbrainz.org/doc/ISRC">ISRCs</a> from disc.
*
* The idea is to have an easy to use library without any dependencies
* that can be used from scripting languages.
*
* The API is documented in discid.h.
*
* \section examples Examples
*
* This is an example of the most basic usage:
*
* \code
*
* DiscId *disc = discid_new();
*
* if ( discid_read_sparse(disc, "/dev/cdrom", 0) == 0 ) {
* fprintf(stderr, "Error: %s\n", discid_get_error_msg(disc));
* return 1;
* }
*
* printf("DiscID : %s\n", discid_get_id(disc));
* printf("Submit via : %s\n", discid_get_submission_url(disc));
*
* discid_free(disc);
*
* \endcode
*
* \section Building
*
* libdiscid provides a pkg-config script that returns the necessary compiler and linker flags, as well as the
* version number. To build a small sample program one would use:
*
* @par
* <tt>gcc libdiscid-test.c \`pkg-config libdiscid --cflags --libs\` -o libdiscid-test</tt>
*
* \section Contact
*
* - <a href="http://lists.musicbrainz.org/mailman/listinfo/musicbrainz-devel">MusicBrainz Development Mailing List</a>
* - <a href="http://tickets.musicbrainz.org/browse/LIB">MusicBrainz Bug Tracker</a>
* - <a href="http://musicbrainz.org/doc/libdiscid">MusicBrainz Documentation</a>
* - <a href="https://github.com/metabrainz/libdiscid">Github Repository</a>
*
*/
/**
* A transparent handle for an Audio CD.
*
* This is returned by discid_new() and has to be passed as the first
* parameter to all discid_*() functions.
*/
typedef void *DiscId;
/**
* Return a handle for a new DiscId object.
*
* If no memory could be allocated, NULL is returned. Don't use the created
* DiscId object before calling discid_read() or discid_put().
*
* @return a DiscId object, or NULL.
*/
LIBDISCID_API DiscId *discid_new();
/**
* Release the memory allocated for the DiscId object.
*
* @param d a DiscId object created by discid_new()
*/
LIBDISCID_API void discid_free(DiscId *d);
/**
* Read all supported features of the disc in the given CD-ROM/DVD-ROM drive.
*
* This function reads the disc in the drive specified by the given device
* identifier. If the device is NULL, the default drive, as returned by
* discid_get_default_device() is used.
*
* If you do not require all features provided by libdiscid, such as MCN
* or ISRC reading, you should consider using discid_read_sparse() instead
* of discid_read() for performance reasons.
*
* On error, this function returns false and sets the error message which you
* can access using discid_get_error_msg(). In this case, the other functions
* won't return meaningful values and should not be used.
*
* This function may be used multiple times with the same DiscId object.
*
* @param d a DiscId object created by discid_new()
* @param device an operating system dependent device identifier, or NULL
* @return true if successful, or false on error.
*/
LIBDISCID_API int discid_read(DiscId *d, const char *device);
/**
* Read the disc in the given CD-ROM/DVD-ROM drive
* extracting only the TOC and additionally specified features.
*
* This function will always read the TOC, but additional features
* like ::DISCID_FEATURE_MCN and ::DISCID_FEATURE_ISRC can be set
* using the features parameter.
* Multiple features can be set using bitwise OR.
*
* If you only want to generate a disc ID, you only need the TOC,
* so set features to 0:
* \code
* discid_read_sparse(disc, device, 0)
* \endcode
* This is a bit more verbose, but equivalent since ::DISCID_FEATURE_READ
* is always implied:
* \code
* discid_read_sparse(disc, device, DISCID_FEATURE_READ)
* \endcode
*
* If you want to read all features available, you can use discid_read().
*
* On error, this function returns false and sets the error message which you
* can access using discid_get_error_msg(). In this case, the other functions
* won't return meaningful values and should not be used.
*
* This function may be used multiple times with the same DiscId object.
*
* \since libdiscid 0.5.0
*
* @param d a DiscId object created by discid_new()
* @param device an operating system dependent device identifier, or NULL
* @param features a list of bit flags from the enum ::discid_feature
* @return true if successful, or false on error.
*/
LIBDISCID_API int discid_read_sparse(DiscId *d, const char *device,
unsigned int features);
#define DISCID_HAVE_SPARSE_READ
/**
* Provides the TOC of a known CD.
*
* This function may be used if the TOC has been read earlier and you
* want to calculate the disc ID afterwards, without accessing the disc
* drive. It replaces the discid_read function in this case.
*
* On error, this function returns false and sets the error message which you
* can access using discid_get_error_msg(). In this case, the other functions
* won't return meaningful values and should not be used.
*
* The offsets parameter points to an array which contains the track offsets
* for each track. The first element, offsets[0], is the leadout track. It
* must contain the total number of sectors on the disc.
*
* For discs with additional data tracks, the trailing data tracks
* should be ignored. offset[0] should then be the last sector of the last
* audio track.
* Make sure the length of the last audio track as returned by libdiscid
* after a put is the same as the length of your last audio track.
* Depending on your tools you might need to substract 11400 (2:32 min.).
* See also:
* <a href="http://musicbrainz.org/doc/Disc_ID_Calculation">Disc ID Calculation</a>
*
*
* @param d a DiscID object created by discid_new()
* @param first the number of the first audio track on disc (usually one)
* @param last the number of the last audio track on the disc
* @param offsets a pointer to an array of 100 track offsets
* @return true if the given data was valid, and false on error
*/
LIBDISCID_API int discid_put(DiscId *d, int first, int last, int *offsets);
/**
* Return a human-readable error message.
*
* This function may only be used if discid_read() failed. The returned
* error message is only valid as long as the DiscId object exists.
*
* @param d a DiscId object created by discid_new()
* @return a string describing the error that occurred
*/
LIBDISCID_API char *discid_get_error_msg(DiscId *d);
/**
* Return a MusicBrainz DiscID.
*
* The returned string is only valid as long as the DiscId object exists.
*
* @param d a DiscId object created by discid_new()
* @return a string containing a MusicBrainz DiscID
*/
LIBDISCID_API char *discid_get_id(DiscId *d);
/**
* Return a FreeDB DiscID.
*
* The returned string is only valid as long as the DiscId object exists.
*
* @param d a DiscId object created by discid_new()
* @return a string containing a FreeDB DiscID
*/
LIBDISCID_API char *discid_get_freedb_id(DiscId *d);
/**
* Return a string representing CD Table Of Contents (TOC).
*
* The string has following values separated by space:
* first track number
* last track number
* total length in sectors
* offset of 1st track
* offset of 2nd track
* ...
*
* Example:
* 1 7 164900 150 22460 50197 80614 100828 133318 144712
*
* The returned string is only valid as long as the DiscId object exists.
*
* @param d a DiscId object created by discid_new()
* @return a string containing TOC information
*/
LIBDISCID_API char *discid_get_toc_string(DiscId *d);
/**
* Return an URL for submitting the DiscID to MusicBrainz.
*
* The URL leads to an interactive disc submission wizard that guides the
* user through the process of associating this disc's DiscID with a
* release in the MusicBrainz database.
*
* The returned string is only valid as long as the DiscId object exists.
*
* @param d a DiscId object created by discid_new()
* @return a string containing an URL
*/
LIBDISCID_API char *discid_get_submission_url(DiscId *d);
/**
* Return an URL for retrieving CD information from MusicBrainz' web service
*
* The URL provides the CD information in XML.
* See http://musicbrainz.org/development/mmd for details.
*
* The returned string is only valid as long as the DiscId object exists.
*
* @param d a DiscId object created by discid_new()
* @return a string containing an URL
*
* @deprecated This function is deprecated. Please use libmusicbrainz instead
* since this function returns an URL referring the deprecated webservice.
*/
LIBDISCID_API LIBDISCID_DEPRECATED char *discid_get_webservice_url(DiscId *d);
/**
* Return the name of the default disc drive for this machine.
* This isn't constant, but possibly depends on the drives currently
* attached, depending on the platform.
* For this reason you should call this once and save it
* when you want to make sure to use the same drive for
* multiple operations.
*
* The returned string is thread local and owned by libdiscid internally.
*
* @return a string containing an operating system dependent device identifier
*/
LIBDISCID_API char *discid_get_default_device(void);
/**
* Return the number of the first track on this disc.
*
* @param d a DiscId object created by discid_new()
* @return the number of the first track
*/
LIBDISCID_API int discid_get_first_track_num(DiscId *d);
/**
* Return the number of the last audio track on this disc.
*
* @param d a DiscId object created by discid_new()
* @return the number of the last track
*/
LIBDISCID_API int discid_get_last_track_num(DiscId *d);
/**
* Return the length of the disc in sectors.
*
* @param d a DiscId object created by discid_new()
* @return the length of the disc in sectors
*/
LIBDISCID_API int discid_get_sectors(DiscId *d);
/**
* Return the sector offset of a track.
*
* Only track numbers between (and including) discid_get_first_track_num()
* and discid_get_last_track_num() may be used.
*
* @param d a DiscId object created by discid_new()
* @param track_num the number of a track
* @return sector offset of the specified track
*/
LIBDISCID_API int discid_get_track_offset(DiscId *d, int track_num);
/**
* Return the length of a track in sectors.
*
* Only track numbers between (and including) discid_get_first_track_num()
* and discid_get_last_track_num() may be used.
*
* @param d a DiscId object created by discid_new()
* @param track_num the number of a track
* @return length of the specified track
*/
LIBDISCID_API int discid_get_track_length(DiscId *d, int track_num);
/**
* Return the Media Catalogue Number (MCN) for the disc.
*
* This is essentially an EAN (= UPC with 0 prefix).
*
* \since libdiscid 0.3.0
*
* @param d a DiscId object created by discid_new()
* @return a string containing an Media Catalogue Number of the disk
*/
LIBDISCID_API char* discid_get_mcn(DiscId *d);
/**
* Return the ISRC for a track.
*
* Only track numbers between (and including) discid_get_first_track_num()
* and discid_get_last_track_num() may be used.
*
* \since libdiscid 0.3.0
*
* @param d a DiscId object created by discid_new()
* @param track_num the number of a track
* @return a string containing an ISRC for the specified track
*/
LIBDISCID_API char* discid_get_track_isrc(DiscId *d, int track_num);
/**
* PLATFORM-DEPENDENT FEATURES
*
* The platform dependent features are currently:
* - "read" read TOC from disc
* - "mcn" read MCN from disc
* - "isrc" read ISRC from disc
*
* A table in the
* <a href="http://musicbrainz.org/doc/libdiscid">MusicBrainz Documentation</a>
* specifies which features are available on which platform in what version.
*
* In the code you can use discid_get_feature_list() or discid_has_feature()
* below to get the features for your platform in this version.
*/
enum discid_feature {
DISCID_FEATURE_READ = 1 << 0,
DISCID_FEATURE_MCN = 1 << 1,
DISCID_FEATURE_ISRC = 1 << 2,
};
/**
* Check if a certain feature is implemented on the current platform.
*
* This only works for single features, not bit masks with multiple features.
*
* \since libdiscid 0.4.0
*
* @param feature as enum ::discid_feature
* @return 1 if the feature is implemented and 0 if not.
*/
LIBDISCID_API int discid_has_feature(enum discid_feature feature);
#define DISCID_FEATURE_STR_READ "read"
#define DISCID_FEATURE_STR_MCN "mcn"
#define DISCID_FEATURE_STR_ISRC "isrc"
#define DISCID_FEATURE_LENGTH 32
/**
* Return a list of features supported by the current platform.
* The array of length ::DISCID_FEATURE_LENGTH should be allocated by the user.
* After the call each element of the array is either NULL
* or a pointer to a static string.
*
* \since libdiscid 0.4.0
*
* @param[out] features a static string array of length ::DISCID_FEATURE_LENGTH
*/
LIBDISCID_API void discid_get_feature_list(
char *features[DISCID_FEATURE_LENGTH]);
/**
* Return the full version string of this library, including the name.
* This can be used for debug output.
* Don't use this to test for features, see discid_has_feature().
*
* \since libdiscid 0.4.0
*
* @return a string containing the version of libdiscid.
*/
LIBDISCID_API char *discid_get_version_string(void);
#ifdef __cplusplus
}
#endif
#endif /* MUSICBRAINZ_DISC_ID_H */

View File

@ -0,0 +1,139 @@
/* --------------------------------------------------------------------------
MusicBrainz -- The Internet music metadatabase
Copyright (C) 2006 Matthias Friedrich
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$
--------------------------------------------------------------------------- */
/*
* For internal use only. This header file is not installed.
*/
#ifndef MUSICBRAINZ_DISC_ID_PRIVATE_H
#define MUSICBRAINZ_DISC_ID_PRIVATE_H
#include "discid/discid.h"
/* Length of toc string, "xxx+xxx" + 100 tracks 7 bytes each ("+xxxxxx")
* The highest possible offset is 90 minutes * 60 seconds/minute * 75 frames/second = 405000.
* That is 6 digits plus one plus sign = 7 characters per track.
* So 3 + 3 (first and last) + 100*7 (disc length plus 99 tracks) = 706
*/
#define MB_TOC_STRING_LENGTH (3 + 3 + 100*7)
/* Length of a MusicBrainz DiscID in bytes (without a trailing '\0'-byte). */
#define MB_DISC_ID_LENGTH 32
/* Length of a FreeDB DiscID in bytes (without a trailing '\0'-byte). */
#define FREEDB_DISC_ID_LENGTH 8
/* The maximum permitted length for an error message (without the '\0'-byte). */
#define MB_ERROR_MSG_LENGTH 255
/* Length of url prefixes */
#define MB_URL_PREFIX_LENGTH 300
/* Maximum length of any url (including query string) */
#define MB_MAX_URL_LENGTH (MB_URL_PREFIX_LENGTH + MB_DISC_ID_LENGTH + MB_TOC_STRING_LENGTH)
/* The URL that can be used for submitting DiscIDs (no parameters yet) */
#define MB_SUBMISSION_URL "http://musicbrainz.org/cdtoc/attach"
/* The URL that can be used for retrieving XML for a CD */
#define MB_WEBSERVICE_URL "http://musicbrainz.org/ws/1/release"
/* Maximum length of a Media Catalogue Number string */
#define MCN_STR_LENGTH 13
/* Maximum length of a ISRC code string */
#define ISRC_STR_LENGTH 12
/* Maximum disc length in frames/sectors
* This is already not according to spec, but many players might still work
* Spec is 79:59.75 = 360000 + lead-in + lead-out */
#define MAX_DISC_LENGTH (90 * 60 * 75)
/*
* This data structure represents an audio disc.
*
* We use fixed length strings here because that way the user doesn't have to
* check for memory exhaustion conditions. As soon as the mb_disc object has
* been created, all calls returning strings will be successful.
*/
typedef struct {
int first_track_num;
int last_track_num;
int track_offsets[100];
char id[MB_DISC_ID_LENGTH+1];
char freedb_id[FREEDB_DISC_ID_LENGTH+1];
char submission_url[MB_MAX_URL_LENGTH+1];
char webservice_url[MB_MAX_URL_LENGTH+1];
char toc_string[MB_TOC_STRING_LENGTH+1];
char error_msg[MB_ERROR_MSG_LENGTH+1];
char isrc[100][ISRC_STR_LENGTH+1];
char mcn[MCN_STR_LENGTH+1];
int success;
} mb_disc_private;
typedef struct {
int control;
int address;
} mb_disc_toc_track;
typedef struct {
int first_track_num;
int last_track_num;
mb_disc_toc_track tracks[100];
} mb_disc_toc;
/*
* This function has to be implemented once per operating system.
*
* The caller guarantees that both the disc and device parameters are
* not NULL.
*
* Implementors have to set mb_disc_private's first_track_num, last_track_num,
* and track_offsets attributes. If there is an error, the error_msg attribute
* has to be set to a human-readable error message.
*
* On error, 0 is returned. On success, 1 is returned.
*/
LIBDISCID_INTERNAL int mb_disc_read_unportable(mb_disc_private *disc, const char *device, unsigned int features);
/*
* This should return the name of the default/preferred CDROM/DVD device
* on this operating system. It has to be in a format usable for the second
* parameter of mb_disc_read_unportable().
*/
LIBDISCID_INTERNAL char *mb_disc_get_default_device_unportable(void);
/*
* This should return 1 if the feature is supported by the platform
* and 0 if not.
*/
LIBDISCID_INTERNAL int mb_disc_has_feature_unportable(enum discid_feature feature);
/*
* Load data to the mb_disc_private structure based on mb_disc_toc.
*
* On error, 0 is returned. On success, 1 is returned.
*/
LIBDISCID_INTERNAL int mb_disc_load_toc(mb_disc_private *disc, mb_disc_toc *toc);
#endif /* MUSICBRAINZ_DISC_ID_PRIVATE_H */

View File

@ -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 */
}

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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);
}
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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);
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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);

Binary file not shown.