⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cdcache.c

📁 读取音乐光盘磁道为磁盘文件的DLL源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * cdcache.c - Copyright (C) 1999 Jay A. Key
 *
 * Interface to CD title/artist/track names cache, and cddb.  Can optionally
 * use cdplayer.ini when internet access is not available.
 *
 * The code to access CDPLAYER.INI was adapted from code submitted by
 * Blair Thompson
 *
 **********************************************************************
 *
 * This program 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 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 **********************************************************************
 *
 * $Id: cdcache.c,v 1.2 2000/02/25 10:47:37 akey Exp $
 * $Date: 2000/02/25 10:47:37 $
 * $Locker:  $
 * $Log: cdcache.c,v $
 * Revision 1.2  2000/02/25 10:47:37  akey
 * sync'ed with akrip32.dll v0.94
 *
 * Revision 1.6  2000/02/14 09:56:25  akey
 * cleaned up #ifdef _DEBUG code considerably
 *
 * Revision 1.5  2000/02/11 10:00:35  akey
 * added access to cdplayer.ini
 *
 * Revision 1.4  2000/01/31 15:35:40  akey
 * v0.93: added CDDBGetServerList and fixed problem with Win2000 scsi pass through code
 *
 * Revision 1.3  2000/01/06 16:38:35  akey
 * Added missing CDDB_OPT_HTTPPORT
 *
 * Revision 1.2  2000/01/03 12:29:43  akey
 * v0.91 release -- added CDDB and bug fixes
 *
 *
 */

#include <windows.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <winsock.h>
#include "aspilib.h"
#include "cdcache.h"


DWORD CDDBPostCmd( char *cmd, char *retBuf, int retLen );
DWORD CDDBPostCmdProxy( char *cmd, char *retBuf, int retLen );
void urlEncodeString( char *s );
void GetLineFromBuf( char **src, char *tgt, int len );
void processCDDBQuery( char *buf, LPCDDBQUERY lpq );
void SkipHTTPHeaders( char **buf );
int extractCDDBQueryInfo( LPCDDBQUERYITEM lpq, char *linebuf );
void processSites( char *buf, LPCDDBSITELIST lps );
int extractCDDBSiteInfo( LPCDDBSITE s, char *buf );
void getWord( char **inBuf, char *outBuf, int len );
DWORD genCDPlayerIniIndex( HCDROM hCD );
void MSB2DWORD( DWORD *d, BYTE *b );
DWORD getDiskInfoCDPlayerIni( LPCDDBQUERYITEM lpq, char *szCDDBEntry, int maxLen );
BOOL isCDinCDPlayerIni( char *s );
void addCDPlayerCDDBIndex( DWORD cdpIdx, DWORD cddbId, DWORD numTracks );
void writeCDPlayerIniEntry( LPCDDBQUERYITEM lpq, char *szCDDBEntry );


extern CDHANDLEREC *cdHandles;
extern HANDLE *cdMutexes;
extern HANDLE hCacheMutex;
extern CRITICAL_SECTION csCache;

extern CRITICAL_SECTION getHandle;
extern int alErrCode;
extern BYTE alAspiErr;

extern DWORD (*pfnSendASPI32Command)(LPSRB);

//static BOOL bCacheInitMutex = FALSE;
static BOOL bCacheInit = FALSE;

static char szCacheDir[MAX_PATH+1];
//static HANDLE hCacheMutex = NULL;
//static CRITICAL_SECTION csCache;

static char szCDPlayerIni[] = "cdplayer.ini";
static char szProxyAddr[256] = "";
static int  iProxyPort = 0;
static char szCDDBServer[256] = "www.freedb.org";
static BOOL bUseProxy = FALSE;
static char szAgent[61] = "akrip32dll 0.91";
static char szUser[65] = "user@akrip.sourceforge.net";
static char szCGI[81] = "/~cddb/cddb.cgi";
static int  iHTTPPort = 80;
static BOOL bUseCDPlayerIni = TRUE;
static DWORD dwCDDB2CDPlayer[20][3];
static int iNextIndex = -1;


DWORD CDDBSum( DWORD n )
{
  DWORD retVal = 0;

  while( n > 0 )
    {
      retVal += ( n % 10 );
      n /= 10;
    }

  return retVal;
}


/*
 * Computes the CDDBID for the CD in the drive represented by hCD.
 * Data which can be used to construct a CDDB query is stored in the 
 * array pID.
 *   pID[0] = CDDBID
 *   pID[1] = number of tracks
 *   pID[2..(2+n)] = starting MSF offset of tracks on CD
 * pID will need to have (at least) n+3 entries, where n is the number
 * of tracks on the CD.  102 should always be enough.  Note that the lead-out
 * track is included.
 */
