📄 cdrom.cpp
字号:
/*C4*/
//****************************************************************
// Author: Jethro Wright, III TS : 1/20/1994 19:39
// Date: 01/01/1994
//
// cdrom.cpp : cd-rom audio interface class for dos
// and windows (as a dll) via mscdex....
//
// History:
// 01/01/1994 jw3 also sprach zarathustra....
//****************************************************************/
//
// the principal purpose of this simple c++ utility
// framework is to provide the basis for a simple
// audio cd util under dos as well as supplement the
// multimedia cd audio facils under windows. as of
// this writing, msoft hasn't provided a means of
// id'ing audio cds for windows.
// unfortunately, audio cd manufacuturers don't
// always include a upc on audio cds, which would
// provide an irrefutable and universal means of
// identifying cds. therefore, this project has
// been undertaken w/ the hope that it'll be
// possible to use basic mscdex services to address
// this oversight. (famous last words....) if
// nothing else, like myself, you'll learn about
// the basics of audio cd pgmg by digging into this
// code, as i knew nothing about it prior to this
// effort.
//
// the code started life from an incomplete C pgm
// discovered in the bbs ether, by an anonymous
// author. i've attempted to document some of the
// less obvious details of mscdex audio cd pgmg
// and complete the work, by providing a neat little
// shell pgm, which demonstrates the use of the classes.
// the pgm and classes are hereby committed to the
// public domain and you are free to use them, in
// whatever way you see fit.
//
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// IF YOU DO USE THIS CODE IN ANY PROJECT, YOU'RE
// COMPLETELY RESPONSIBLE FOR ALL DAMAGES INCURRED BY
// ITS USE. IN OTHER WORDS, WHETHER MODIFIED OR NOT,
// I ACCEPT NO RESPONSIBILITY FOR ANY USE OF THE CODE
// OR THE PROGRAM PROVIDED WITH THIS KIT.
//
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// perhaps you may want to clean the code up a bit.
// personally, i've gotten tired of playing w/ it
// (under dos), but it's pretty modular as c++ class
// libs go, however there is room for improvement.
//
// essentially, one simply instantiates a CDRom object
// it's off to the races, sending commands to the
// object and watching the results. main.cpp illustrates
// a simple pgm that uses most, if not all, of the
// functionality of the class lib. prior to instantiating
// the CDRom object, one must call CDRom::InitClass() to
// initialize the lib -> mscdex interface. this fn
// returns the nbr of drives mscdex knows about. had
// i been a little more fastidious, i might have added
// a fn to present a list of drives from which one
// could choose a particular cdrom drive, if more than
// one unit were attached to a system. since i don't
// have a means of testing this facil, it wasn't
// included, altho it would be very simple to write.
// who knows, as i'm writing this prior to setting up
// the final archive, such a routine *might* even make it
// into the kit....
//
// also to be found in this kit is the mscdex 2.20
// spec. this was the spec that was the basis of the
// work provided. among other things, it has an rtf
// (microsoft word) version of the spec, which will
// make it possible to generate a pretty-printed
// copy of the document.
//
// the principal CDRom mbr fns are generally very simple
// and could have been written as inline fns, but i
// wasn't sure how complex i'd want to make to the command
// dispatching when i started coding them. again, for
// those who're a bit more anal retentive than myself,
// the src code is available for add'l modification.
//
// commands are dispatched to the cdrom driver via
// an ioctl object. the public mbr fns it supports
// are all related to cd audio operations. an ioctl
// object only needs to know which unit (to be precise,
// the sub-unit nbr) and the addresses of the cdrom
// driver's strategy and interrupt functions. most
// of these operations could've been inlined, but
// besides my lack of enthusiasm to labor on this too
// much more, i also don't want to see the executable
// size grow anymore. the exe is currently 33 kb, of
// which 90+ % is the library itself. inlining more
// of the code wouldn't have helped the size situation
// and couldn't have done much (if anything) to improve
// performance.
//
// things to look out for: audio cd track timing isn't
// as perfect as one might expect. that is, i've
// noted minor discrepencies bet what's written on
// cd liner and what's actually on the disc. nothing
// more than two or three seconds per track and, in my
// opinion, not worth the bother of splitting hairs
// for code that *might* make things absolutely perfect.
// - *no* error handling code. since the consumer (the
// user of the classes) can interrogate any meaningful
// status information before initiating any cmd and
// bec the cmds are *so* straight-fwd, it was decided to
// leave out a safety net. as noted elsewhere, it might
// not be a good idea to interrogate the toc while a play
// operation is underway, as this might interrupt the
// audio pgm, depending on the cd driver sware. my
// limited testing hasn't encountered this prob, but a
// full-blown cd audio player app should have the option to
// deal w/ this contingency. btw, any CDRom play fn will
// stop the current audio pgm, in order to start a new pgm.
// but this was dictated by the cdrom sub-system used to
// develop this code (a sony cdu-31a, a sub-system to be
// avoided, if at all possible.)
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <dos.h>
#include "types.h" // needed for our basic data types
#include "device.h" // device driver and device cmd stuff
#include "ioctl.hpp" // to communicate w/ the drivers
// themselves
#include "cdrom.hpp"
static union REGS inRegs, outRegs ; // == used by the DOS interface
static struct SREGS segRegs ; // routines
static DeviceList deviceTable[ 26 ] ; // == up to 26 cdrom drives supported
// the obligatory dummy initializations that c++ demands for
// static (class) mbr varbls....
int CDRom::version = 0,
CDRom::firstLetter = 0,
CDRom::nbrOfDrives = 0 ;
//********************************************************
//
// CDRom::CDRom :-
//
// prior to using this cstor the consumer must use
// the static (class) InitClass mbr fn to setup the
// internal list of cdrom drives, which will also
// return the nbr of available drives. as w/ all
// operations covered by this system, there is *no*
// error checking for procedural foul-ups, so let the
// consumer beware....
//
//********************************************************/
CDRom::CDRom( int cdDrv ) :
cmdInterface( cdDrv, ( int ) deviceTable[ cdDrv ].subUnit,
MK_FP( FP_SEG( deviceTable[ cdDrv ].deviceAddress ),
deviceTable[ cdDrv ].deviceAddress->deviceStrat ),
MK_FP( FP_SEG( deviceTable[ cdDrv ].deviceAddress ),
deviceTable[ cdDrv ].deviceAddress->deviceEntry ) )
{
// this shudn't be needed, but let's keep it around anyway....
cdDriveNbr = cdDrv ;
GetDeviceStatus() ; // find out if anything is happening
}
//********************************************************
//
// CDRom::~CDRom :-
//
// don't really need an explicit dstor for the
// moment....
//
//********************************************************/
CDRom::~CDRom()
{
}
//********************************************************
//
// CDRom::InitClass :-
//
// this static (class) mbr fn is to be called prior
// to instancing the 1st CDRom obj, in order to extract
// the cdrom device table from dos/mscdex. returns
// the nbr of drives or zero if mscdex isn't loaded.
//
//********************************************************/
int CDRom::InitClass( void )
{
// get number of cdrom drive letters from mscdex, via the dos multiplex
// interrupt
inRegs.x.ax = 0x1500 ;
inRegs.x.bx = 0 ; // will be unmodified if mscdex isn't
int86( 0x2f, &inRegs, &outRegs ) ; // loaded
if( outRegs.x.bx == 0 ) {
return( 0 ) ;
}
CDRom::nbrOfDrives = outRegs.x.bx ;
CDRom::firstLetter = outRegs.x.cx ;
// get cdrom drive device list
inRegs.x.ax = 0x1501 ;
inRegs.x.bx = FP_OFF( ( DeviceList far * ) &deviceTable ) ;
segRegs.es = FP_SEG( ( DeviceList far * ) &deviceTable ) ;
int86x( 0x2f, &inRegs, &outRegs, &segRegs ) ;
// finally, get the mscdex version code, but it only works for
// mscdex 2.00 and above....
inRegs.x.ax = 0x150C ;
inRegs.x.bx = 0 ;
int86x( 0x2f, &inRegs, &outRegs, &segRegs ) ;
CDRom::version = outRegs.x.bx ;
// returns the nbr of drives or zero if this failed for some bizzare
// reason, bec mscdex is in fact loaded and it wouldn't be around if
// the cdrom device driver didn't load and normally they don't seem
// to load if a working drive isn't detected....
return( ! outRegs.x.cflag ? CDRom::nbrOfDrives : 0 ) ;
}
//********************************************************
//
// CDRom::GetUPC :-
//
// get the upc code from the disk, if it exists.
// the function returns non-zero if found or
// zero if not found. the consumer can subsequently
// interrogate the driver for the precise failure (per
// the mscdex spec by calling GetErrorCode() immediately
// after calling GetUPC()....
// we really have no way of knowing if all of this works
// bec there are apparently so few disks that possess the
// code....
//
//********************************************************/
int CDRom::GetUPC( DWORD far * upcCode )
{
int i ;
WORD st ;
DWORD tmp = 0 ;
UPCCommand upc ;
memset( &upc, 0, sizeof( UPCCommand ) ) ;
lastStatus = cmdInterface.GetUPC( ( struct UPCCommand far * ) &upc ) ;
// mscdex sez that the cmd will retn an sect not fnd err if the operation
// is supported by the driver, but the upc was missing/not found or
// an unknwn cmd if not supported
st = GetErrorCode() ;
if ( st == ERROR_UNKWN_CMD || st == ERROR_SECT_NOT_FND )
return( 0 ) ;
// assumes the upc is a bcd value, which isn't entirely clear from the
// mscdex spec....
for ( i = 0 ; i <= 7 ; i++ ) {
tmp *= 10L ;
tmp = ( ( upc.upc[ i ] >> 4 ) * 10 ) + ( upc.upc[ i ] & 0x0f ) + tmp ;
}
// if the control byte is 0 or if the upc itself is 0, then no UPC was
// found, so synthesize the sector not fnd error
if ( upc.controlAddress == 0 || tmp == 0L ) {
st = lastStatus & 0xff00 ;
lastStatus = st | ERROR_SECT_NOT_FND ;
return 0 ;
}
*upcCode = tmp ;
return( 1 ) ;
}
//********************************************************
//
// CDRom::GetDeviceStatus :-
//
// get the most up-to-date device status from the
// cd and return it to the caller....
//
//********************************************************/
DWORD CDRom::GetDeviceStatus( void )
{
DWORD cdStatus ;
lastStatus = cmdInterface.GetDeviceStatus( ( DWORD far * ) &cdStatus ) ;
return cdStatus ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -