Compare commits
No commits in common. "9c7f91496c56738fd707905f257643b792c05bb9" and "78cbcc9582cdc02fbe7e12b0b05787170f6a75b6" have entirely different histories.
9c7f91496c
...
78cbcc9582
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
||||||
|
}
|
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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.
Loading…
Reference in New Issue