748 lines
18 KiB
C
748 lines
18 KiB
C
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cddump.c
|
|
|
|
Abstract:
|
|
|
|
parses commands and acts
|
|
|
|
Environment:
|
|
|
|
User mode only
|
|
|
|
Revision History:
|
|
|
|
05-26-98 : Created
|
|
|
|
--*/
|
|
|
|
#include "common.h"
|
|
|
|
#define VERSION_MAJOR 1
|
|
#define VERSION_MINOR 0
|
|
#define VERSION_STRING "1.00"
|
|
|
|
|
|
ULONG32
|
|
TestCommand(
|
|
HANDLE device,
|
|
int argc,
|
|
char *argv[]
|
|
);
|
|
|
|
ULONG32
|
|
ListCommand(
|
|
HANDLE device,
|
|
int argc,
|
|
char *argv[]
|
|
);
|
|
|
|
ULONG32
|
|
DumpTrackCommand(
|
|
HANDLE device,
|
|
int argc,
|
|
char *argv[]
|
|
);
|
|
|
|
ULONG32
|
|
VerifyHeaderCommand(
|
|
HANDLE device,
|
|
int argc,
|
|
char *argv[]
|
|
);
|
|
|
|
ULONG32
|
|
ReadTOCCommand(
|
|
HANDLE device,
|
|
int argc,
|
|
char *argv[]
|
|
);
|
|
|
|
ULONG32
|
|
DumpSectorCommand(
|
|
HANDLE device,
|
|
int argc,
|
|
char *argv[]
|
|
);
|
|
|
|
//
|
|
// Each structure instance can have a function pointer, name, and description
|
|
//
|
|
|
|
typedef struct {
|
|
char *Name;
|
|
char *Description;
|
|
ULONG32 (*Function)(HANDLE device, int argc, char *argv[]);
|
|
} COMMAND;
|
|
|
|
//
|
|
// List of commands
|
|
// all command names are case sensitive
|
|
// arguments are passed into command routines
|
|
// list must be terminated with NULL command
|
|
// command will not be listed in help if description == NULL
|
|
//
|
|
|
|
COMMAND CommandArray[] = {
|
|
{"test", NULL, TestCommand},
|
|
{"help", "help for all commands", ListCommand},
|
|
{"dump", "[track] dump an audio track", DumpTrackCommand},
|
|
{"toc", "prints the table of contents", ReadTOCCommand},
|
|
{"header", "[file] verifies the info in the wav header", VerifyHeaderCommand},
|
|
{"sector", "dumps a given redbook sector", DumpSectorCommand},
|
|
{NULL, NULL, NULL}
|
|
};
|
|
|
|
|
|
int __cdecl main(int argc, char *argv[])
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parses input, showing help or calling function requested appropriately
|
|
|
|
Return Value:
|
|
|
|
0 - success
|
|
-1 - insufficient arguments
|
|
-2 - error opening device (DNE?)
|
|
|
|
--*/
|
|
{
|
|
int i = 0;
|
|
int buflen;
|
|
char *buffer;
|
|
HANDLE h;
|
|
HRESULT hr;
|
|
|
|
if ( argc < 3 ) {
|
|
ListCommand( NULL, argc, argv );
|
|
return -1;
|
|
}
|
|
|
|
buflen = ( strlen(argv[1]) + 5 ) * sizeof(char);
|
|
|
|
buffer = (char *)malloc( buflen );
|
|
if (buffer == NULL) {
|
|
fprintf(stderr, "Insufficient memory\n");
|
|
return -1;
|
|
}
|
|
|
|
hr = StringCbPrintf(buffer, buflen, "\\\\.\\%s", argv[1]);
|
|
if (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER) {
|
|
fprintf(stderr, "Unable to format device string (too long?)\n");
|
|
free(buffer);
|
|
return -9;
|
|
} else if (!SUCCEEDED(hr)) {
|
|
fprintf(stderr, "Unable to format device string\n");
|
|
free(buffer);
|
|
return -9;
|
|
}
|
|
|
|
|
|
DebugPrint((2, "Main => Sending command %s to drive %s\n", argv[2], buffer));
|
|
|
|
h = CreateFile( buffer,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if ( h == INVALID_HANDLE_VALUE ) {
|
|
fprintf(stderr, "Error %d opening device %s\n", GetLastError(), buffer);
|
|
return -2;
|
|
}
|
|
|
|
//
|
|
// Iterate through the command array and find the correct function to
|
|
// call.
|
|
//
|
|
|
|
while ( CommandArray[i].Name != NULL ) {
|
|
|
|
if(strcmp(argv[2], CommandArray[i].Name) == 0) {
|
|
|
|
(CommandArray[i].Function)(h, (argc - 2), &(argv[2]));
|
|
|
|
break;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
if ( CommandArray[i].Name == NULL ) {
|
|
fprintf(stderr, "Unknown command %s\n", argv[2]);
|
|
}
|
|
|
|
CloseHandle(h);
|
|
|
|
return 0;
|
|
}
|
|
|
|
ULONG32
|
|
VerifyHeaderCommand(
|
|
HANDLE device,
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
opens the next argument and reads the wav header, printing to stdout
|
|
|
|
Arguments:
|
|
|
|
device - unused
|
|
argc - the number of additional arguments.
|
|
argv - the additional arguments
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful
|
|
The value of GetLastError() from the point of failure
|
|
|
|
--*/
|
|
{
|
|
HANDLE wavHandle;
|
|
|
|
if (argv[1] == NULL) {
|
|
fprintf(stderr, "Need filename to attempt to parse\n");
|
|
return -1;
|
|
}
|
|
|
|
TRY {
|
|
|
|
DebugPrint((2, "VerifyHeader => Opening %s\n", argv[1]));
|
|
|
|
wavHandle = CreateFile(argv[1],
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (wavHandle == INVALID_HANDLE_VALUE) {
|
|
printf("Error openingfile %x\n", GetLastError());
|
|
LEAVE;
|
|
}
|
|
|
|
ReadWavHeader(wavHandle);
|
|
|
|
CloseHandle(wavHandle);
|
|
|
|
} FINALLY {
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
ULONG32 TestCommand(HANDLE device, int argc, char *argv[])
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Tests the command "parsing"
|
|
|
|
Arguments:
|
|
|
|
device - a file handle to send the ioctl to
|
|
argc - the number of additional arguments.
|
|
argv - the additional arguments
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful
|
|
The value of GetLastError() from the point of failure
|
|
|
|
--*/
|
|
|
|
{
|
|
int i;
|
|
printf("Test - %d additional arguments\n", argc);
|
|
|
|
for(i = 0; i < argc; i++) {
|
|
printf("arg %d: %s\n", i, argv[i]);
|
|
}
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
ULONG32 ListCommand(HANDLE device, int argc, char *argv[])
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints out the command list
|
|
|
|
Arguments:
|
|
|
|
device - unused
|
|
argc - unused
|
|
argv - unused
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
int i;
|
|
|
|
printf("\nCdDump Version " VERSION_STRING "\n");
|
|
printf("\tUsage: cddump <drive> <command> [parameters]\n");
|
|
printf("\tpossible commands: \n");
|
|
for (i = 0; CommandArray[i].Name != NULL; i++) {
|
|
|
|
if(CommandArray[i].Description != NULL) {
|
|
printf( "\t\t%s - %s\n",
|
|
CommandArray[i].Name,
|
|
CommandArray[i].Description
|
|
);
|
|
}
|
|
|
|
}
|
|
printf( "\n" );
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
ULONG32 ReadTOCCommand(HANDLE device, int argc, char *argv[])
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads and prints out the cdrom's table of contents
|
|
|
|
Arguments:
|
|
|
|
device - a file handle to send the ioctl to
|
|
argc - the number of additional arguments. should be zero
|
|
argv - the additional arguments
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful
|
|
The value of GetLastError() from the point of failure
|
|
|
|
--*/
|
|
{
|
|
PCDROM_TOC toc;
|
|
PTRACK_DATA track;
|
|
ULONG numberOfTracks;
|
|
ULONG i;
|
|
|
|
DebugPrint((2, "ReadToc => Reading Table of Contents\n"));
|
|
|
|
toc = CddumpGetToc( device );
|
|
if (toc == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
printf("First Track Number: %d\n", toc->FirstTrack);
|
|
printf("Last Track Number: %d\n", toc->LastTrack);
|
|
printf("CDDB ID: %08x\n", CDDB_ID(toc));
|
|
|
|
|
|
|
|
numberOfTracks = (toc->LastTrack - toc->FirstTrack) + 1;
|
|
|
|
// parse and print the information
|
|
|
|
track = (PTRACK_DATA) &(toc->TrackData[0]);
|
|
|
|
printf("Number ADR Control Start End Bytes\n");
|
|
printf("------ --- ------- ---------- ---------- ----------\n");
|
|
|
|
for(i = 0; i < numberOfTracks; i++) {
|
|
|
|
ULONG trackStart;
|
|
ULONG trackEnd;
|
|
ULONG trackBytes;
|
|
|
|
trackStart = MSF_TO_LBA(track->Address[1],
|
|
track->Address[2],
|
|
track->Address[3]);
|
|
trackEnd = MSF_TO_LBA((track+1)->Address[1],
|
|
(track+1)->Address[2],
|
|
(track+1)->Address[3]);
|
|
trackEnd--;
|
|
|
|
trackBytes = (trackEnd - trackStart) * RAW_SECTOR_SIZE;
|
|
|
|
printf(" %2d %2d %2d %10d %10d %8dk \n",
|
|
track->TrackNumber,
|
|
track->Adr,
|
|
track->Control,
|
|
trackStart,
|
|
trackEnd,
|
|
trackBytes / 1000
|
|
);
|
|
|
|
|
|
track++;
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
ULONG32 DumpTrackCommand(HANDLE device, int argc, char *argv[])
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads a section of disc in raw read mode
|
|
|
|
Arguments:
|
|
|
|
device - a file handle to send the ioctl to
|
|
|
|
argc - the number of additional arguments.
|
|
|
|
argv[1] - the starting LBA. Starts at zero if this is not here
|
|
argv[2] - the ending LBA. if not specified, equal to start
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful
|
|
The value of GetLastError() from the point of failure
|
|
|
|
--*/
|
|
{
|
|
PCDROM_TOC toc;
|
|
HANDLE outputFile = (HANDLE)-1;
|
|
HRESULT hr;
|
|
ULONG track;
|
|
ULONG endingSector;
|
|
ULONG numberOfSectors; // actually useful data
|
|
ULONG numberOfReads;
|
|
ULONG status;
|
|
|
|
ULONG startingSector;
|
|
LONG i;
|
|
|
|
ULONG cddbId = 0;
|
|
|
|
UCHAR fileName[1024]; // randomly chosen size.
|
|
|
|
PSAMPLE sample;
|
|
|
|
toc = NULL;
|
|
sample = NULL;
|
|
|
|
TRY {
|
|
track = atoi(argv[1]);
|
|
if (track==0) {
|
|
printf( "Cannot read track 0.\n" );
|
|
status = -1;
|
|
LEAVE;
|
|
}
|
|
|
|
toc = CddumpGetToc( device );
|
|
if (toc==NULL) {
|
|
status = -1;
|
|
LEAVE;
|
|
}
|
|
|
|
cddbId = CDDB_ID(toc);
|
|
hr = StringCbPrintf(fileName,
|
|
sizeof(fileName),
|
|
"%08x - Track %02d.wav",
|
|
cddbId, track);
|
|
if (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER) {
|
|
fprintf(stderr, "Unable to format device string (too long?)\n");
|
|
status = -1;
|
|
LEAVE;
|
|
} else if (!SUCCEEDED(hr)) {
|
|
fprintf(stderr, "Unable to format device string\n");
|
|
status = -1;
|
|
LEAVE;
|
|
}
|
|
|
|
DebugPrint((2, "DumpTrack => output filename: %s\n", fileName));
|
|
|
|
//
|
|
// account for zero-index
|
|
//
|
|
|
|
startingSector = MSF_TO_LBA(toc->TrackData[track-1].Address[1],
|
|
toc->TrackData[track-1].Address[2],
|
|
toc->TrackData[track-1].Address[3]
|
|
);
|
|
endingSector = MSF_TO_LBA(toc->TrackData[track].Address[1],
|
|
toc->TrackData[track].Address[2],
|
|
toc->TrackData[track].Address[3]
|
|
);
|
|
endingSector--; // no overlap
|
|
|
|
numberOfSectors = endingSector - startingSector;
|
|
|
|
DebugPrint((3, "DumpTrack => old sectors: start %8d end %8d count %d\n",
|
|
startingSector, endingSector, numberOfSectors));
|
|
|
|
|
|
sample = (PSAMPLE)malloc( RAW_SECTOR_SIZE );
|
|
if ( sample == NULL ) {
|
|
printf("Insufficient resources (sample)\n");
|
|
status = -1;
|
|
LEAVE;
|
|
}
|
|
|
|
//
|
|
// first find a fully zero'd sample -- that will be
|
|
// the _real_ start address of the track after adjusting
|
|
// for redbook inaccuracies.
|
|
//
|
|
|
|
for (i=REDBOOK_INACCURACY; i > -(REDBOOK_INACCURACY); i--) {
|
|
|
|
RAW_READ_INFO info;
|
|
ULONG bytesReturned;
|
|
ULONG j;
|
|
BOOLEAN foundZeroSector = FALSE;
|
|
|
|
if ((LONG)startingSector + i > 0 ) { // only read positive
|
|
|
|
info.DiskOffset.QuadPart = (ULONGLONG)((startingSector + i)*(ULONGLONG)2048);
|
|
info.SectorCount = 1;
|
|
info.TrackMode = CDDA;
|
|
|
|
if(DeviceIoControl(device,
|
|
IOCTL_CDROM_RAW_READ,
|
|
&info, // pointer to inputbuffer
|
|
sizeof(RAW_READ_INFO), // sizeof inputbuffer
|
|
sample, // pointer to outputbuffer
|
|
RAW_SECTOR_SIZE, // sizeof outputbuffer
|
|
&bytesReturned, // pointer to number of bytes returned
|
|
FALSE)) {
|
|
|
|
//
|
|
// read succeeded, see if all zero'd
|
|
//
|
|
|
|
assert(bytesReturned == RAW_SECTOR_SIZE);
|
|
|
|
foundZeroSector = TRUE;
|
|
for (j=0;j<SAMPLES_PER_SECTOR;j++) {
|
|
if (sample[j].AsUlong32 != 0) foundZeroSector = FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
if (foundZeroSector) {
|
|
DebugPrint((1, "DumpTrack => New starting sector is "
|
|
"offset by %d\n", i));
|
|
startingSector += i; // change to real starting sector
|
|
break; // stop looping.
|
|
}
|
|
} // end of positive check
|
|
} // end of loop
|
|
|
|
//
|
|
// then find a fully zero'd sample at the end -- that will
|
|
// be the _real_ end address of the track after adjusting
|
|
// for redbook inaccuracies.
|
|
//
|
|
|
|
for (i=-(REDBOOK_INACCURACY); i < REDBOOK_INACCURACY; i++) {
|
|
|
|
RAW_READ_INFO info;
|
|
ULONG bytesReturned;
|
|
ULONG j;
|
|
BOOLEAN foundZeroSector = FALSE;
|
|
|
|
if ((LONG)endingSector + i > 0 ) { // only read positive
|
|
|
|
info.DiskOffset.QuadPart = (ULONGLONG)((endingSector + i)*(ULONGLONG)2048);
|
|
info.SectorCount = 1;
|
|
info.TrackMode = CDDA;
|
|
|
|
if(DeviceIoControl(device,
|
|
IOCTL_CDROM_RAW_READ,
|
|
&info, // pointer to inputbuffer
|
|
sizeof(RAW_READ_INFO), // sizeof inputbuffer
|
|
sample, // pointer to outputbuffer
|
|
RAW_SECTOR_SIZE, // sizeof outputbuffer
|
|
&bytesReturned, // pointer to number of bytes returned
|
|
FALSE)) {
|
|
|
|
//
|
|
// read succeeded, see if all zero'd
|
|
//
|
|
|
|
assert(bytesReturned == RAW_SECTOR_SIZE);
|
|
|
|
foundZeroSector = TRUE;
|
|
for (j=0;j<SAMPLES_PER_SECTOR;j++) {
|
|
if (sample[j].AsUlong32 != 0) foundZeroSector = FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
if (foundZeroSector) {
|
|
DebugPrint((2, "DumpTrack => New starting sector is "
|
|
"offset by %d\n", i));
|
|
endingSector += i; // change to real starting sector
|
|
break; // stop looping.
|
|
}
|
|
} // end of positive check
|
|
} // end of loop
|
|
|
|
numberOfSectors = endingSector - startingSector;
|
|
|
|
DebugPrint((2, "DumpTrack => new sectors: start %8d end %8d count %d\n",
|
|
startingSector, endingSector, numberOfSectors));
|
|
|
|
//
|
|
// a bit of debugging info...
|
|
//
|
|
|
|
DebugPrint((2, "DumpTrack => Reading %d sectors starting at sector %d\n",
|
|
numberOfSectors, startingSector));
|
|
|
|
//
|
|
// create the file
|
|
//
|
|
outputFile = CreateFile(fileName,
|
|
GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
(HANDLE)NULL);
|
|
|
|
if (outputFile == INVALID_HANDLE_VALUE) {
|
|
printf( "Cannot open output file.\n" );
|
|
status = -1;
|
|
LEAVE;
|
|
}
|
|
|
|
//
|
|
// dump the wav header info
|
|
//
|
|
DumpWavHeader(outputFile,
|
|
numberOfSectors * SAMPLES_PER_SECTOR,
|
|
44100, // 44.1KHz sound
|
|
2, // stereo sound
|
|
16 // 16-bit sound
|
|
);
|
|
CddumpDumpLba(device,
|
|
outputFile,
|
|
startingSector,
|
|
endingSector
|
|
);
|
|
|
|
DebugPrint((2, "DumpTrack => Done!\n"));
|
|
|
|
CloseHandle(outputFile);
|
|
|
|
} FINALLY {
|
|
|
|
free(toc);
|
|
free(sample);
|
|
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
ULONG32 DumpSectorCommand(HANDLE device, int argc, char *argv[])
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads a section of disc in raw read mode
|
|
|
|
Arguments:
|
|
|
|
device - a file handle to send the ioctl to
|
|
|
|
argc - the number of additional arguments.
|
|
|
|
argv[1] - the starting LBA. Starts at zero if this is not here
|
|
argv[2] - the ending LBA. if not specified, equal to start
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful
|
|
The value of GetLastError() from the point of failure
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr;
|
|
ULONG sector;
|
|
ULONG status;
|
|
|
|
PSAMPLE sample;
|
|
|
|
sample = NULL;
|
|
|
|
TRY {
|
|
sector = atoi(argv[1]);
|
|
printf( "Reading sector %x.\n", sector );
|
|
|
|
sample = (PSAMPLE)malloc( RAW_SECTOR_SIZE );
|
|
if ( sample == NULL ) {
|
|
printf("Insufficient resources (sample)\n");
|
|
status = -1;
|
|
LEAVE;
|
|
}
|
|
|
|
{
|
|
RAW_READ_INFO info;
|
|
ULONG bytesReturned;
|
|
BOOLEAN foundZeroSector = FALSE;
|
|
|
|
info.DiskOffset.QuadPart = (ULONGLONG)((sector)*(ULONGLONG)2048);
|
|
info.SectorCount = 1;
|
|
info.TrackMode = CDDA;
|
|
|
|
if(DeviceIoControl(device,
|
|
IOCTL_CDROM_RAW_READ,
|
|
&info, // pointer to inputbuffer
|
|
sizeof(RAW_READ_INFO), // sizeof inputbuffer
|
|
sample, // pointer to outputbuffer
|
|
RAW_SECTOR_SIZE, // sizeof outputbuffer
|
|
&bytesReturned, // pointer to number of bytes returned
|
|
FALSE)) {
|
|
|
|
//
|
|
// read succeeded, see if all zero'd
|
|
//
|
|
|
|
assert(bytesReturned == RAW_SECTOR_SIZE);
|
|
|
|
}
|
|
else
|
|
{
|
|
printf("Error: %x\n", GetLastError());
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
} FINALLY {
|
|
|
|
free(sample);
|
|
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|