1283 lines
29 KiB
C
1283 lines
29 KiB
C
|
/******************************Module*Header*******************************\
|
||
|
* Module Name: database.c
|
||
|
*
|
||
|
* This module implements the database routines for the CD Audio app.
|
||
|
* The information is stored in the ini file "cdaudio.ini" which should
|
||
|
* be located in the nt\windows directory.
|
||
|
*
|
||
|
* Warning:
|
||
|
* These functions ARE NOT THREAD safe.
|
||
|
* The functions in this file MUST only be called on the UI thread. Before
|
||
|
* calling any of the functions the CALLER MUST call LockTableOfContents
|
||
|
* for the specified cdrom device.
|
||
|
*
|
||
|
* Author:
|
||
|
* Rick Turner (ricktu) 31-Jan-1992
|
||
|
*
|
||
|
*
|
||
|
* Revision History:
|
||
|
*
|
||
|
* 04-Aug-1992 (ricktu) Incorperated routines from old cdaudio.c,
|
||
|
* and made work w/new child window framework.
|
||
|
*
|
||
|
*
|
||
|
* Copyright (c) 1993 - 1995 Microsoft Corporation. All rights reserved.
|
||
|
\**************************************************************************/
|
||
|
#pragma warning( once : 4201 4214 )
|
||
|
|
||
|
#define NOOLE
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include "resource.h"
|
||
|
#include "cdapi.h"
|
||
|
#include "cdplayer.h"
|
||
|
#include "database.h"
|
||
|
#include "literals.h"
|
||
|
|
||
|
|
||
|
#include <string.h>
|
||
|
#include <stdio.h>
|
||
|
#include <tchar.h>
|
||
|
|
||
|
|
||
|
/* -------------------------------------------------------------------------
|
||
|
** Private entry points
|
||
|
** -------------------------------------------------------------------------
|
||
|
*/
|
||
|
DWORD
|
||
|
ComputeOldDiscId(
|
||
|
int cdrom
|
||
|
);
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
DeleteEntry(
|
||
|
DWORD Id
|
||
|
);
|
||
|
|
||
|
BOOL
|
||
|
WriteEntry(
|
||
|
int cdrom
|
||
|
);
|
||
|
|
||
|
BOOL
|
||
|
ReadEntry(
|
||
|
int cdrom,
|
||
|
DWORD dwId
|
||
|
);
|
||
|
|
||
|
BOOL
|
||
|
ReadMusicBoxEntry(
|
||
|
int cdrom,
|
||
|
DWORD dwId
|
||
|
);
|
||
|
|
||
|
|
||
|
/*****************************Private*Routine******************************\
|
||
|
* ComputeOldDiscId
|
||
|
*
|
||
|
* This routine computes a unique ID based on the information
|
||
|
* in the table of contexts a given disc.
|
||
|
*
|
||
|
*
|
||
|
* History:
|
||
|
* 18-11-93 - ricktu - Created
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
DWORD
|
||
|
ComputeOldDiscId(
|
||
|
int cdrom
|
||
|
)
|
||
|
{
|
||
|
int NumTracks,i;
|
||
|
DWORD DiscId = 0;
|
||
|
|
||
|
|
||
|
NumTracks = g_Devices[ cdrom ]->toc.LastTrack -
|
||
|
g_Devices[ cdrom ]->toc.FirstTrack;
|
||
|
|
||
|
for ( i = 0; i < NumTracks; i++ ) {
|
||
|
DiscId += ( (TRACK_M(cdrom,i) << 16) +
|
||
|
(TRACK_S(cdrom,i) << 8) +
|
||
|
TRACK_F(cdrom,i) );
|
||
|
}
|
||
|
|
||
|
return DiscId;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* ComputeNewDiscId
|
||
|
*
|
||
|
* Just call mci to get the product ID.
|
||
|
*
|
||
|
* History:
|
||
|
* dd-mm-94 - StephenE - Created
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
DWORD
|
||
|
ComputeNewDiscId(
|
||
|
int cdrom
|
||
|
)
|
||
|
{
|
||
|
#ifdef USE_IOCTLS
|
||
|
return ComputeOrgDiscId( cdrom );
|
||
|
#else
|
||
|
|
||
|
MCI_INFO_PARMS mciInfo;
|
||
|
TCHAR szBuffer[32];
|
||
|
DWORD dwRet;
|
||
|
|
||
|
mciInfo.lpstrReturn = szBuffer;
|
||
|
mciInfo.dwRetSize = sizeof(szBuffer)/sizeof(TCHAR);
|
||
|
|
||
|
dwRet = mciSendCommand( g_Devices[cdrom]->hCd, MCI_INFO,
|
||
|
MCI_INFO_MEDIA_IDENTITY,
|
||
|
(DWORD)(LPVOID)&mciInfo );
|
||
|
|
||
|
if ( dwRet != MMSYSERR_NOERROR ) {
|
||
|
return 0L;
|
||
|
}
|
||
|
|
||
|
_stscanf(szBuffer, TEXT("%ld"), &dwRet );
|
||
|
|
||
|
return dwRet;
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*****************************Private*Routine******************************\
|
||
|
* ComputeOrgDiscId
|
||
|
*
|
||
|
* This routine computes a unique ID based on the information
|
||
|
* in the table of contexts a given disc. This is done by taking
|
||
|
* the TMSF value for each track and XOR'ing it with the previous
|
||
|
* quantity shifted left one bit.
|
||
|
*
|
||
|
*
|
||
|
* History:
|
||
|
* 18-11-93 - ricktu - Created
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
DWORD
|
||
|
ComputeOrgDiscId(
|
||
|
int cdrom
|
||
|
)
|
||
|
{
|
||
|
int NumTracks,i;
|
||
|
DWORD DiscId = 0;
|
||
|
|
||
|
|
||
|
NumTracks = g_Devices[ cdrom ]->toc.LastTrack -
|
||
|
g_Devices[ cdrom ]->toc.FirstTrack + 1;
|
||
|
|
||
|
for ( i = 0; i < NumTracks; i++ ) {
|
||
|
DiscId = (DiscId << 1) ^
|
||
|
((i<<24) +
|
||
|
(TRACK_M(cdrom,i) << 16) +
|
||
|
(TRACK_S(cdrom,i) << 8) +
|
||
|
TRACK_F(cdrom,i) );
|
||
|
}
|
||
|
|
||
|
return DiscId;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************Private*Routine******************************\
|
||
|
* ErasePlayList
|
||
|
*
|
||
|
* Erases the current play list. This includes freeing the memory
|
||
|
* for the nodes in the play list, and resetting the current track
|
||
|
* pointer to NULL.
|
||
|
*
|
||
|
*
|
||
|
* History:
|
||
|
* 18-11-93 - ricktu - Created
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
VOID
|
||
|
ErasePlayList(
|
||
|
int cdrom
|
||
|
)
|
||
|
{
|
||
|
|
||
|
PTRACK_PLAY temp, temp1;
|
||
|
|
||
|
//
|
||
|
// Free memory for each track in play list
|
||
|
//
|
||
|
|
||
|
temp = PLAYLIST( cdrom );
|
||
|
while (temp!=NULL) {
|
||
|
|
||
|
temp1 = temp->nextplay;
|
||
|
LocalFree( (HLOCAL)temp );
|
||
|
temp = temp1;
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Reset pointers
|
||
|
//
|
||
|
|
||
|
PLAYLIST( cdrom ) = NULL;
|
||
|
CURRTRACK( cdrom ) = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* EraseSaveList
|
||
|
*
|
||
|
* Erases the current save list. This includes freeing the memory
|
||
|
* for the nodes in the save list.
|
||
|
*
|
||
|
*
|
||
|
* History:
|
||
|
* 18-11-93 - ricktu - Created
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
VOID
|
||
|
EraseSaveList(
|
||
|
int cdrom
|
||
|
)
|
||
|
{
|
||
|
|
||
|
PTRACK_PLAY temp, temp1;
|
||
|
|
||
|
//
|
||
|
// Free memory for each track in play list
|
||
|
//
|
||
|
|
||
|
|
||
|
temp = SAVELIST( cdrom );
|
||
|
while ( temp != NULL ) {
|
||
|
|
||
|
temp1 = temp->nextplay;
|
||
|
LocalFree( (HLOCAL)temp );
|
||
|
temp = temp1;
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Reset pointers
|
||
|
//
|
||
|
|
||
|
SAVELIST( cdrom ) = NULL;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************Private*Routine******************************\
|
||
|
* EraseTrackList
|
||
|
*
|
||
|
* Erases the current track list. This includes freeing the memory
|
||
|
* for the nodes in the track list, and resetting the track list
|
||
|
* pointer to NULL.
|
||
|
*
|
||
|
*
|
||
|
* History:
|
||
|
* 18-11-93 - ricktu - Created
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
VOID
|
||
|
EraseTrackList(
|
||
|
int cdrom
|
||
|
)
|
||
|
{
|
||
|
|
||
|
PTRACK_INF temp, temp1;
|
||
|
|
||
|
//
|
||
|
// Free memory for each track in track list
|
||
|
//
|
||
|
|
||
|
temp = ALLTRACKS( cdrom );
|
||
|
while ( temp != NULL ) {
|
||
|
|
||
|
temp1 = temp->next;
|
||
|
LocalFree( (HLOCAL)temp );
|
||
|
temp = temp1;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Reset pointers
|
||
|
//
|
||
|
|
||
|
ALLTRACKS( cdrom ) = NULL;
|
||
|
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* CopyPlayList
|
||
|
*
|
||
|
* Returns a copy of the playlist pointed to by p.
|
||
|
*
|
||
|
*
|
||
|
* History:
|
||
|
* 18-11-93 - ricktu - Created
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
PTRACK_PLAY
|
||
|
CopyPlayList(
|
||
|
PTRACK_PLAY p
|
||
|
)
|
||
|
{
|
||
|
|
||
|
PTRACK_PLAY t,t1,tend,tret;
|
||
|
|
||
|
tret = tend = NULL;
|
||
|
|
||
|
//
|
||
|
// Duplicate list pointed to by p.
|
||
|
//
|
||
|
|
||
|
t = p;
|
||
|
while( t!=NULL ) {
|
||
|
|
||
|
t1 = (PTRACK_PLAY)AllocMemory( sizeof(TRACK_PLAY) );
|
||
|
t1->TocIndex = t->TocIndex;
|
||
|
t1->min = t->min;
|
||
|
t1->sec = t->sec;
|
||
|
t1->nextplay = NULL;
|
||
|
t1->prevplay = tend;
|
||
|
|
||
|
if (tret==NULL) {
|
||
|
|
||
|
tret = tend = t1;
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
tend->nextplay = t1;
|
||
|
tend = t1;
|
||
|
}
|
||
|
|
||
|
t = t->nextplay;
|
||
|
|
||
|
}
|
||
|
|
||
|
return(tret);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************Private*Routine******************************\
|
||
|
* ResetPlayList
|
||
|
*
|
||
|
* Resets play order for the disc. Used to initialize/reset
|
||
|
* the play list. This is done by reseting the doubly-linked list
|
||
|
* of tracks in the g_Devices[...]->CdInfo.PlayList.[prevplay,nextplay]
|
||
|
* pointers. All the tracks on the CD are stored in a singly linked list
|
||
|
* pointed to by g_Devices[...]->CdInfo.AllTracks pointer.
|
||
|
*
|
||
|
*
|
||
|
* History:
|
||
|
* 18-11-93 - ricktu - Created
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
VOID
|
||
|
ResetPlayList(
|
||
|
int cdrom
|
||
|
)
|
||
|
{
|
||
|
PTRACK_INF t;
|
||
|
PTRACK_PLAY temp, prev;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Kill old play list
|
||
|
//
|
||
|
|
||
|
ErasePlayList( cdrom );
|
||
|
EraseSaveList( cdrom );
|
||
|
|
||
|
//
|
||
|
// Duplicate each node in AllTracks and insert in-order
|
||
|
// in SaveList list. The SaveList is the master which is
|
||
|
// used for the playlist.
|
||
|
//
|
||
|
|
||
|
t = ALLTRACKS( cdrom );
|
||
|
prev = NULL;
|
||
|
|
||
|
while (t!=NULL) {
|
||
|
|
||
|
temp = (PTRACK_PLAY)AllocMemory( sizeof(TRACK_PLAY) );
|
||
|
|
||
|
temp->TocIndex = t->TocIndex;
|
||
|
temp->min = 0;
|
||
|
temp->sec = 0;
|
||
|
temp->prevplay = prev;
|
||
|
temp->nextplay = NULL;
|
||
|
|
||
|
if (prev!=NULL) {
|
||
|
|
||
|
prev->nextplay = temp;
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
SAVELIST( cdrom ) = temp;
|
||
|
}
|
||
|
|
||
|
prev = temp;
|
||
|
t=t->next;
|
||
|
|
||
|
}
|
||
|
|
||
|
PLAYLIST( cdrom ) = CopyPlayList( SAVELIST( cdrom) );
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************Private*Routine******************************\
|
||
|
* DeleteEntry
|
||
|
*
|
||
|
* The ID format has changed to make the id's for the different CD's
|
||
|
* more unique. This routine will completely delete the old key value
|
||
|
* from the ini file. We remove it by writing a NULL entry.
|
||
|
*
|
||
|
*
|
||
|
* History:
|
||
|
* 18-11-93 - ricktu - Created
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
BOOL
|
||
|
DeleteEntry(
|
||
|
DWORD Id
|
||
|
)
|
||
|
{
|
||
|
TCHAR Section[80];
|
||
|
|
||
|
wsprintf( Section, g_szSectionF, Id );
|
||
|
return WritePrivateProfileSection( Section, g_szEmpty, g_IniFileName );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*****************************Private*Routine******************************\
|
||
|
* WriteEntry
|
||
|
*
|
||
|
* Write current disc information into database ini file.
|
||
|
* The section for the current disc (section name is a hex
|
||
|
* value of the disc id) is completely rewritten.
|
||
|
*
|
||
|
* This function uses 64K of stack !!
|
||
|
*
|
||
|
* History:
|
||
|
* 18-11-93 - ricktu - Created
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
BOOL
|
||
|
WriteEntry(
|
||
|
int cdrom
|
||
|
)
|
||
|
{
|
||
|
TCHAR *Buffer;
|
||
|
LPTSTR s;
|
||
|
int i;
|
||
|
TCHAR Section[ 10 ];
|
||
|
PTRACK_INF temp;
|
||
|
PTRACK_PLAY temp1;
|
||
|
BOOL fRc;
|
||
|
|
||
|
//
|
||
|
// Construct ini file buffer, form of:
|
||
|
//
|
||
|
// artist = artist name
|
||
|
// title = Title of disc
|
||
|
// numtracks = n
|
||
|
// 0 = Title of track 1
|
||
|
// 1 = Title of track 2
|
||
|
// n-1 = Title of track n
|
||
|
// order = 0 4 3 2 6 7 8 ... (n-1)
|
||
|
// numplay = # of entries in order list
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Is it legal to save this information?
|
||
|
//
|
||
|
|
||
|
if (!g_Devices[ cdrom ]->CdInfo.save)
|
||
|
return( TRUE );
|
||
|
|
||
|
Buffer = AllocMemory( 64000 * sizeof(TCHAR) );
|
||
|
// note: if the memory allocation fails, AllocMemory will terminate
|
||
|
// the application
|
||
|
|
||
|
g_Devices[ cdrom ]->CdInfo.IsVirginCd = FALSE;
|
||
|
|
||
|
s = Buffer;
|
||
|
|
||
|
s += 1 + wsprintf( s, g_szEntryTypeF, 1 );
|
||
|
s += 1 + wsprintf( s, g_szArtistF, g_Devices[ cdrom ]->CdInfo.Artist );
|
||
|
s += 1 + wsprintf( s, g_szTitleF, g_Devices[ cdrom ]->CdInfo.Title );
|
||
|
s += 1 + wsprintf( s, g_szNumTracksF, g_Devices[ cdrom ]->CdInfo.NumTracks );
|
||
|
|
||
|
for ( temp = g_Devices[ cdrom ]->CdInfo.AllTracks;
|
||
|
temp!=NULL; temp = temp->next ) {
|
||
|
|
||
|
s += 1 + wsprintf( s, TEXT("%d=%s"), temp->TocIndex, temp->name );
|
||
|
}
|
||
|
|
||
|
s += wsprintf( s, g_szOrderF );
|
||
|
|
||
|
i = 0;
|
||
|
for ( temp1 = g_Devices[ cdrom ]->CdInfo.SaveList;
|
||
|
temp1!=NULL; temp1 = temp1->nextplay ) {
|
||
|
|
||
|
s += wsprintf( s, TEXT("%d "), temp1->TocIndex );
|
||
|
i++;
|
||
|
|
||
|
}
|
||
|
s += 1;
|
||
|
|
||
|
s += 1 + wsprintf( s, g_szNumPlayF, i );
|
||
|
|
||
|
//
|
||
|
// Just make sure there are NULLs at end of buffer
|
||
|
//
|
||
|
|
||
|
wsprintf( s, g_szThreeNulls );
|
||
|
|
||
|
wsprintf( Section, g_szSectionF, g_Devices[ cdrom ]->CdInfo.Id );
|
||
|
|
||
|
//
|
||
|
// Try writing buffer into ini file
|
||
|
//
|
||
|
|
||
|
fRc = WritePrivateProfileSection( Section, Buffer, g_IniFileName );
|
||
|
|
||
|
LocalFree( (HLOCAL)Buffer );
|
||
|
return fRc;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* ReadMusicBoxEntry
|
||
|
*
|
||
|
* Try to parse the music box database ini file looking for the given disk
|
||
|
* id.
|
||
|
*
|
||
|
* History:
|
||
|
* dd-mm-94 - StephenE - Created
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
BOOL
|
||
|
ReadMusicBoxEntry(
|
||
|
int cdrom,
|
||
|
DWORD dwId
|
||
|
)
|
||
|
{
|
||
|
TCHAR Section[32];
|
||
|
|
||
|
TCHAR s[TITLE_LENGTH];
|
||
|
|
||
|
int i;
|
||
|
PTRACK_INF temp, curr;
|
||
|
|
||
|
g_Devices[ cdrom ]->CdInfo.iFrameOffset = NEW_FRAMEOFFSET;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Try to read in section from ini file. Note that music box stores
|
||
|
// the key in decimal NOT hex.
|
||
|
//
|
||
|
|
||
|
wsprintf( Section, TEXT("%ld"), dwId );
|
||
|
|
||
|
GetPrivateProfileString( Section, g_szDiscTitle, g_szNothingThere,
|
||
|
g_Devices[ cdrom ]->CdInfo.Title,
|
||
|
TITLE_LENGTH, g_szMusicBoxIni );
|
||
|
|
||
|
//
|
||
|
// Was the section found?
|
||
|
//
|
||
|
if ( _tcscmp(g_Devices[ cdrom ]->CdInfo.Title, g_szNothingThere) == 0 ) {
|
||
|
|
||
|
//
|
||
|
// Nope, notify caller
|
||
|
//
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Now read the track information. Also the artists name is unknown.
|
||
|
*/
|
||
|
|
||
|
_tcscpy( ARTIST(cdrom), IdStr(STR_UNKNOWN) );
|
||
|
|
||
|
NUMTRACKS(cdrom) = LASTTRACK(cdrom) - FIRSTTRACK(cdrom) + 1;
|
||
|
|
||
|
// Make sure there is at least one track!!!
|
||
|
if (0 == NUMTRACKS(cdrom)) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
for ( i = 0, curr = NULL; i < NUMTRACKS(cdrom); i++ ) {
|
||
|
|
||
|
wsprintf( s, g_szMusicBoxFormat, i + 1 );
|
||
|
|
||
|
temp = (PTRACK_INF)AllocMemory( sizeof(TRACK_INF) );
|
||
|
|
||
|
GetPrivateProfileString( Section, s, s, temp->name,
|
||
|
TRACK_TITLE_LENGTH, g_szMusicBoxIni );
|
||
|
temp->TocIndex = i;
|
||
|
temp->next = NULL;
|
||
|
|
||
|
if ( curr == NULL ) {
|
||
|
|
||
|
ALLTRACKS( cdrom ) = curr = temp;
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
curr->next = temp;
|
||
|
curr = temp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Make sure there is at least one track in Default playlist!!!
|
||
|
if (NULL == ALLTRACKS(cdrom)) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
_tcscpy( ARTIST(cdrom), IdStr(STR_UNKNOWN) );
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Process the play list
|
||
|
*/
|
||
|
|
||
|
GetPrivateProfileString( Section, g_szPlayList, g_szNothingThere,
|
||
|
s, TITLE_LENGTH, g_szMusicBoxIni );
|
||
|
|
||
|
/*
|
||
|
** Was the section found?
|
||
|
*/
|
||
|
if ( _tcscmp(g_Devices[ cdrom ]->CdInfo.Title, g_szNothingThere) == 0 ) {
|
||
|
|
||
|
/*
|
||
|
** Nope, just use the default playlist.
|
||
|
*/
|
||
|
|
||
|
ResetPlayList( cdrom );
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
LPTSTR lpPlayList, porder;
|
||
|
PTRACK_PLAY temp1, prev;
|
||
|
int i;
|
||
|
const PLAYLEN = 8192;
|
||
|
|
||
|
lpPlayList = AllocMemory( sizeof(TCHAR) * PLAYLEN );
|
||
|
|
||
|
GetPrivateProfileString( Section, g_szPlayList, g_szNothingThere,
|
||
|
lpPlayList, PLAYLEN, g_szMusicBoxIni );
|
||
|
|
||
|
_tcscat( lpPlayList, g_szBlank );
|
||
|
porder = lpPlayList;
|
||
|
prev = NULL;
|
||
|
|
||
|
while ( *porder && (_stscanf( porder, TEXT("%d"), &i ) == 1) ) {
|
||
|
|
||
|
i--;
|
||
|
|
||
|
/*
|
||
|
** Assert that i is a valid index.
|
||
|
** ie 0 <= i <= (NUMTRACKS(cdrom) - 1)
|
||
|
*/
|
||
|
|
||
|
i = min( (NUMTRACKS(cdrom) - 1), max( 0, i ) );
|
||
|
|
||
|
temp1 = (PTRACK_PLAY)AllocMemory( sizeof(TRACK_PLAY) );
|
||
|
temp1->TocIndex = i;
|
||
|
temp1->min = 0;
|
||
|
temp1->sec = 0;
|
||
|
temp1->prevplay = prev;
|
||
|
temp1->nextplay = NULL;
|
||
|
|
||
|
if (prev == NULL) {
|
||
|
|
||
|
SAVELIST( cdrom ) = temp1;
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
prev->nextplay = temp1;
|
||
|
}
|
||
|
|
||
|
prev = temp1;
|
||
|
|
||
|
porder = _tcschr( porder, TEXT(' ') ) + 1;
|
||
|
}
|
||
|
|
||
|
// Make sure there is at least one track in SAVED playlist!!!
|
||
|
if (NULL == SAVELIST(cdrom)) {
|
||
|
// Nope, just use the default playlist instead!!!
|
||
|
ResetPlayList( cdrom );
|
||
|
}
|
||
|
|
||
|
PLAYLIST( cdrom ) = CopyPlayList( SAVELIST( cdrom ) );
|
||
|
|
||
|
LocalFree( (HLOCAL)lpPlayList );
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*****************************Private*Routine******************************\
|
||
|
* ReadEntry
|
||
|
*
|
||
|
* Try to read entry for new disc from database ini file.
|
||
|
* The section name we are trying to read is a hex
|
||
|
* value of the disc id. If the sections is found,
|
||
|
* fill in the data for the disc in the cdrom drive.
|
||
|
*
|
||
|
* This function uses over 16K of stack space !!
|
||
|
*
|
||
|
* History:
|
||
|
* 18-11-93 - ricktu - Created
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
BOOL
|
||
|
ReadEntry(
|
||
|
int cdrom,
|
||
|
DWORD dwId
|
||
|
)
|
||
|
{
|
||
|
|
||
|
DWORD rc;
|
||
|
TCHAR Section[10];
|
||
|
TCHAR s[100],s1[100];
|
||
|
TCHAR order[ 8192 ];
|
||
|
TCHAR torder[ 8192 ];
|
||
|
int i;
|
||
|
LPTSTR porder;
|
||
|
int numtracks, numplay;
|
||
|
PTRACK_INF temp, curr;
|
||
|
PTRACK_PLAY temp1, prev;
|
||
|
BOOL OldEntry;
|
||
|
BOOL fRewriteEntry = FALSE;
|
||
|
|
||
|
|
||
|
g_Devices[ cdrom ]->CdInfo.iFrameOffset = NEW_FRAMEOFFSET;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Try to read in section from ini file
|
||
|
//
|
||
|
|
||
|
wsprintf( Section, g_szSectionF, dwId );
|
||
|
|
||
|
rc = GetPrivateProfileString( Section, g_szTitle, g_szNothingThere,
|
||
|
g_Devices[ cdrom ]->CdInfo.Title,
|
||
|
TITLE_LENGTH, g_IniFileName );
|
||
|
|
||
|
//
|
||
|
// Was the section found?
|
||
|
//
|
||
|
|
||
|
if ( _tcscmp(g_Devices[ cdrom ]->CdInfo.Title, g_szNothingThere) == 0 ) {
|
||
|
|
||
|
//
|
||
|
// Nope, notify caller
|
||
|
//
|
||
|
|
||
|
return( FALSE );
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// We found an entry for this disc, so copy all the information
|
||
|
// from the ini file entry
|
||
|
//
|
||
|
// Is this an old entry?
|
||
|
//
|
||
|
|
||
|
i = GetPrivateProfileInt( Section, g_szEntryType, 0, g_IniFileName );
|
||
|
|
||
|
OldEntry = (i==0);
|
||
|
|
||
|
numtracks = GetPrivateProfileInt( Section, g_szNumTracks,
|
||
|
0, g_IniFileName );
|
||
|
|
||
|
// Make sure there is at least one track!!!
|
||
|
if (0 == numtracks) {
|
||
|
fRewriteEntry = TRUE;
|
||
|
}
|
||
|
|
||
|
g_Devices[ cdrom ]->CdInfo.NumTracks = numtracks;
|
||
|
|
||
|
rc = GetPrivateProfileString( Section, g_szArtist, g_szUnknownTxt,
|
||
|
(LPTSTR)ARTIST(cdrom), ARTIST_LENGTH,
|
||
|
g_IniFileName );
|
||
|
|
||
|
//
|
||
|
// Validate the stored track numbers
|
||
|
//
|
||
|
if (g_Devices[cdrom]->fIsTocValid) {
|
||
|
|
||
|
int maxTracks; // validate the high point in ini file
|
||
|
|
||
|
maxTracks = g_Devices[cdrom]->toc.LastTrack;
|
||
|
|
||
|
if (numtracks > maxTracks) {
|
||
|
// Current ini file contains invalid data
|
||
|
// this can result in the CD not playing at all as the end
|
||
|
// point is likely to be invalid
|
||
|
g_Devices[ cdrom ]->CdInfo.NumTracks
|
||
|
= numtracks
|
||
|
= maxTracks;
|
||
|
fRewriteEntry = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Read the track list information
|
||
|
//
|
||
|
|
||
|
for (i=0, curr = NULL; i < numtracks; i++) {
|
||
|
|
||
|
temp = (PTRACK_INF)AllocMemory( sizeof(TRACK_INF) );
|
||
|
temp->TocIndex = i;
|
||
|
temp->next = NULL;
|
||
|
wsprintf( s1, IdStr(STR_INIT_TRACK), i + 1 );
|
||
|
wsprintf( s, TEXT("%d"), i );
|
||
|
rc = GetPrivateProfileString( Section, s, s1, (LPTSTR)temp->name,
|
||
|
TRACK_TITLE_LENGTH, g_IniFileName );
|
||
|
|
||
|
if (curr==NULL) {
|
||
|
|
||
|
ALLTRACKS( cdrom ) = curr = temp;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
curr->next = temp;
|
||
|
curr = temp;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// Make sure there is at least one entry in TRACK list
|
||
|
if (ALLTRACKS(cdrom) == NULL)
|
||
|
{
|
||
|
fRewriteEntry = TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// if we detected a problem in the ini file, or the entry is an
|
||
|
// old format, rewrite the section.
|
||
|
//
|
||
|
|
||
|
if (OldEntry || fRewriteEntry) {
|
||
|
|
||
|
//
|
||
|
// Generate generic play list (all tracks in order)
|
||
|
//
|
||
|
|
||
|
ResetPlayList( cdrom );
|
||
|
|
||
|
//
|
||
|
// Need to rewrite this entry in new format
|
||
|
//
|
||
|
|
||
|
WriteEntry( cdrom );
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
//
|
||
|
// Read play list (order) information and construct play list doubly
|
||
|
// linked list
|
||
|
//
|
||
|
|
||
|
numplay = GetPrivateProfileInt( Section, g_szNumPlay,
|
||
|
0, g_IniFileName );
|
||
|
|
||
|
porder = torder;
|
||
|
ZeroMemory( porder, sizeof(torder) );
|
||
|
|
||
|
//
|
||
|
// construct a default play order list
|
||
|
//
|
||
|
|
||
|
for ( i = 0; i < numtracks; i++ ) {
|
||
|
|
||
|
wsprintf( porder, TEXT("%d "), i );
|
||
|
/* porder += (_tcslen( porder ) * sizeof( TCHAR )); */
|
||
|
porder += _tcslen( porder );
|
||
|
|
||
|
}
|
||
|
|
||
|
rc = GetPrivateProfileString( Section, g_szOrder,
|
||
|
torder, (LPTSTR)order, 8192,
|
||
|
g_IniFileName );
|
||
|
|
||
|
//
|
||
|
// Ensure a trailing space
|
||
|
//
|
||
|
|
||
|
_tcscat( order, g_szBlank );
|
||
|
porder = order;
|
||
|
prev = NULL;
|
||
|
|
||
|
while ( *porder && (_stscanf( porder, TEXT("%d"), &i ) == 1) ) {
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Assert that i is a valid index.
|
||
|
** ie 0 <= i <= (numtracks - 1)
|
||
|
*/
|
||
|
|
||
|
i = min( (numtracks - 1), max( 0, i ) );
|
||
|
|
||
|
temp1 = (PTRACK_PLAY)AllocMemory( sizeof(TRACK_PLAY) );
|
||
|
temp1->TocIndex = i;
|
||
|
temp1->min = 0;
|
||
|
temp1->sec = 0;
|
||
|
temp1->prevplay = prev;
|
||
|
temp1->nextplay = NULL;
|
||
|
|
||
|
if (prev==NULL) {
|
||
|
|
||
|
SAVELIST( cdrom ) = temp1;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
prev->nextplay = temp1;
|
||
|
|
||
|
}
|
||
|
prev = temp1;
|
||
|
|
||
|
porder = _tcschr( porder, g_chBlank ) + 1;
|
||
|
|
||
|
}
|
||
|
|
||
|
// Make sure there is at least one entry in SAVED list
|
||
|
if (SAVELIST(cdrom) == NULL)
|
||
|
{
|
||
|
// Nope, use default list instead
|
||
|
ResetPlayList( cdrom );
|
||
|
WriteEntry( cdrom );
|
||
|
}
|
||
|
|
||
|
PLAYLIST( cdrom ) = CopyPlayList( SAVELIST( cdrom ) );
|
||
|
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* WriteSettings
|
||
|
*
|
||
|
*
|
||
|
*
|
||
|
* History:
|
||
|
* 18-11-93 - ricktu - Created
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
BOOL
|
||
|
WriteSettings(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
WINDOWPLACEMENT wndpl;
|
||
|
HKEY hKey;
|
||
|
LONG lRet;
|
||
|
DWORD dwTmp;
|
||
|
extern BOOL g_fTitlebarShowing; //cdplayer.c
|
||
|
extern int cyMenuCaption; //cdplayer.c
|
||
|
|
||
|
lRet = RegCreateKey( HKEY_CURRENT_USER, g_szRegistryKey, &hKey );
|
||
|
if ( lRet != ERROR_SUCCESS) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Save settings on exit
|
||
|
dwTmp = (DWORD)g_fSaveOnExit;
|
||
|
RegSetValueEx( hKey, g_szSaveSettingsOnExit, 0L, REG_DWORD,
|
||
|
(LPBYTE)&dwTmp, sizeof(dwTmp) );
|
||
|
|
||
|
if ( !g_fSaveOnExit ) {
|
||
|
|
||
|
RegCloseKey( hKey );
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Small LED font
|
||
|
dwTmp = (DWORD)g_fSmallLedFont;
|
||
|
RegSetValueEx( hKey, g_szSmallFont, 0L, REG_DWORD,
|
||
|
(LPBYTE)&dwTmp, sizeof(dwTmp) );
|
||
|
|
||
|
// Enable Tooltips
|
||
|
dwTmp = (DWORD)g_fToolTips;
|
||
|
RegSetValueEx( hKey, g_szToolTips, 0L, REG_DWORD,
|
||
|
(LPBYTE)&dwTmp, sizeof(dwTmp) );
|
||
|
|
||
|
// Stop CD playing on exit
|
||
|
dwTmp = (DWORD)g_fStopCDOnExit;
|
||
|
RegSetValueEx( hKey, g_szStopCDPlayingOnExit, 0L, REG_DWORD,
|
||
|
(LPBYTE)&dwTmp, sizeof(dwTmp) );
|
||
|
|
||
|
// Currect track time
|
||
|
dwTmp = (DWORD)g_fDisplayT;
|
||
|
RegSetValueEx( hKey, g_szDisplayT, 0L, REG_DWORD,
|
||
|
(LPBYTE)&dwTmp, sizeof(dwTmp) );
|
||
|
|
||
|
// Time remaining for this track
|
||
|
dwTmp = (DWORD)g_fDisplayTr;
|
||
|
RegSetValueEx( hKey, g_szDisplayTr, 0L, REG_DWORD,
|
||
|
(LPBYTE)&dwTmp, sizeof(dwTmp) );
|
||
|
|
||
|
// Time remaining for this play list
|
||
|
dwTmp = (DWORD)g_fDisplayDr;
|
||
|
RegSetValueEx( hKey, g_szDisplayDr, 0L, REG_DWORD,
|
||
|
(LPBYTE)&dwTmp, sizeof(dwTmp) );
|
||
|
|
||
|
// Play in selected order
|
||
|
dwTmp = (DWORD)g_fSelectedOrder;
|
||
|
RegSetValueEx( hKey, g_szInOrderPlay, 0L, REG_DWORD,
|
||
|
(LPBYTE)&dwTmp, sizeof(dwTmp) );
|
||
|
|
||
|
// Use single disk
|
||
|
dwTmp = (DWORD)!g_fSingleDisk;
|
||
|
RegSetValueEx( hKey, g_szMultiDiscPlay, 0L, REG_DWORD,
|
||
|
(LPBYTE)&dwTmp, sizeof(dwTmp) );
|
||
|
|
||
|
// Intro play ( Default 10Secs)
|
||
|
dwTmp = (DWORD)g_fIntroPlay;
|
||
|
RegSetValueEx( hKey, g_szIntroPlay, 0L, REG_DWORD,
|
||
|
(LPBYTE)&dwTmp, sizeof(dwTmp) );
|
||
|
|
||
|
dwTmp = (DWORD)g_IntroPlayLength;
|
||
|
RegSetValueEx( hKey, g_szIntroPlayLen, 0L, REG_DWORD,
|
||
|
(LPBYTE)&dwTmp, sizeof(dwTmp) );
|
||
|
|
||
|
// Continuous play (loop at end)
|
||
|
dwTmp = (DWORD)g_fContinuous;
|
||
|
RegSetValueEx( hKey, g_szContinuousPlay, 0L, REG_DWORD,
|
||
|
(LPBYTE)&dwTmp, sizeof(dwTmp) );
|
||
|
|
||
|
// Show toolbar
|
||
|
dwTmp = (DWORD)g_fToolbarVisible;
|
||
|
RegSetValueEx( hKey, g_szToolbar, 0L, REG_DWORD,
|
||
|
(LPBYTE)&dwTmp, sizeof(dwTmp) );
|
||
|
|
||
|
// Show track information
|
||
|
dwTmp = (DWORD)g_fTrackInfoVisible;
|
||
|
RegSetValueEx( hKey, g_szDiscAndTrackDisplay, 0L, REG_DWORD,
|
||
|
(LPBYTE)&dwTmp, sizeof(dwTmp) );
|
||
|
|
||
|
// Show track status bar
|
||
|
dwTmp = (DWORD)g_fStatusbarVisible;
|
||
|
RegSetValueEx( hKey, g_szStatusBar, 0L, REG_DWORD,
|
||
|
(LPBYTE)&dwTmp, sizeof(dwTmp) );
|
||
|
|
||
|
|
||
|
// Save window position.
|
||
|
wndpl.length = sizeof(WINDOWPLACEMENT);
|
||
|
GetWindowPlacement(g_hwndApp,&wndpl);
|
||
|
if (!g_fTitlebarShowing) {
|
||
|
wndpl.rcNormalPosition.top -= cyMenuCaption;
|
||
|
}
|
||
|
|
||
|
// X pos
|
||
|
dwTmp = (DWORD)wndpl.rcNormalPosition.left;
|
||
|
RegSetValueEx( hKey, g_szWindowOriginX, 0L, REG_DWORD,
|
||
|
(LPBYTE)&dwTmp, sizeof(dwTmp) );
|
||
|
|
||
|
// Y pos
|
||
|
dwTmp = (DWORD)wndpl.rcNormalPosition.top;
|
||
|
RegSetValueEx( hKey, g_szWindowOriginY, 0L, REG_DWORD,
|
||
|
(LPBYTE)&dwTmp, sizeof(dwTmp) );
|
||
|
|
||
|
RegCloseKey( hKey );
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* AddFindEntry
|
||
|
*
|
||
|
* Search the database file for the current disc, if found, read the
|
||
|
* information, otherwise, generate some default artist and track names etc.
|
||
|
* but don't store this in the database. A new entry is only added to the
|
||
|
* database after the user has used the "Edit Track Titles" dialog box.
|
||
|
*
|
||
|
* The design of this function is complicated by the fact that we have to
|
||
|
* support two previous attempts at generating CDplayer keys. Also, we try
|
||
|
* to support the MusicBox key format now that it is compatible with the
|
||
|
* new CDplayer format.
|
||
|
*
|
||
|
*
|
||
|
* History:
|
||
|
* 18-11-93 - ricktu - Created
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
VOID
|
||
|
AddFindEntry(
|
||
|
int cdrom,
|
||
|
DWORD key,
|
||
|
PCDROM_TOC lpTOC
|
||
|
)
|
||
|
{
|
||
|
|
||
|
int i, num;
|
||
|
PTRACK_INF temp, temp1;
|
||
|
|
||
|
/*
|
||
|
** Kill off old PlayList, Save lists if they exists.
|
||
|
*/
|
||
|
|
||
|
ErasePlayList( cdrom );
|
||
|
EraseSaveList( cdrom );
|
||
|
EraseTrackList( cdrom );
|
||
|
|
||
|
/*
|
||
|
** Check ini file for an existing entry
|
||
|
**
|
||
|
** First Look in cdplayer.ini using the new key, return if found
|
||
|
*/
|
||
|
|
||
|
// We initialize this field early, otherwise ReadEntry will not be
|
||
|
// able to save any new information (or lose invalid).
|
||
|
g_Devices[ cdrom ]->CdInfo.save = TRUE;
|
||
|
|
||
|
if ( ReadEntry(cdrom, key) ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Initialize these fields
|
||
|
*/
|
||
|
g_Devices[ cdrom ]->CdInfo.IsVirginCd = FALSE;
|
||
|
g_Devices[ cdrom ]->CdInfo.Id = key;
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Look again in cdplayer.ini. This time use the original cdplayer key.
|
||
|
** If we found the original key in cdplayer.ini write the new key into
|
||
|
** cdplayer.ini and then return
|
||
|
*/
|
||
|
|
||
|
if ( ReadEntry(cdrom, ComputeOrgDiscId(cdrom)) ) {
|
||
|
|
||
|
/*
|
||
|
** If the disc was under an Original id, we need to delete the
|
||
|
** old one, convert it to the new format, and save it under
|
||
|
** its new key.
|
||
|
*/
|
||
|
|
||
|
DeleteEntry( ComputeOrgDiscId(cdrom) );
|
||
|
WriteEntry( cdrom );
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Final look in cdplayer.ini. This time use the OLD cdplayer key.
|
||
|
** If we found the OLD key in cdplayer.ini write the new key into
|
||
|
** cdplayer.ini and then return
|
||
|
*/
|
||
|
|
||
|
else if ( ReadEntry(cdrom, ComputeOldDiscId(cdrom)) ) {
|
||
|
|
||
|
/*
|
||
|
** If the disc was under an OLD id, we need to delete the
|
||
|
** old one, convert it to the new format, and save it under
|
||
|
** its new key.
|
||
|
*/
|
||
|
|
||
|
DeleteEntry( ComputeOldDiscId(cdrom) );
|
||
|
WriteEntry( cdrom );
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Couldn't find it in cdplayer.ini, now look for the key in musicbox.ini
|
||
|
** If we found the key in musicbox.ini write it into cdplayer.ini and
|
||
|
** then return
|
||
|
*/
|
||
|
|
||
|
else if ( ReadMusicBoxEntry(cdrom, key) ) {
|
||
|
|
||
|
WriteEntry( cdrom );
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
** This is a new entry, fill it in but don't store it in the database.
|
||
|
*/
|
||
|
|
||
|
else {
|
||
|
|
||
|
g_Devices[ cdrom ]->CdInfo.IsVirginCd = TRUE;
|
||
|
|
||
|
wsprintf( (LPTSTR)ARTIST( cdrom ), IdStr( STR_NEW_ARTIST ) );
|
||
|
wsprintf( (LPTSTR)TITLE( cdrom ), IdStr( STR_NEW_TITLE ) );
|
||
|
|
||
|
NUMTRACKS( cdrom ) = num = lpTOC->LastTrack - lpTOC->FirstTrack + 1;
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Create generic playlist, which is all audio tracks
|
||
|
** played in the order they are on the CD. First, create
|
||
|
** a singly linked list that contains all the tracks.
|
||
|
** Then, create a double linked list, using the nodes of
|
||
|
** from the single linked list for the play list.
|
||
|
*/
|
||
|
|
||
|
|
||
|
for( i = 0; i < num; i++ ) {
|
||
|
|
||
|
/*
|
||
|
** Create storage for track
|
||
|
*/
|
||
|
|
||
|
temp = (PTRACK_INF)AllocMemory( sizeof(TRACK_INF) );
|
||
|
|
||
|
/*
|
||
|
** Initialize information (storage already ZERO initialized)
|
||
|
*/
|
||
|
|
||
|
wsprintf( (LPTSTR)temp->name, IdStr( STR_INIT_TRACK ), i+1 );
|
||
|
temp->TocIndex = i;
|
||
|
temp->next = NULL;
|
||
|
|
||
|
/*
|
||
|
** Add node to singly linked list of all tracks
|
||
|
*/
|
||
|
|
||
|
if (i == 0) {
|
||
|
|
||
|
temp1 = ALLTRACKS( cdrom ) = temp;
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
temp1->next = temp;
|
||
|
temp1 = temp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Generate generic play list (all tracks in order)
|
||
|
*/
|
||
|
|
||
|
ResetPlayList( cdrom );
|
||
|
}
|
||
|
}
|