Fix the GLEXT function prototype typedefs detection.
[wine/dcerpc.git] / misc / cdrom.c
blob14a2ffe113ce394818ead65829b86c018dfa8a01
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3 * Main file for CD-ROM support
5 * Copyright 1994 Martin Ayotte
6 * Copyright 1999 Eric Pouech
7 * Copyright 2000 Andreas Mohr
8 */
10 #include "config.h"
12 #include <errno.h>
13 #include <string.h>
14 #include <fcntl.h>
15 #include <sys/ioctl.h>
16 #include "cdrom.h"
17 #include "drive.h"
18 #include "debugtools.h"
19 #include "winbase.h"
21 DEFAULT_DEBUG_CHANNEL(cdrom);
23 #define MAX_CDAUDIO_TRACKS 256
25 /**************************************************************************
26 * CDROM_Open [internal]
28 * drive = 0, 1, ...
29 * or -1 (figure it out)
31 int CDROM_Open(WINE_CDAUDIO* wcda, int drive)
33 int i;
34 BOOL avail = FALSE;
35 const char *dev;
37 if (drive == -1)
39 for (i=0; i < MAX_DOS_DRIVES; i++)
40 if (DRIVE_GetType(i) == TYPE_CDROM)
42 drive = i;
43 avail = TRUE;
44 break;
47 else
48 avail = TRUE;
50 if (avail == FALSE)
52 WARN("No CD-ROM #%d found !\n", drive);
53 return -1;
55 if ((dev = DRIVE_GetDevice(drive)) == NULL)
57 WARN("No device entry for CD-ROM #%d (drive %c:) found !\n",
58 drive, 'A' + drive);
59 return -1;
62 wcda->unixdev = open(dev, O_RDONLY | O_NONBLOCK, 0);
63 if (wcda->unixdev == -1) {
64 WARN("can't open '%s'!. %s\n", dev, strerror(errno));
65 return -1;
67 wcda->cdaMode = WINE_CDA_OPEN; /* to force reading tracks info */
68 wcda->nCurTrack = 0;
69 wcda->nTracks = 0;
70 wcda->dwFirstFrame = 0;
71 wcda->dwLastFrame = 0;
72 wcda->lpdwTrackLen = NULL;
73 wcda->lpdwTrackPos = NULL;
74 wcda->lpbTrackFlags = NULL;
75 return 0;
78 /**************************************************************************
79 * CDROM_GetMediaType [internal]
81 int CDROM_GetMediaType(WINE_CDAUDIO* wcda)
83 #ifdef linux
84 return ioctl(wcda->unixdev, CDROM_DISC_STATUS);
85 #else
86 return -1;
87 #endif
90 /**************************************************************************
91 * CDROM_Close [internal]
93 int CDROM_Close(WINE_CDAUDIO* wcda)
95 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
96 if (wcda->lpdwTrackLen != NULL) free(wcda->lpdwTrackLen);
97 if (wcda->lpdwTrackPos != NULL) free(wcda->lpdwTrackPos);
98 if (wcda->lpbTrackFlags != NULL) free(wcda->lpbTrackFlags);
99 close(wcda->unixdev);
100 return 0;
101 #else
102 return -1;
103 #endif
106 /**************************************************************************
107 * CDROM_Get_UPC [internal]
109 * upc has to be 14 bytes long
111 int CDROM_Get_UPC(WINE_CDAUDIO* wcda, LPSTR upc)
113 #ifdef linux
114 struct cdrom_mcn mcn;
115 int status = ioctl(wcda->unixdev, CDROM_GET_MCN, &mcn);
116 if (status)
118 ERR("ioctl() failed with code %d\n",status);
119 return -1;
121 strcpy(upc, mcn.medium_catalog_number);
122 return 0;
123 #else
124 return -1;
125 #endif
128 /**************************************************************************
129 * CDROM_Audio_GetNumberOfTracks [internal]
131 UINT16 CDROM_Audio_GetNumberOfTracks(WINE_CDAUDIO* wcda)
133 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
134 #ifdef linux
135 struct cdrom_tochdr hdr;
136 #else
137 struct ioc_toc_header hdr;
138 #endif
140 if (wcda->nTracks == 0) {
141 #ifdef linux
142 if (ioctl(wcda->unixdev, CDROMREADTOCHDR, &hdr))
143 #else
144 if (ioctl(wcda->unixdev, CDIOREADTOCHEADER, &hdr))
145 #endif
147 WARN("(%p) -- Error occurred (%d)!\n", wcda, errno);
148 return (WORD)-1;
150 #ifdef linux
151 wcda->nFirstTrack = hdr.cdth_trk0;
152 wcda->nLastTrack = hdr.cdth_trk1;
153 #else
154 wcda->nFirstTrack = hdr.starting_track;
155 wcda->nLastTrack = hdr.ending_track;
156 #endif
157 wcda->nTracks = wcda->nLastTrack - wcda->nFirstTrack + 1;
159 return wcda->nTracks;
160 #else
161 return (WORD)-1;
162 #endif
165 /**************************************************************************
166 * CDROM_Audio_GetTracksInfo [internal]
168 BOOL CDROM_Audio_GetTracksInfo(WINE_CDAUDIO* wcda)
170 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
171 int i, length;
172 int start, last_start = 0;
173 int total_length = 0;
174 #ifdef linux
175 struct cdrom_tocentry entry;
176 #else
177 struct ioc_read_toc_entry entry;
178 struct cd_toc_entry toc_buffer;
179 #endif
181 if (wcda->nTracks == 0) {
182 if (CDROM_Audio_GetNumberOfTracks(wcda) == (WORD)-1) return FALSE;
184 TRACE("nTracks=%u\n", wcda->nTracks);
186 if (wcda->lpdwTrackLen != NULL)
187 free(wcda->lpdwTrackLen);
188 wcda->lpdwTrackLen = (LPDWORD)malloc((wcda->nTracks + 1) * sizeof(DWORD));
189 if (wcda->lpdwTrackPos != NULL)
190 free(wcda->lpdwTrackPos);
191 wcda->lpdwTrackPos = (LPDWORD)malloc((wcda->nTracks + 1) * sizeof(DWORD));
192 if (wcda->lpbTrackFlags != NULL)
193 free(wcda->lpbTrackFlags);
194 wcda->lpbTrackFlags = (LPBYTE)malloc((wcda->nTracks + 1) * sizeof(BYTE));
195 if (wcda->lpdwTrackLen == NULL || wcda->lpdwTrackPos == NULL ||
196 wcda->lpbTrackFlags == NULL) {
197 WARN("error allocating track table !\n");
198 return FALSE;
200 memset(wcda->lpdwTrackLen, 0, (wcda->nTracks + 1) * sizeof(DWORD));
201 memset(wcda->lpdwTrackPos, 0, (wcda->nTracks + 1) * sizeof(DWORD));
202 memset(wcda->lpbTrackFlags, 0, (wcda->nTracks + 1) * sizeof(BYTE));
203 for (i = 0; i <= wcda->nTracks; i++) {
204 if (i == wcda->nTracks)
205 #ifdef linux
206 entry.cdte_track = CDROM_LEADOUT;
207 #else
208 #define LEADOUT 0xaa
209 entry.starting_track = LEADOUT; /* FIXME */
210 #endif
211 else
212 #ifdef linux
213 entry.cdte_track = i + 1;
214 #else
215 entry.starting_track = i + 1;
216 #endif
217 #ifdef linux
218 entry.cdte_format = CDROM_MSF;
219 #else
220 bzero((char *)&toc_buffer, sizeof(toc_buffer));
221 entry.address_format = CD_MSF_FORMAT;
222 entry.data_len = sizeof(toc_buffer);
223 entry.data = &toc_buffer;
224 #endif
225 #ifdef linux
226 if (ioctl(wcda->unixdev, CDROMREADTOCENTRY, &entry))
227 #else
228 if (ioctl(wcda->unixdev, CDIOREADTOCENTRYS, &entry))
229 #endif
231 WARN("error read entry (%s)\n", strerror(errno));
232 /* update status according to new status */
233 CDROM_Audio_GetCDStatus(wcda);
235 return FALSE;
237 #ifdef linux
238 start = CDFRAMES_PERSEC * (SECONDS_PERMIN *
239 entry.cdte_addr.msf.minute + entry.cdte_addr.msf.second) +
240 entry.cdte_addr.msf.frame;
241 #else
242 start = CDFRAMES_PERSEC * (SECONDS_PERMIN *
243 toc_buffer.addr.msf.minute + toc_buffer.addr.msf.second) +
244 toc_buffer.addr.msf.frame;
245 #endif
246 if (i == 0) {
247 last_start = start;
248 wcda->dwFirstFrame = start;
249 TRACE("dwFirstOffset=%u\n", start);
250 } else {
251 length = start - last_start;
252 last_start = start;
253 start = last_start - length;
254 total_length += length;
255 wcda->lpdwTrackLen[i - 1] = length;
256 wcda->lpdwTrackPos[i - 1] = start;
257 TRACE("track #%u start=%u len=%u\n", i, start, length);
259 #ifdef linux
260 wcda->lpbTrackFlags[i] =
261 (entry.cdte_adr << 4) | (entry.cdte_ctrl & 0x0f);
262 #else
263 wcda->lpbTrackFlags[i] =
264 (toc_buffer.addr_type << 4) | (toc_buffer.control & 0x0f);
265 #endif
266 TRACE("track #%u flags=%02x\n", i + 1, wcda->lpbTrackFlags[i]);
268 wcda->dwLastFrame = last_start;
269 TRACE("total_len=%u\n", total_length);
270 return TRUE;
271 #else
272 return FALSE;
273 #endif
276 /**************************************************************************
277 * CDROM_Audio_GetCDStatus [internal]
279 BOOL CDROM_Audio_GetCDStatus(WINE_CDAUDIO* wcda)
281 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
282 int oldmode = wcda->cdaMode;
283 #ifdef linux
284 wcda->sc.cdsc_format = CDROM_MSF;
285 #else
286 struct ioc_read_subchannel read_sc;
288 read_sc.address_format = CD_MSF_FORMAT;
289 read_sc.data_format = CD_CURRENT_POSITION;
290 read_sc.track = 0;
291 read_sc.data_len = sizeof(wcda->sc);
292 read_sc.data = (struct cd_sub_channel_info *)&wcda->sc;
293 #endif
294 #ifdef linux
295 if (ioctl(wcda->unixdev, CDROMSUBCHNL, &wcda->sc))
296 #else
297 if (ioctl(wcda->unixdev, CDIOCREADSUBCHANNEL, &read_sc))
298 #endif
300 TRACE("opened or no_media (%s)!\n", strerror(errno));
301 wcda->cdaMode = WINE_CDA_OPEN; /* was NOT_READY */
302 return TRUE;
304 switch (
305 #ifdef linux
306 wcda->sc.cdsc_audiostatus
307 #else
308 wcda->sc.header.audio_status
309 #endif
311 #ifdef linux
312 case CDROM_AUDIO_INVALID:
313 #else
314 case CD_AS_AUDIO_INVALID:
315 #endif
316 WARN("device doesn't support status.\n");
317 wcda->cdaMode = WINE_CDA_DONTKNOW;
318 break;
319 #ifdef linux
320 case CDROM_AUDIO_NO_STATUS:
321 #else
322 case CD_AS_NO_STATUS:
323 #endif
324 wcda->cdaMode = WINE_CDA_STOP;
325 TRACE("WINE_CDA_STOP !\n");
326 break;
327 #ifdef linux
328 case CDROM_AUDIO_PLAY:
329 #else
330 case CD_AS_PLAY_IN_PROGRESS:
331 #endif
332 wcda->cdaMode = WINE_CDA_PLAY;
333 break;
334 #ifdef linux
335 case CDROM_AUDIO_PAUSED:
336 #else
337 case CD_AS_PLAY_PAUSED:
338 #endif
339 wcda->cdaMode = WINE_CDA_PAUSE;
340 TRACE("WINE_CDA_PAUSE !\n");
341 break;
342 default:
343 #ifdef linux
344 TRACE("status=%02X !\n",
345 wcda->sc.cdsc_audiostatus);
346 #else
347 TRACE("status=%02X !\n",
348 wcda->sc.header.audio_status);
349 #endif
351 #ifdef linux
352 wcda->nCurTrack = wcda->sc.cdsc_trk;
353 wcda->dwCurFrame =
354 CDFRAMES_PERMIN * wcda->sc.cdsc_absaddr.msf.minute +
355 CDFRAMES_PERSEC * wcda->sc.cdsc_absaddr.msf.second +
356 wcda->sc.cdsc_absaddr.msf.frame;
357 #else
358 wcda->nCurTrack = wcda->sc.what.position.track_number;
359 wcda->dwCurFrame =
360 CDFRAMES_PERMIN * wcda->sc.what.position.absaddr.msf.minute +
361 CDFRAMES_PERSEC * wcda->sc.what.position.absaddr.msf.second +
362 wcda->sc.what.position.absaddr.msf.frame;
363 #endif
364 #ifdef linux
365 TRACE("%02u-%02u:%02u:%02u \n",
366 wcda->sc.cdsc_trk,
367 wcda->sc.cdsc_absaddr.msf.minute,
368 wcda->sc.cdsc_absaddr.msf.second,
369 wcda->sc.cdsc_absaddr.msf.frame);
370 #else
371 TRACE("%02u-%02u:%02u:%02u \n",
372 wcda->sc.what.position.track_number,
373 wcda->sc.what.position.absaddr.msf.minute,
374 wcda->sc.what.position.absaddr.msf.second,
375 wcda->sc.what.position.absaddr.msf.frame);
376 #endif
378 if (oldmode != wcda->cdaMode && oldmode == WINE_CDA_OPEN) {
379 if (!CDROM_Audio_GetTracksInfo(wcda)) {
380 WARN("error updating TracksInfo !\n");
381 return FALSE;
384 return TRUE;
385 #else
386 return FALSE;
387 #endif
390 /**************************************************************************
391 * CDROM_Audio_Play [internal]
393 int CDROM_Audio_Play(WINE_CDAUDIO* wcda, DWORD start, DWORD end)
395 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
396 #ifdef linux
397 struct cdrom_msf msf;
398 #else
399 struct ioc_play_msf msf;
400 #endif
402 #ifdef linux
403 msf.cdmsf_min0 = start / CDFRAMES_PERMIN;
404 msf.cdmsf_sec0 = (start % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
405 msf.cdmsf_frame0 = start % CDFRAMES_PERSEC;
406 msf.cdmsf_min1 = end / CDFRAMES_PERMIN;
407 msf.cdmsf_sec1 = (end % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
408 msf.cdmsf_frame1 = end % CDFRAMES_PERSEC;
409 #else
410 msf.start_m = start / CDFRAMES_PERMIN;
411 msf.start_s = (start % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
412 msf.start_f = start % CDFRAMES_PERSEC;
413 msf.end_m = end / CDFRAMES_PERMIN;
414 msf.end_s = (end % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
415 msf.end_f = end % CDFRAMES_PERSEC;
416 #endif
417 #ifdef linux
418 if (ioctl(wcda->unixdev, CDROMSTART))
419 #else
420 if (ioctl(wcda->unixdev, CDIOCSTART, NULL))
421 #endif
423 WARN("motor doesn't start !\n");
424 return -1;
426 #ifdef linux
427 if (ioctl(wcda->unixdev, CDROMPLAYMSF, &msf))
428 #else
429 if (ioctl(wcda->unixdev, CDIOCPLAYMSF, &msf))
430 #endif
432 WARN("device doesn't play !\n");
433 return -1;
435 #ifdef linux
436 TRACE("msf = %d:%d:%d %d:%d:%d\n",
437 msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0,
438 msf.cdmsf_min1, msf.cdmsf_sec1, msf.cdmsf_frame1);
439 #else
440 TRACE("msf = %d:%d:%d %d:%d:%d\n",
441 msf.start_m, msf.start_s, msf.start_f,
442 msf.end_m, msf.end_s, msf.end_f);
443 #endif
444 return 0;
445 #else
446 return -1;
447 #endif
450 /**************************************************************************
451 * CDROM_Audio_Stop [internal]
453 int CDROM_Audio_Stop(WINE_CDAUDIO* wcda)
455 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
456 int ret = 0;
457 #ifdef linux
458 ret = ioctl(wcda->unixdev, CDROMSTOP);
459 #else
460 ret = ioctl(wcda->unixdev, CDIOCSTOP, NULL);
461 #endif
462 return ret;
463 #else
464 return -1;
465 #endif
468 /**************************************************************************
469 * CDROM_Audio_Pause [internal]
471 int CDROM_Audio_Pause(WINE_CDAUDIO* wcda, int pauseOn)
473 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
474 int ret = 0;
475 #ifdef linux
476 ret = ioctl(wcda->unixdev, pauseOn ? CDROMPAUSE : CDROMRESUME);
477 #else
478 ret = ioctl(wcda->unixdev, pauseOn ? CDIOCPAUSE : CDIOCRESUME, NULL);
479 #endif
480 return ret;
481 #else
482 return -1;
483 #endif
486 /**************************************************************************
487 * CDROM_Audio_Seek [internal]
489 int CDROM_Audio_Seek(WINE_CDAUDIO* wcda, DWORD at)
491 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
492 int ret = 0;
493 #ifdef linux
494 struct cdrom_msf0 msf;
495 msf.minute = at / CDFRAMES_PERMIN;
496 msf.second = (at % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
497 msf.frame = at % CDFRAMES_PERSEC;
499 ret = ioctl(wcda->unixdev, CDROMSEEK, &msf);
500 #else
501 /* FIXME: the current end for play is lost
502 * use end of CD ROM instead
504 FIXME("Could a BSD expert implement the seek function ?\n");
505 CDROM_Audio_Play(wcda, at, wcda->lpdwTrackPos[wcda->nTracks] + wcda->lpdwTrackLen[wcda->nTracks]);
507 #endif
508 return ret;
509 #else
510 return -1;
511 #endif
514 /**************************************************************************
515 * CDROM_SetDoor [internal]
517 int CDROM_SetDoor(WINE_CDAUDIO* wcda, int open)
519 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
520 int ret = 0;
521 #ifdef linux
522 if (open) {
523 ret = ioctl(wcda->unixdev, CDROMEJECT);
524 } else {
525 ret = ioctl(wcda->unixdev, CDROMEJECT, 1);
527 #else
528 ret = (ioctl(wcda->unixdev, CDIOCALLOW, NULL)) ||
529 (ioctl(wcda->unixdev, open ? CDIOCEJECT : CDIOCCLOSE, NULL)) ||
530 (ioctl(wcda->unixdev, CDIOCPREVENT, NULL));
531 #endif
532 wcda->nTracks = 0;
533 return ret;
534 #else
535 return -1;
536 #endif
539 /**************************************************************************
540 * CDROM_Reset [internal]
542 int CDROM_Reset(WINE_CDAUDIO* wcda)
544 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
545 int ret = 0;
546 #ifdef linux
547 ret = ioctl(wcda->unixdev, CDROMRESET);
548 #else
549 ret = ioctl(wcda->unixdev, CDIOCRESET, NULL);
550 #endif
551 return ret;
552 #else
553 return -1;
554 #endif
557 WORD CDROM_Data_FindBestVoldesc(int fd)
559 BYTE cur_vd_type, max_vd_type = 0;
560 unsigned int offs, best_offs = 0;
562 for (offs=0x8000; offs <= 0x9800; offs += 0x800)
564 lseek(fd, offs, SEEK_SET);
565 read(fd, &cur_vd_type, 1);
566 if (cur_vd_type == 0xff) /* voldesc set terminator */
567 break;
568 if (cur_vd_type > max_vd_type)
570 max_vd_type = cur_vd_type;
571 best_offs = offs;
574 return best_offs;
577 /**************************************************************************
578 * CDROM_Audio_GetSerial [internal]
580 DWORD CDROM_Audio_GetSerial(WINE_CDAUDIO* wcda)
582 unsigned long serial = 0;
583 int i;
584 DWORD dwFrame, msf;
585 WORD wMinutes, wSeconds, wFrames;
587 for (i = 0; i < wcda->nTracks; i++) {
588 dwFrame = wcda->lpdwTrackPos[i];
589 wMinutes = dwFrame / CDFRAMES_PERMIN;
590 wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
591 wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds;
592 msf = CDROM_MAKE_MSF(wMinutes, wSeconds, wFrames);
594 serial += (CDROM_MSF_MINUTE(msf) << 16) +
595 (CDROM_MSF_SECOND(msf) << 8) +
596 (CDROM_MSF_FRAME(msf));
598 return serial;
601 /**************************************************************************
602 * CDROM_Data_GetSerial [internal]
604 DWORD CDROM_Data_GetSerial(WINE_CDAUDIO* wcda)
606 WORD offs = CDROM_Data_FindBestVoldesc(wcda->unixdev);
607 union {
608 unsigned long val;
609 unsigned char p[4];
610 } serial;
611 BYTE b0 = 0, b1 = 1, b2 = 2, b3 = 3;
613 serial.val = 0;
614 if (offs)
616 BYTE buf[2048];
617 OSVERSIONINFOA ovi;
618 int i;
620 lseek(wcda->unixdev,offs,SEEK_SET);
621 read(wcda->unixdev,buf,2048);
623 * OK, another braindead one... argh. Just believe it.
624 * Me$$ysoft chose to reverse the serial number in NT4/W2K.
625 * It's true and nobody will ever be able to change it.
627 ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
628 GetVersionExA(&ovi);
629 if ((ovi.dwPlatformId == VER_PLATFORM_WIN32_NT)
630 && (ovi.dwMajorVersion >= 4))
632 b0 = 3; b1 = 2; b2 = 1; b3 = 0;
634 for(i=0; i<2048; i+=4)
636 /* DON'T optimize this into DWORD !! (breaks overflow) */
637 serial.p[b0] += buf[i+b0];
638 serial.p[b1] += buf[i+b1];
639 serial.p[b2] += buf[i+b2];
640 serial.p[b3] += buf[i+b3];
643 return serial.val;
646 /**************************************************************************
647 * CDROM_GetSerial [internal]
649 DWORD CDROM_GetSerial(int drive)
651 WINE_CDAUDIO wcda;
652 DWORD serial = 0;
654 /* EXPIRES 01.01.2001 */
655 FIXME("CD-ROM serial number calculation might fail.\n");
656 FIXME("Please test with as many exotic CDs as possible !\n");
658 if (!(CDROM_Open(&wcda, drive)))
660 int media = CDROM_GetMediaType(&wcda);
661 LPSTR p;
663 if (media == CDS_AUDIO)
665 if (!(CDROM_Audio_GetCDStatus(&wcda))) {
666 ERR("couldn't get CD status !\n");
667 CDROM_Close(&wcda);
668 return 0;
670 serial = CDROM_Audio_GetSerial(&wcda);
672 else
673 if ((media > CDS_AUDIO)
674 || (media == -1) /* ioctl() error: ISO9660 image file given ? */
676 /* hopefully a data CD */
677 serial = CDROM_Data_GetSerial(&wcda);
678 else
679 WARN("Strange CD type (%d) or empty ?\n", media);
681 p = (media == CDS_AUDIO) ? "Audio " :
682 (media > CDS_AUDIO) ? "Data " : "";
683 if (serial)
684 FIXME("%sCD serial number is %04x-%04x.\n",
685 p, HIWORD(serial), LOWORD(serial));
686 else
687 ERR("couldn't get %sCD serial !\n", p);
688 CDROM_Close(&wcda);
690 return serial;
693 static const char empty_label[] = " ";
695 /**************************************************************************
696 * CDROM_Data_GetLabel [internal]
698 DWORD CDROM_Data_GetLabel(WINE_CDAUDIO* wcda, char *label)
700 #define LABEL_LEN 32+1
701 WORD offs = CDROM_Data_FindBestVoldesc(wcda->unixdev);
702 WCHAR label_read[LABEL_LEN]; /* Unicode possible, too */
703 DWORD unicode_id = 0;
705 if (offs)
707 if ((lseek(wcda->unixdev, offs+0x58, SEEK_SET) == offs+0x58)
708 && (read(wcda->unixdev, &unicode_id, 3) == 3))
710 int ver = (unicode_id & 0xff0000) >> 16;
712 if ((lseek(wcda->unixdev, offs+0x28, SEEK_SET) != offs+0x28)
713 || (read(wcda->unixdev, &label_read, LABEL_LEN) != LABEL_LEN))
714 goto failure;
716 if ((LOWORD(unicode_id) == 0x2f25) /* Unicode ID */
717 && ((ver == 0x40) || (ver == 0x43) || (ver == 0x45)))
718 { /* yippee, unicode */
719 int i;
720 WORD ch;
721 for (i=0; i<LABEL_LEN;i++)
722 { /* Motorola -> Intel Unicode conversion :-\ */
723 ch = label_read[i];
724 label_read[i] = (ch << 8) | (ch >> 8);
726 lstrcpynWtoA(label, label_read, 11);
728 else
730 strncpy(label, (LPSTR)label_read, 11);
731 label[11] = '\0';
733 return 0;
736 failure:
737 ERR("error reading label !\n");
738 strcpy(label, empty_label);
739 return 0;
742 /**************************************************************************
743 * CDROM_GetLabel [internal]
745 DWORD CDROM_GetLabel(int drive, char *label)
747 WINE_CDAUDIO wcda;
748 DWORD res = 1;
750 if (!(CDROM_Open(&wcda, drive)))
752 int media = CDROM_GetMediaType(&wcda);
753 LPSTR p;
755 if (media == CDS_AUDIO)
757 strcpy(label, "Audio CD ");
759 else
760 if (media == CDS_NO_INFO)
762 strcpy(label, empty_label);
764 else
765 if ((media > CDS_AUDIO)
766 || (media == -1) /* ioctl() error: ISO9660 image file given ? */
768 /* hopefully a data CD */
769 CDROM_Data_GetLabel(&wcda, label);
770 else
772 WARN("Strange CD type (%d) or empty ?\n", media);
773 strcpy(label, empty_label);
774 res = 0;
777 p = (media == CDS_AUDIO) ? "Audio " :
778 (media > CDS_AUDIO) ? "Data " : "";
779 TRACE("%sCD label is '%s'.\n",
780 p, label);
781 CDROM_Close(&wcda);
783 return res;