Windows-Server-2003/sdktools/cddump/cddump.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;
}