DWORD GetCDDBDiskID( HCDROM hCD, DWORD *pID, int numEntries )
{
  TOC toc;
  TOCTRACK *t1, *t2;
  int idx = (int)hCD - 1;
  DWORD t;
  DWORD n;
  int i;
  int j;
  BOOL bMSF;

  *pID = 0;

  if ( (idx<0) || (idx>=MAXCDHAND) || !cdHandles[idx].used )
    {
      alErrCode = ALERR_INVHANDLE;
      return SS_ERR;
    }

  if ( WaitForSingleObject( cdMutexes[idx], TIMEOUT ) != WAIT_OBJECT_0 )
    {
      alErrCode = ALERR_LOCK;
      return SS_ERR;
    }

  bMSF = cdHandles[idx].bMSF;
  cdHandles[idx].bMSF = TRUE;

  memset( &toc, 0, sizeof(toc) );
  ReadTOC( hCD, &toc );

  n = t = 0;
  for( j = 2, i = toc.firstTrack - 1; i < toc.lastTrack; i++, j++ )
    {
      t1 = &(toc.tracks[i]);
      pID[j] = (((t1->addr[1]*60)+t1->addr[2])*75)+t1->addr[3];
      n += CDDBSum( 60 * toc.tracks[i].addr[1] + toc.tracks[i].addr[2] );
    }

  t2 = &(toc.tracks[toc.lastTrack-toc.firstTrack+1]);
  t = 60 * t2->addr[1] + t2->addr[2];
  t2 = &(toc.tracks[0]);
  t -= ( 60 * t2->addr[1] + t2->addr[2] );
  pID[toc.lastTrack+2] = t;

#if 0
  // fudge the total time to generate inexact matches for testing
  t += 2;
#endif

  pID[1] = toc.lastTrack - toc.firstTrack + 1;

  *pID = ((n%0xFF) << 24) | (t << 8) | (toc.lastTrack - toc.firstTrack + 1);

  cdHandles[idx].bMSF = bMSF;

  n = genCDPlayerIniIndex( hCD );

  addCDPlayerCDDBIndex( n, pID[0], pID[1] );

  ReleaseMutex( cdMutexes[idx] );
  return SS_COMP;
}


BOOL InitCache( LPCTSTR lpszDir )
{
  if ( bCacheInit )
    return FALSE;

  if ( !lpszDir )
    lpszDir = "";
  strncpy( szCacheDir, lpszDir, MAX_PATH+1 );

  bCacheInit = TRUE;
  return TRUE;
}


/*
 * Sends an HTTP POST command and waits for a response.  The response is
 * copied to retBuf.  Uses a proxy.  Returns the number of bytes copied to
 * retBuf.  Before returning, it should strip the HTTP header from the info
 * if present.
 */
DWORD CDDBPostCmdProxy( char *cmd, char *retBuf, int retLen )
{
  WSADATA wsaData;
  SOCKET s;
  struct hostent *h;
  struct sockaddr_in sin;
  int i;
  char *postcmd, *p;
  DWORD retVal = 0;

  p = retBuf;
  ZeroMemory( p, retLen );
  retLen--;                 // reserve room for the terminating NULL

  WSAStartup( MAKEWORD(1,1), &wsaData );

  s = socket( AF_INET, SOCK_STREAM, 0 );
  h = gethostbyname( szProxyAddr );

  if ( !h )
    {
#ifdef _DEBUG
      dbprintf( "akrip32: CDDBPostCmdProxy: unable to resolve hostname" );
#endif
      return 0;
    }

  sin.sin_family = AF_INET;
  sin.sin_port = htons( iProxyPort );
  memcpy( &sin.sin_addr, h->h_addr, h->h_length );

  i = connect( s, (struct sockaddr *)&sin, sizeof(sin) );

  p = postcmd = (char *)GlobalAlloc( GPTR, lstrlen(cmd) + 512 );

  wsprintf( postcmd, "POST http://%s%s HTTP/1.0\r\nContent-Type: application/x-www-form-urlencoded\r\nUser-Agent: AKRip090\r\n", szCDDBServer, szCGI );
  p += lstrlen( postcmd );
  wsprintf( p, "Content-Length: %d\r\n\r\n", lstrlen( cmd ) + 2 );
  strcat( p, cmd );
  strcat( p, "\r\n" );

#if 0
  i = 120;
  i = setsockopt( s, IPPROTO_TCP, SO_SNDTIMEO, &i, sizeof(int) );
  if ( i == SOCKET_ERROR )
    dbprintf( "Error setting rcv timeout on socket" );
  else
    dbprintf( "Receive socket timeout set" );
#endif

  send( s, postcmd, lstrlen( postcmd ), 0 );

  p = retBuf;
  ZeroMemory( p, retLen );
  i = -1;
  while( (i != 0) && (retLen >= 128) )
    {
      i = recv( s, p, 128, 0 );
      p += i;
      retLen -= i;
      retVal += (DWORD)i;
      if ( i < 0 )
	i = 0;
    }

  closesocket( s );
  
  GlobalFree( (HGLOBAL)postcmd );
  WSACleanup();

  return retVal;
}


