home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 November / PCONLINE_11_99.ISO / filesbbs / OS2 / ACDCR032.ZIP / source / cd.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-08-03  |  16.0 KB  |  587 lines

  1. /*
  2.  * This file is (C) Chris Wohlgemuth 1999
  3.  */
  4. /*
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2, or (at your option)
  8.  * any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; see the file COPYING.  If not, write to
  17.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  */
  19.  
  20. #define INCL_DOS
  21. #define INCL_DOSDEVICES
  22. #define INCL_DOSDEVIOCTL
  23. #define INCL_DOSFILEMGR
  24.  
  25. #include <os2.h>
  26. #include <stdio.h>
  27. #include <string.h>
  28. #include "cddb.h"
  29.  
  30.  
  31. #pragma pack(1)
  32.  
  33. typedef struct{
  34.     UCHAR   ucFirstTrack;
  35.     UCHAR     ucLastTrack;
  36.     ULONG   ulLeadOut;
  37. }CDINFO;
  38.  
  39. typedef struct{
  40.     ULONG   ulLeadOut;
  41.     UCHAR   ucFirstTrack;
  42.     UCHAR     ucLastTrack;
  43. }CDINFO2;
  44.  
  45. typedef struct
  46. {
  47.     ULONG ulTrackAddress;
  48.     UCHAR ucTCInfo;
  49. }TRACKINFO;
  50.  
  51. typedef struct
  52. {
  53.     UCHAR signature[4];
  54.     UCHAR  ucTrackNum;
  55. }TINFOPARAM;
  56.  
  57. typedef struct
  58. {
  59.     UCHAR ucFrames;
  60.     UCHAR ucSeconds;
  61.     UCHAR ucMinutes;
  62.     UCHAR ucNotUsed;
  63. }MSF;
  64.  
  65. typedef struct
  66. {
  67.   UCHAR signature[4];
  68.   UCHAR  ucAddressMode;
  69.   UCHAR ucStartSector[4];
  70.   UCHAR ucEndSector[4];
  71. }PLAYPARAM;
  72.  
  73. #pragma pack()
  74.  
  75.  
  76. HFILE extern openDrive(char* drive);
  77. void extern closeDrive(HFILE hfDrive);
  78. LONG extern CDCalculateSize(MSF* msf1,MSF* msf2);
  79. /******************************************/
  80. /* Result:  
  81.      0:   Error
  82.      -1: CD is Data Disk
  83.      other: # Audio tracks */
  84. /******************************************/
  85. int extern CDQueryAudioCDTracks(HFILE hfDrive);
  86. ULONG extern CDQueryUPC(UCHAR* ucUPC, char * drive);
  87. /* Returns the size in bytes of a track on drive 'drive' (e.g. O:) */
  88. LONG extern CDQueryTrackSize(ULONG numTrack, char * drive);
  89. BOOL CDPlayTrack(ULONG numTrack, char * drive);
  90. BOOL extern CDStop(char * drive);
  91. LONG extern queryFreeDriveSpace(ULONG diskNum) ;
  92. /**************************************************************/
  93. /* This funktion returns the CD-Drives in the system          */
  94. /*                                                            */
  95. /* iNumCD (output): # of CD-Drives                            */
  96. /* cFirstDrive (output): first cd-Drive letter                */
  97. /* returns TRUE: We have cd-drives                            */
  98. /**************************************************************/
  99. BOOL extern CDQueryCDDrives(int *iNumCD, char * cFirstDrive);
  100. /* Returns a CDDB disc-ID for quering the database */
  101. /* Returns 0 if error.                             */
  102. LONG extern CDDBDiscID(char * drive, CDDBINFO * cddbInfo); 
  103.  
  104.  
  105. LONG extern CDCalculateSize(MSF* msf1,MSF* msf2)
  106. {
  107.      return ((msf2->ucMinutes*60+msf2->ucSeconds)*75+msf2->ucFrames)*2352-
  108.         ((msf1->ucMinutes*60+msf1->ucSeconds)*75+msf1->ucFrames)*2352;    
  109. }
  110.  
  111. LONG extern CDCalculateSector2(MSF* msf1)
  112. {
  113.      return ((msf1->ucMinutes*60+msf1->ucSeconds));    
  114. }
  115.  
  116. LONG extern CDCalculateSector(MSF* msf1)
  117. {
  118.      return ((msf1->ucMinutes*60+msf1->ucSeconds)*75+msf1->ucFrames);    
  119. }
  120.  
  121.  
  122. /****************************************/
  123. /* Input: drive (e.g. o:)               */
  124. /****************************************/
  125. HFILE extern openDrive(char* drive)
  126. {
  127.     HFILE hfDrive = 0;
  128.     ULONG ulAction;
  129.     ULONG rc;
  130.     
  131.     rc = DosOpen(drive, &hfDrive, &ulAction, 0,
  132.                      FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS,
  133.                      OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY |
  134.                      OPEN_FLAGS_DASD|OPEN_FLAGS_FAIL_ON_ERROR, NULL);    
  135.  
  136.     if(rc)
  137.         return NULL;//Error
  138.  
  139.     return hfDrive;
  140. }
  141.  
  142. void extern closeDrive(HFILE hfDrive)
  143. {
  144.     DosClose(hfDrive);    
  145. }
  146.  
  147. /******************************************/
  148. /* Result:  
  149.      0:   Error
  150.      -1: CD is Data Disk
  151.      other: # Audio tracks */
  152. /******************************************/
  153. int extern CDQueryAudioCDTracks(HFILE hfDrive)
  154. {
  155.     ULONG ulParamLen;
  156.     ULONG ulDataLen;
  157.     ULONG rc;
  158.     CDINFO cdInfo;
  159.     TINFOPARAM tip;
  160.     TRACKINFO trackInfo;
  161.     
  162.     ulDataLen=sizeof(cdInfo);
  163.     ulParamLen=4;
  164.         
  165.     if(!hfDrive)
  166.         return 0;
  167.     
  168.     rc = DosDevIOCtl(hfDrive, IOCTL_CDROMAUDIO, CDROMAUDIO_GETAUDIODISK,
  169.                           "CD01", 4, &ulParamLen, &cdInfo,
  170.                           sizeof(cdInfo), &ulDataLen);
  171.  
  172.     if(rc) {
  173.         return 0;//Error
  174.     }
  175.  
  176.     ulDataLen=sizeof(trackInfo);
  177.     ulParamLen=sizeof(TINFOPARAM);
  178.     tip.signature[0]='C';
  179.     tip.signature[1]='D';    
  180.     tip.signature[2]='0';
  181.     tip.signature[3]='1';
  182.     tip.ucTrackNum=1;
  183.     
  184.     /* We have a disc. Check if it's audio */
  185.     rc = DosDevIOCtl(hfDrive, IOCTL_CDROMAUDIO, CDROMAUDIO_GETAUDIOTRACK,
  186.                           &tip, sizeof(tip), &ulParamLen, &trackInfo,
  187.                           sizeof(trackInfo), &ulDataLen);
  188.  
  189.     if(rc) {
  190.         return 0;//Error
  191.     }
  192.         
  193.     if(trackInfo.ucTCInfo & 0x40) {
  194.         return -1;//It's a data track
  195.     }
  196.         
  197.     return cdInfo.ucLastTrack-cdInfo.ucFirstTrack+1;
  198.     
  199. }
  200.  
  201. /* Returns the UPC of CD in drive 'drive' (e.g. O:) */
  202. /* Size of ucUCP must be 10!                        */
  203. ULONG extern CDQueryUPC(UCHAR* ucUPC, char * drive)
  204. {
  205.   HFILE hfDrive;
  206.   ULONG ulParamLen;
  207.   ULONG ulDataLen;
  208.   ULONG rc;
  209.   char setup[100]; 
  210.  
  211.   hfDrive=openDrive(drive);
  212.   if(!hfDrive) return -1;
  213.  
  214.   do {
  215.     DosBeep(1000,200);
  216.     /* Get UPC info */
  217.     ulDataLen=10;
  218.     ulParamLen=4;
  219.     rc = DosDevIOCtl(hfDrive, IOCTL_CDROMDISK, CDROMDISK_GETUPC,
  220.                      "CD01", 4, &ulParamLen, ucUPC,
  221.                      10, &ulDataLen);
  222.     sprintf(setup,"rc is: %x",rc);
  223.  
  224.     WinMessageBox(  HWND_DESKTOP,   HWND_DESKTOP,  
  225.                   setup, "GET_UPC", 0UL, MB_OK | MB_ICONEXCLAMATION|MB_MOVEABLE );
  226.  
  227.     if(rc)
  228.       break;
  229.     DosBeep(2000,200);
  230.     closeDrive(hfDrive);
  231.     return 0;
  232.  
  233.   }while(TRUE);
  234.  
  235.   /* No error */
  236.   closeDrive(hfDrive);
  237.   return -1;
  238. }
  239.  
  240.  
  241. /* Returns the size in bytes of a track on drive 'drive' (e.g. O:) */
  242. LONG extern CDQueryTrackSize(ULONG numTrack, char * drive)
  243. {
  244.     HFILE hfDrive;
  245.     ULONG ulParamLen;
  246.     ULONG ulDataLen;
  247.     ULONG rc;
  248.     CDINFO cdInfo;
  249.     TINFOPARAM tip;
  250.     TRACKINFO trackInfo[2];
  251.  
  252.     hfDrive=openDrive(drive);
  253.     if(!hfDrive) return 0;
  254.     
  255.     do {
  256.         /* Get cd info */
  257.         ulDataLen=sizeof(cdInfo);
  258.         ulParamLen=4;
  259.         rc = DosDevIOCtl(hfDrive, IOCTL_CDROMAUDIO, CDROMAUDIO_GETAUDIODISK,
  260.                                          "CD01", 4, &ulParamLen, &cdInfo,
  261.                                          sizeof(cdInfo), &ulDataLen);        
  262.         if(rc)
  263.             break;//Error
  264.         ulDataLen=sizeof(trackInfo);
  265.         ulParamLen=sizeof(TINFOPARAM);
  266.         tip.signature[0]='C';
  267.         tip.signature[1]='D';    
  268.         tip.signature[2]='0';
  269.         tip.signature[3]='1';
  270.         /* Get information about our track */
  271.         tip.ucTrackNum=numTrack;
  272.         rc = DosDevIOCtl(hfDrive, IOCTL_CDROMAUDIO, CDROMAUDIO_GETAUDIOTRACK,
  273.                                          &tip, sizeof(tip), &ulParamLen, &trackInfo[0],
  274.                                          sizeof(trackInfo[0]), &ulDataLen);
  275.         if(rc) 
  276.             break;//Error
  277.  
  278.         /* Get information about next track */
  279.         tip.ucTrackNum=numTrack+1;
  280.         if(tip.ucTrackNum<=cdInfo.ucLastTrack) {
  281.             rc = DosDevIOCtl(hfDrive, IOCTL_CDROMAUDIO, CDROMAUDIO_GETAUDIOTRACK,
  282.                                              &tip, sizeof(tip), &ulParamLen, &trackInfo[1],
  283.                                              sizeof(trackInfo[1]), &ulDataLen);
  284.             if(rc) 
  285.                 break;//Error
  286.         }
  287.         else {
  288.           trackInfo[1].ulTrackAddress=cdInfo.ulLeadOut;
  289.           /* #pragma pack(1) eingebaut */
  290.  
  291.           /*BYTE *cdInfoBytes;
  292.             cdInfoBytes=(BYTE*)&cdInfo;
  293.             cdInfoBytes+=2;
  294.             trackInfo[1].ulTrackAddress=*((ULONG*)cdInfoBytes);*/
  295.         }
  296.         closeDrive(hfDrive);
  297.         return CDCalculateSize((MSF*)&trackInfo[0].ulTrackAddress, (MSF*)&trackInfo[1].ulTrackAddress);
  298.     }while(TRUE);
  299.     closeDrive(hfDrive);
  300.     return 0;
  301. }
  302.  
  303. /* Returns sector info of track #numTrack */
  304. /* Starting with track 0 */
  305. LONG extern CDQueryTrackStartSector(ULONG numTrack, HFILE hfDrive)
  306. {
  307.     
  308.     ULONG ulParamLen;
  309.     ULONG ulDataLen;
  310.     ULONG rc;
  311.     CDINFO cdInfo;
  312.     TINFOPARAM tip;
  313.     TRACKINFO trackInfo[2];
  314.  
  315.     do {
  316.       /* Get cd info */
  317.       ulDataLen=sizeof(cdInfo);
  318.       ulParamLen=4;
  319.       rc = DosDevIOCtl(hfDrive, IOCTL_CDROMAUDIO, CDROMAUDIO_GETAUDIODISK,
  320.                        "CD01", 4, &ulParamLen, &cdInfo,
  321.                        sizeof(cdInfo), &ulDataLen);        
  322.       if(rc)
  323.         break;//Error
  324.       
  325.       ulDataLen=sizeof(trackInfo);
  326.         ulParamLen=sizeof(TINFOPARAM);
  327.         tip.signature[0]='C';
  328.         tip.signature[1]='D';    
  329.         tip.signature[2]='0';
  330.         tip.signature[3]='1';
  331.         /* Get information about our track */
  332.         tip.ucTrackNum=numTrack+1;
  333.         if(tip.ucTrackNum<=cdInfo.ucLastTrack) {
  334.           rc = DosDevIOCtl(hfDrive, IOCTL_CDROMAUDIO, CDROMAUDIO_GETAUDIOTRACK,
  335.                            &tip, sizeof(tip), &ulParamLen, &trackInfo[0],
  336.                            sizeof(trackInfo[0]), &ulDataLen);
  337.           if(rc) 
  338.             break;//Error
  339.           }else 
  340.             return CDCalculateSector((MSF*)&cdInfo.ulLeadOut);
  341.         
  342.  
  343.         return CDCalculateSector((MSF*)&trackInfo[0].ulTrackAddress);
  344.  
  345.     }while(TRUE);
  346.     
  347.     /* error */
  348.     printf("ERROR!!!!!!!!!\n");
  349.     return 0;
  350. }
  351.  
  352. /*****************************************/
  353. /*                                       */
  354. /* Plays track #numTrack on              */
  355. /* CD-Drive 'drive'                      */
  356. /*                                       */
  357. /* Returns TRUE if successful            */
  358. /*                                       */
  359. /*****************************************/
  360. BOOL CDPlayTrack(ULONG numTrack, char * drive)
  361. {
  362.     HFILE hfDrive;
  363.     ULONG ulParamLen;
  364.     ULONG ulDataLen;
  365.     ULONG rc;
  366.     CDINFO cdInfo;
  367.     TINFOPARAM tip;
  368.     TRACKINFO trackInfo[2];
  369.     PLAYPARAM playParam;
  370.  
  371.     hfDrive=openDrive(drive);
  372.     if(!hfDrive) return FALSE;
  373.     do {
  374.     /* Get cd info */
  375.         ulDataLen=sizeof(cdInfo);
  376.         ulParamLen=4;
  377.         rc = DosDevIOCtl(hfDrive, IOCTL_CDROMAUDIO, CDROMAUDIO_GETAUDIODISK,
  378.                                          "CD01", 4, &ulParamLen, &cdInfo,
  379.                                          sizeof(cdInfo), &ulDataLen);        
  380.         if(rc)
  381.             break;//Error
  382.         ulDataLen=sizeof(trackInfo);
  383.         ulParamLen=sizeof(TINFOPARAM);
  384.         tip.signature[0]='C';
  385.         tip.signature[1]='D';    
  386.         tip.signature[2]='0';
  387.         tip.signature[3]='1';
  388.         /* Get information about our track */
  389.         tip.ucTrackNum=numTrack;
  390.         rc = DosDevIOCtl(hfDrive, IOCTL_CDROMAUDIO, CDROMAUDIO_GETAUDIOTRACK,
  391.                                          &tip, sizeof(tip), &ulParamLen, &trackInfo[0],
  392.                                          sizeof(trackInfo[0]), &ulDataLen);
  393.         if(rc) 
  394.             break;//Error
  395.         /* Get information about next track */
  396.         tip.ucTrackNum=numTrack+1;
  397.         if(tip.ucTrackNum<=cdInfo.ucLastTrack) {
  398.             rc = DosDevIOCtl(hfDrive, IOCTL_CDROMAUDIO, CDROMAUDIO_GETAUDIOTRACK,
  399.                                              &tip, sizeof(tip), &ulParamLen, &trackInfo[1],
  400.                                              sizeof(trackInfo[1]), &ulDataLen);
  401.             if(rc) 
  402.                 break;//Error
  403.         }
  404.         else {
  405.           /* The following does not work on my system. Compilerbug ? 
  406.              trackInfo[1].ulTrackAddress=cdInfo.ulLeadOut; */
  407.           BYTE *cdInfoBytes;
  408.           cdInfoBytes=(BYTE*)&cdInfo;
  409.           cdInfoBytes+=2;
  410.           trackInfo[1].ulTrackAddress=*((ULONG*)cdInfoBytes);
  411.         }
  412.  
  413.               /* Play the Track... */
  414.         ulParamLen=sizeof(PLAYPARAM);
  415.         playParam.signature[0]='C';
  416.         playParam.signature[1]='D';    
  417.         playParam.signature[2]='0';
  418.         playParam.signature[3]='1';
  419.         playParam.ucAddressMode=01;
  420.         memcpy(&playParam.ucStartSector,&trackInfo[0].ulTrackAddress,4);
  421.         memcpy(&playParam.ucEndSector,&trackInfo[1].ulTrackAddress,4);
  422.         
  423.         rc = DosDevIOCtl(hfDrive, IOCTL_CDROMAUDIO, CDROMAUDIO_PLAYAUDIO,
  424.                          &playParam, sizeof(playParam), &ulParamLen,0,
  425.                          0, 0);
  426.         if(rc)
  427.           break;
  428.         closeDrive(hfDrive);
  429.         return TRUE;
  430.     }while(TRUE);
  431.     closeDrive(hfDrive);
  432.     return FALSE;
  433. }
  434.  
  435. BOOL extern CDStop(char * drive)
  436. {
  437.     HFILE hfDrive;
  438.     ULONG ulParamLen;
  439.     ULONG rc;
  440.  
  441.     hfDrive=openDrive(drive);
  442.     if(!hfDrive) return FALSE;
  443.     
  444.     do {
  445.       /* Stop CD */
  446.       ulParamLen=4;
  447.       rc = DosDevIOCtl(hfDrive, IOCTL_CDROMAUDIO, CDROMAUDIO_STOPAUDIO,
  448.                        "CD01", 4, &ulParamLen,0,
  449.                        0, 0);        
  450.       if(rc)
  451.         break;//Error
  452.       closeDrive(hfDrive);
  453.       return TRUE;
  454.     }while(TRUE);
  455.     closeDrive(hfDrive);
  456.     return FALSE;
  457. }
  458.  
  459. LONG extern queryFreeDriveSpace(ULONG diskNum) 
  460. {
  461.     FSALLOCATE infoBuf;
  462.     
  463.     if(DosQueryFSInfo(diskNum,FSIL_ALLOC,&infoBuf,sizeof(infoBuf)))
  464.         return 0;
  465.     
  466.     return infoBuf.cUnitAvail*infoBuf.cbSector*infoBuf.cSectorUnit;
  467. }
  468.  
  469. /**************************************************************/
  470. /*                                                            */
  471. /* This funktion returns the CD-Drives in the system          */
  472. /*                                                            */
  473. /* iNumCD (output): # of CD-Drives                            */
  474. /* cFirstDrive (output): first cd-Drive letter                */
  475. /* returns TRUE: We have cd-drives                            */
  476. /*                                                            */
  477. /**************************************************************/
  478. BOOL extern CDQueryCDDrives(int *iNumCD, char * cFirstDrive)
  479. {
  480.   HFILE hfDevice;
  481.   ULONG ulAction;
  482.   ULONG ulLen;
  483.   static char cFirst=0;
  484.   static int iNumCDLocal=0;
  485.   static BOOL haveCD=FALSE;
  486.   static BOOL done=FALSE;            
  487.   struct
  488.   {
  489.     USHORT usCountCD;
  490.     USHORT usFirstCD;
  491.   } CDInfo;
  492.   
  493.   if(!done){
  494.     ulLen = sizeof(CDInfo);
  495.     if(!DosOpen("\\DEV\\CD-ROM2$", &hfDevice, &ulAction, 0,
  496.                 FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS,
  497.                 OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY, NULL))
  498.       {
  499.         if(!DosDevIOCtl(hfDevice, 0x82, 0x60, NULL, 0, NULL, &CDInfo, ulLen, &ulLen))
  500.           {
  501.             if(CDInfo.usCountCD) {
  502.               haveCD=TRUE;
  503.               iNumCDLocal=CDInfo.usCountCD;
  504.               cFirst='A'+ CDInfo.usFirstCD;
  505.             }                                         
  506.           }
  507.         DosClose(hfDevice);
  508.       }
  509.     done=TRUE;
  510.   }
  511.   *iNumCD=iNumCDLocal;
  512.   *cFirstDrive=cFirst;
  513.   return haveCD;                
  514. }
  515.  
  516.  
  517. /*****************************************/
  518. /*                                       */
  519. /* Query if a CD is avaiable in          */
  520. /* CD-Drive 'drive'                      */
  521. /*                                       */
  522. /* Input: drive num (starting with 0)    */
  523. /* Returns TRUE if media is avaiable     */
  524. /*                                       */
  525. /*****************************************/
  526. BOOL CDQueryMedia(ULONG  driveNum)
  527. {
  528.   return FALSE;
  529. }
  530.  
  531.  
  532. int cddb_sum(int n)
  533. {
  534.   int ret;
  535.   //printf("n:  %d   ",n);
  536.   for (ret = 0; n > 0; n /= 10) {
  537.     ret += (n % 10);
  538.   }
  539.   //printf("ret:  %d   ",ret);
  540.   return ret;
  541. }
  542.  
  543. /* Returns a CDDB disc-ID for quering the database */
  544. /* Returns 0 if error.                             */
  545. LONG extern CDDBDiscID(char * drive, CDDBINFO * cddbInfo)
  546. {
  547.   int numTracks,a;
  548.   HFILE hfDrive;
  549.   LONG sum;
  550.   int t;
  551.  
  552.   do {
  553.     hfDrive=openDrive(drive);
  554.     if(!hfDrive)
  555.       return 0;
  556.  
  557.     numTracks=CDQueryAudioCDTracks(hfDrive);
  558.     if(numTracks==0||numTracks==-1)
  559.       break;
  560.     cddbInfo->numTracks=numTracks;
  561.  
  562.     sum=0;
  563.     /* Calculating the id */
  564.     for(a=0;a<numTracks;a++) {
  565.       sum+= cddb_sum(CDQueryTrackStartSector(a, hfDrive)/75 );
  566.       //printf("Track%d: %d\n",a,CDQueryTrackStartSector(a, hfDrive));
  567.       cddbInfo->startSector[a]=CDQueryTrackStartSector(a, hfDrive);
  568.     }
  569.     t=CDQueryTrackStartSector(a, hfDrive)/75-CDQueryTrackStartSector(0, hfDrive)/75;
  570.     /*printf("(a-1): %d  0: %d t:  %d\n",CDQueryTrackStartSector(a, hfDrive),
  571.            CDQueryTrackStartSector(0, hfDrive),t);*/
  572.     //printf("discid: %x\n",((sum % 0xff) << 24 | (t << 8) | numTracks));
  573.     //printf("Disclength: %d",(CDQueryTrackStartSector(a, hfDrive)-CDQueryTrackStartSector(0, hfDrive))/75);
  574.     cddbInfo->discLength=(CDQueryTrackStartSector(a, hfDrive)-CDQueryTrackStartSector(0, hfDrive))/75;
  575.     cddbInfo->discid=(sum % 0xff) << 24 | (t << 8) | numTracks;
  576.     closeDrive(hfDrive);
  577.     return cddbInfo->discid;
  578.   }while(TRUE);
  579.  
  580.   /* error */
  581.   closeDrive(hfDrive);
  582.   return 0;
  583. }
  584.  
  585.  
  586.  
  587.