disc_win32.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /* --------------------------------------------------------------------------
  2. MusicBrainz -- The Internet music metadatabase
  3. Copyright (C) 2007-2008 Lukas Lalinsky
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with this library; if not, write to the Free Software
  14. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  15. ----------------------------------------------------------------------------*/
  16. #ifdef _MSC_VER
  17. #define _CRT_SECURE_NO_WARNINGS
  18. #if (_MSC_VER < 1900)
  19. #define snprintf _snprintf
  20. #endif
  21. #endif
  22. #include <windows.h>
  23. #include <string.h>
  24. #include <stdio.h>
  25. #if defined(__CYGWIN__)
  26. #include <ntddcdrm.h>
  27. #elif defined(__MINGW32__)
  28. #include <ddk/ntddcdrm.h>
  29. #else
  30. #include "ntddcdrm.h"
  31. #endif
  32. #include "discid/discid.h"
  33. #include "discid/discid_private.h"
  34. #define MB_DEFAULT_DEVICE "D:"
  35. #define MAX_DEV_LEN 3
  36. #if defined(_MSC_VER)
  37. # define THREAD_LOCAL __declspec(thread)
  38. #elif (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
  39. # define THREAD_LOCAL __thread
  40. #else
  41. # define THREAD_LOCAL
  42. #endif
  43. static THREAD_LOCAL char default_device[MAX_DEV_LEN] = "\0";
  44. static int address_to_sectors(UCHAR address[4]) {
  45. return address[1] * 4500 + address[2] * 75 + address[3];
  46. }
  47. static HANDLE create_device_handle(mb_disc_private *disc, const char *device) {
  48. HANDLE hDevice;
  49. char filename[128];
  50. const char* colon;
  51. size_t len;
  52. strcpy(filename, "\\\\.\\");
  53. len = strlen(device);
  54. colon = strchr(device, ':');
  55. if (colon) {
  56. len = colon - device + 1;
  57. }
  58. strncat(filename, device, len > 120 ? 120 : len);
  59. hDevice = CreateFile(filename, GENERIC_READ,
  60. FILE_SHARE_READ | FILE_SHARE_WRITE,
  61. NULL, OPEN_EXISTING, 0, NULL);
  62. if (hDevice == INVALID_HANDLE_VALUE) {
  63. snprintf(disc->error_msg, MB_ERROR_MSG_LENGTH,
  64. "cannot open the CD audio device '%s'", device);
  65. return 0;
  66. }
  67. return hDevice;
  68. }
  69. static void read_disc_mcn(HANDLE hDevice, mb_disc_private *disc) {
  70. DWORD dwReturned;
  71. BOOL bResult;
  72. CDROM_SUB_Q_DATA_FORMAT format;
  73. SUB_Q_CHANNEL_DATA data;
  74. format.Track = 0;
  75. format.Format = IOCTL_CDROM_MEDIA_CATALOG;
  76. bResult = DeviceIoControl(hDevice, IOCTL_CDROM_READ_Q_CHANNEL,
  77. &format, sizeof(format),
  78. &data, sizeof(data),
  79. &dwReturned, NULL);
  80. if (bResult == FALSE) {
  81. fprintf(stderr, "Warning: Unable to read the disc's media catalog number.\n");
  82. } else {
  83. strncpy(disc->mcn, (char *) data.MediaCatalog.MediaCatalog,
  84. MCN_STR_LENGTH);
  85. }
  86. }
  87. static void read_disc_isrc(HANDLE hDevice, mb_disc_private *disc, int track) {
  88. DWORD dwReturned;
  89. BOOL bResult;
  90. CDROM_SUB_Q_DATA_FORMAT format;
  91. SUB_Q_CHANNEL_DATA data;
  92. format.Track = track;
  93. format.Format = IOCTL_CDROM_TRACK_ISRC;
  94. bResult = DeviceIoControl(hDevice, IOCTL_CDROM_READ_Q_CHANNEL,
  95. &format, sizeof(format),
  96. &data, sizeof(data),
  97. &dwReturned, NULL);
  98. if (bResult == FALSE) {
  99. fprintf(stderr, "Warning: Unable to read the international standard recording code (ISRC) for track %i\n", track);
  100. } else {
  101. strncpy(disc->isrc[track], (char *) data.TrackIsrc.TrackIsrc,
  102. ISRC_STR_LENGTH);
  103. }
  104. }
  105. static int get_nth_device(int number, char* device, int device_length) {
  106. int i, counter = 0;
  107. char tmpDevice[MAX_DEV_LEN];
  108. DWORD mask = GetLogicalDrives();
  109. for (i = 0; i <= 25; i++) {
  110. if (mask >> i & 1) {
  111. snprintf(tmpDevice, MAX_DEV_LEN, "%c:", i + 'A');
  112. if (GetDriveType(tmpDevice) == DRIVE_CDROM) {
  113. counter++;
  114. if (counter == number) {
  115. strncpy(device, tmpDevice, device_length);
  116. return TRUE;
  117. }
  118. }
  119. }
  120. }
  121. return FALSE;
  122. }
  123. char *mb_disc_get_default_device_unportable(void) {
  124. if (!get_nth_device(1, default_device, MAX_DEV_LEN)) {
  125. return MB_DEFAULT_DEVICE;
  126. }
  127. return default_device;
  128. }
  129. int mb_disc_has_feature_unportable(enum discid_feature feature) {
  130. switch(feature) {
  131. case DISCID_FEATURE_READ:
  132. case DISCID_FEATURE_MCN:
  133. case DISCID_FEATURE_ISRC:
  134. return 1;
  135. default:
  136. return 0;
  137. }
  138. }
  139. static int mb_disc_winnt_read_toc(HANDLE device, mb_disc_private *disc, mb_disc_toc *toc) {
  140. DWORD dwReturned;
  141. BOOL bResult;
  142. CDROM_TOC cd;
  143. int i;
  144. bResult = DeviceIoControl(device, IOCTL_CDROM_READ_TOC,
  145. NULL, 0,
  146. &cd, sizeof(cd),
  147. &dwReturned, NULL);
  148. if (bResult == FALSE) {
  149. snprintf(disc->error_msg, MB_ERROR_MSG_LENGTH,
  150. "error while reading the CD TOC");
  151. return 0;
  152. }
  153. toc->first_track_num = cd.FirstTrack;
  154. toc->last_track_num = cd.LastTrack;
  155. /* Get info about all tracks */
  156. for (i = toc->first_track_num; i <= toc->last_track_num; i++) {
  157. toc->tracks[i].address = address_to_sectors(cd.TrackData[i - 1].Address) - 150;
  158. toc->tracks[i].control = cd.TrackData[i - 1].Control;
  159. }
  160. /* Lead-out is stored after the last track */
  161. toc->tracks[0].address = address_to_sectors(cd.TrackData[toc->last_track_num].Address) - 150;
  162. toc->tracks[0].control = cd.TrackData[toc->last_track_num].Control;
  163. return 1;
  164. }
  165. int mb_disc_read_unportable(mb_disc_private *disc, const char *device,
  166. unsigned int features) {
  167. mb_disc_toc toc;
  168. char tmpDevice[MAX_DEV_LEN];
  169. HANDLE hDevice;
  170. int i, device_number;
  171. device_number = (int) strtol(device, NULL, 10);
  172. if (device_number > 0) {
  173. if (!get_nth_device(device_number, tmpDevice, MAX_DEV_LEN)) {
  174. snprintf(disc->error_msg, MB_ERROR_MSG_LENGTH,
  175. "cannot find the CD audio device '%i'", device_number);
  176. return 0;
  177. }
  178. device = tmpDevice;
  179. }
  180. hDevice = create_device_handle(disc, device);
  181. if (hDevice == 0)
  182. return 0;
  183. if (!mb_disc_winnt_read_toc(hDevice, disc, &toc)) {
  184. CloseHandle(hDevice);
  185. return 0;
  186. }
  187. if (!mb_disc_load_toc(disc, &toc)) {
  188. CloseHandle(hDevice);
  189. return 0;
  190. }
  191. if (features & DISCID_FEATURE_MCN) {
  192. read_disc_mcn(hDevice, disc);
  193. }
  194. for (i = disc->first_track_num; i <= disc->last_track_num; i++) {
  195. if (features & DISCID_FEATURE_ISRC) {
  196. read_disc_isrc(hDevice, disc, i);
  197. }
  198. }
  199. CloseHandle(hDevice);
  200. return 1;
  201. }
  202. /* EOF */