/*
 * Sends an HTTP POST command and waits for a response.  The response is
 * copied to retBuf.  Returns the number of bytes copied to retBuf.
 */
DWORD CDDBPostCmd( char *cmd, char *retBuf, int retLen )
{
  WSADATA wsaData;
  SOCKET s;
  struct hostent *h;
  struct sockaddr_in sin;
  int i;
  char *postcmd, *p;
  DWORD retVal = 0;

  p = retBuf;
  ZeroMemory( p, retLen );
  retLen--;                 // reserve room for the terminating NULL

  WSAStartup( MAKEWORD(1,1), &wsaData );

  s = socket( AF_INET, SOCK_STREAM, 0 );
  h = gethostbyname( szCDDBServer );

  if ( !h )
    return 0;

  sin.sin_family = AF_INET;
  sin.sin_port = htons( iHTTPPort );
  memcpy( &sin.sin_addr, h->h_addr, h->h_length );

  i = connect( s, (struct sockaddr *)&sin, sizeof(sin) );

  p = postcmd = (char *)GlobalAlloc( GPTR, lstrlen(cmd) + 512 );
  
  wsprintf( p, "GET %s?", szCGI );
  strcat( p, cmd );
  strcat( p, "\r\n" );

  send( s, postcmd, lstrlen( postcmd ), 0 );

  p = retBuf;
  ZeroMemory( p, retLen );
  i = -1;
  while( (i != 0) && (retLen >= 128) )
    {
      i = recv( s, p, 128, 0 );
      p += i;
      retLen -= i;
      retVal += (DWORD)i;
      if ( i < 0 )
	i = 0;
    }

  closesocket( s );
  
  GlobalFree( (HGLOBAL)postcmd );
  WSACleanup();

  return retVal;
}


/*
 * Queries the CDDB for a given disk.
 * Returns SS_COMP on success, SS_ERR on error.  numEntries on entry contains
 * the number of elements in the lpq array, and on return is set to the 
 * number of entries returned.
 *
 * If the no items are returned, or if no network connection is available,
 * returns one item with category "cdplayerini" and the index stored in
 * cddbId;
 */
DWORD CDDBQuery( HCDROM hCD, LPCDDBQUERY lpq )
{
  //int numRead = 0;
  LPDWORD pdwId;
  char *cmd, *p, *retBuf;
  int i;

  if ( !lpq )
    {
      return SS_ERR;
    }

  pdwId = GlobalAlloc( GPTR, 103 * sizeof(DWORD) );
  cmd = GlobalAlloc( GPTR, 1024 );
  retBuf = GlobalAlloc( GPTR, 2048 );
  if ( !cmd || !pdwId || !retBuf )
    {
      if ( cmd ) GlobalFree( (HGLOBAL)cmd );
      if ( pdwId ) GlobalFree( (HGLOBAL)pdwId );
      if ( retBuf ) GlobalFree( (HGLOBAL)retBuf );
      lpq->num = 0;
      return SS_ERR;
    }

  // Generate the cddb ID for the disc
  if ( GetCDDBDiskID( hCD, pdwId, 102 ) == SS_COMP )
    {
      // Generate a query string
      p = cmd;
      wsprintf( p, "cmd=cddb+query+%08x+%d+", pdwId[0], pdwId[1] );
      p += lstrlen( p );
      for( i = 0; i < pdwId[1]; i++ )
	{
	  wsprintf( p, "%d+", pdwId[i+2] );
	  p += lstrlen(p);
	}
      wsprintf( p, "%d&hello=%s+%s&proto=3",
		pdwId[pdwId[1]+2], szUser, szAgent );
      urlEncodeString( p );

      // send the query string
      if ( bUseProxy )
	CDDBPostCmdProxy( cmd, retBuf, 2048 );
      else
	CDDBPostCmd( cmd, retBuf, 2048 );

      // process the returned data (if any)
      processCDDBQuery( retBuf, lpq );

      // fall back to cdplayer.ini if no items matched
      if ( (lpq->num == 0) && bUseCDPlayerIni )
	{
	  pdwId[0] = genCDPlayerIniIndex( hCD );
	  wsprintf( retBuf, "%X", pdwId[0] );
	  if ( isCDinCDPlayerIni( retBuf ) )
	    {
	      wsprintf( lpq->q[0].cddbId, "%X", pdwId[0] );
	      lstrcpy( lpq->q[0].categ, "cdplayerini" );
	      lpq->q[0].bExact = TRUE;
	      lpq->num = 1;
	    }
	}
      // else if we have multiple/partial matches from CDDB, we need to 
      // associate all of the cddbId values with the cdPlayer.ini index
      else if ( (lpq->num > 1) && bUseCDPlayerIni )
	{
	  pdwId[2] = genCDPlayerIniIndex( hCD );
	  for( i = 0; i < lpq->num; i++ )
	    {
	      pdwId[0] = (DWORD)strtoul( lpq->q[i].cddbId, NULL, 16 );
	      addCDPlayerCDDBIndex( pdwId[2], pdwId[0], pdwId[1] );
	    }
	}
    }

  GlobalFree( (HGLOBAL)pdwId );
  GlobalFree( (HGLOBAL)cmd );
  GlobalFree( (HGLOBAL)retBuf );

  return SS_COMP;
}


void CDDBSetOption( int what, char *szVal, int iVal )
{
  switch( what )
    {
    case CDDB_OPT_PROXY:
      if ( szVal )
	lstrcpyn( szProxyAddr, szVal, 255 );
      szProxyAddr[255] = 0;
      break;

    case CDDB_OPT_SERVER:
      if ( szVal )
	lstrcpyn( szCDDBServer, szVal, 255 );
      szCDDBServer[255] = 0;
      break;

    case CDDB_OPT_CGI:
      if ( szVal )
	lstrcpyn( szCGI, szVal, 80 );
      szCGI[80] = 0;
      break;

    case CDDB_OPT_PROXYPORT:
      iProxyPort = iVal;
      break;

    case CDDB_OPT_AGENT:
      if ( szVal )
	lstrcpyn( szAgent, szVal, 60 );
      szAgent[60] = 0;
      urlEncodeString( szAgent );
      break;

    case CDDB_OPT_USER:
      if ( szVal )
	lstrcpyn( szUser, szVal, 64 );
      szUser[64] = 0;
      urlEncodeString( szUser );
      break;

    case CDDB_OPT_USEPROXY:
      bUseProxy = (BOOL)iVal;
      break;

    case CDDB_OPT_HTTPPORT:
      iHTTPPort = iVal;
      break;

    case CDDB_OPT_USECDPLAYERINI:
      bUseCDPlayerIni = (BOOL)iVal;
      break;
    }
}


void urlEncodeString( char *s )
{
  if ( !s || !*s )
    return;

  while( *++s )
    {
      if ( (*s == '@') || (*s == ' ') )
	*s = '+';
    }
}


/*
 * Process the return buffer from a cddb query.  Verify that the return code
 * is one that we expect (200, 211, 202, 403, 409).
 */
void processCDDBQuery( char *buf, LPCDDBQUERY lpq )
{
  int total = 0;
  int iRetCode, i;
  int maxLines = 100;
  char retCode[4] = "100";
  char linebuf[81];
  char *p = buf;
  FILE *fp;

  fp = fopen( "retbuf.txt", "wb" );
  fwrite( p, 1, lstrlen( p ), fp );

  SkipHTTPHeaders( &p );

  GetLineFromBuf( &p, linebuf, 81 );

  strncpy( retCode, linebuf, 3 );
  iRetCode = atoi( retCode );

  switch( iRetCode )
    {
    case 200:
      // one exact match
      if ( extractCDDBQueryInfo( &lpq->q[0], linebuf+4 ) )
	{
	  lpq->q[0].bExact = TRUE;
	  total++;
	}
      break;

    case 211:
      // inexact match(es)
      i = 0;
      while ( p && lpq->num && (maxLines-- > 0) )
	{
	  GetLineFromBuf( &p, linebuf, 81 );
	  if ( !strcmp( linebuf, "." ) )
	    break;
	  if ( extractCDDBQueryInfo( &lpq->q[i], linebuf ) )
	    {
	      lpq->q[i].bExact = FALSE;
	      total++;
	      i++;
	      lpq->num--;
	    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -