Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

625 lines
15 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. cddump.c
  5. Abstract:
  6. parses commands and acts
  7. Environment:
  8. User mode only
  9. Revision History:
  10. 05-26-98 : Created
  11. --*/
  12. #include "common.h"
  13. #define VERSION_MAJOR 1
  14. #define VERSION_MINOR 0
  15. #define VERSION_STRING "1.00"
  16. ULONG32
  17. TestCommand(
  18. HANDLE device,
  19. int argc,
  20. char *argv[]
  21. );
  22. ULONG32
  23. ListCommand(
  24. HANDLE device,
  25. int argc,
  26. char *argv[]
  27. );
  28. ULONG32
  29. DumpTrackCommand(
  30. HANDLE device,
  31. int argc,
  32. char *argv[]
  33. );
  34. ULONG32
  35. VerifyHeaderCommand(
  36. HANDLE device,
  37. int argc,
  38. char *argv[]
  39. );
  40. ULONG32
  41. ReadTOCCommand(
  42. HANDLE device,
  43. int argc,
  44. char *argv[]
  45. );
  46. //
  47. // Each structure instance can have a function pointer, name, and description
  48. //
  49. typedef struct {
  50. char *Name;
  51. char *Description;
  52. ULONG32 (*Function)(HANDLE device, int argc, char *argv[]);
  53. } COMMAND;
  54. //
  55. // List of commands
  56. // all command names are case sensitive
  57. // arguments are passed into command routines
  58. // list must be terminated with NULL command
  59. // command will not be listed in help if description == NULL
  60. //
  61. COMMAND CommandArray[] = {
  62. {"test", NULL, TestCommand},
  63. {"help", "help for all commands", ListCommand},
  64. {"dump", "[track] dump an audio track", DumpTrackCommand},
  65. {"toc", "prints the table of contents", ReadTOCCommand},
  66. {"header", "[file] verifies the info in the wav header", VerifyHeaderCommand},
  67. {NULL, NULL, NULL}
  68. };
  69. int __cdecl main(int argc, char *argv[])
  70. /*++
  71. Routine Description:
  72. Parses input, showing help or calling function requested appropriately
  73. Return Value:
  74. 0 - success
  75. -1 - insufficient arguments
  76. -2 - error opening device (DNE?)
  77. --*/
  78. {
  79. int i = 0;
  80. int buflen;
  81. char *buffer;
  82. HANDLE h;
  83. if ( argc < 3 ) {
  84. ListCommand( NULL, argc, argv );
  85. return -1;
  86. }
  87. buflen = ( strlen(argv[1]) + 5 ) * sizeof(char);
  88. buffer = (char *)malloc( buflen );
  89. if (buffer == NULL) {
  90. fprintf(stderr, "Insufficient memory\n");
  91. return -1;
  92. }
  93. sprintf( buffer, "\\\\.\\%s", argv[1] );
  94. DebugPrint((2, "Main => Sending command %s to drive %s\n", argv[2], buffer));
  95. h = CreateFile( buffer,
  96. GENERIC_READ,
  97. FILE_SHARE_READ,
  98. NULL,
  99. OPEN_EXISTING,
  100. FILE_ATTRIBUTE_NORMAL,
  101. NULL);
  102. if ( h == INVALID_HANDLE_VALUE ) {
  103. fprintf(stderr, "Error %d opening device %s\n", GetLastError(), buffer);
  104. return -2;
  105. }
  106. //
  107. // Iterate through the command array and find the correct function to
  108. // call.
  109. //
  110. while ( CommandArray[i].Name != NULL ) {
  111. if(strcmp(argv[2], CommandArray[i].Name) == 0) {
  112. (CommandArray[i].Function)(h, (argc - 2), &(argv[2]));
  113. break;
  114. }
  115. i++;
  116. }
  117. if ( CommandArray[i].Name == NULL ) {
  118. fprintf(stderr, "Unknown command %s\n", argv[2]);
  119. }
  120. CloseHandle(h);
  121. return 0;
  122. }
  123. ULONG32
  124. VerifyHeaderCommand(
  125. HANDLE device,
  126. int argc,
  127. char *argv[]
  128. )
  129. /*++
  130. Routine Description:
  131. opens the next argument and reads the wav header, printing to stdout
  132. Arguments:
  133. device - unused
  134. argc - the number of additional arguments.
  135. argv - the additional arguments
  136. Return Value:
  137. STATUS_SUCCESS if successful
  138. The value of GetLastError() from the point of failure
  139. --*/
  140. {
  141. HANDLE wavHandle;
  142. if (argv[1] == NULL) {
  143. fprintf(stderr, "Need filename to attempt to parse\n");
  144. return -1;
  145. }
  146. TRY {
  147. DebugPrint((2, "VerifyHeader => Opening %s\n", argv[1]));
  148. wavHandle = CreateFile(argv[1],
  149. GENERIC_READ,
  150. FILE_SHARE_READ,
  151. NULL,
  152. OPEN_EXISTING,
  153. FILE_ATTRIBUTE_NORMAL,
  154. NULL);
  155. if (wavHandle == INVALID_HANDLE_VALUE) {
  156. printf("Error openingfile %x\n", GetLastError());
  157. LEAVE;
  158. }
  159. ReadWavHeader(wavHandle);
  160. } FINALLY {
  161. }
  162. return 0;
  163. }
  164. ULONG32 TestCommand(HANDLE device, int argc, char *argv[])
  165. /*++
  166. Routine Description:
  167. Tests the command "parsing"
  168. Arguments:
  169. device - a file handle to send the ioctl to
  170. argc - the number of additional arguments.
  171. argv - the additional arguments
  172. Return Value:
  173. STATUS_SUCCESS if successful
  174. The value of GetLastError() from the point of failure
  175. --*/
  176. {
  177. int i;
  178. printf("Test - %d additional arguments\n", argc);
  179. for(i = 0; i < argc; i++) {
  180. printf("arg %d: %s\n", i, argv[i]);
  181. }
  182. return STATUS_SUCCESS;
  183. }
  184. ULONG32 ListCommand(HANDLE device, int argc, char *argv[])
  185. /*++
  186. Routine Description:
  187. Prints out the command list
  188. Arguments:
  189. device - unused
  190. argc - unused
  191. argv - unused
  192. Return Value:
  193. STATUS_SUCCESS
  194. --*/
  195. {
  196. int i;
  197. printf("\nCdDump Version " VERSION_STRING "\n");
  198. printf("\tUsage: cddump <drive> <command> [parameters]\n");
  199. printf("\tpossible commands: \n");
  200. for (i = 0; CommandArray[i].Name != NULL; i++) {
  201. if(CommandArray[i].Description != NULL) {
  202. printf( "\t\t%s - %s\n",
  203. CommandArray[i].Name,
  204. CommandArray[i].Description
  205. );
  206. }
  207. }
  208. printf( "\n" );
  209. return STATUS_SUCCESS;
  210. }
  211. ULONG32 ReadTOCCommand(HANDLE device, int argc, char *argv[])
  212. /*++
  213. Routine Description:
  214. Reads and prints out the cdrom's table of contents
  215. Arguments:
  216. device - a file handle to send the ioctl to
  217. argc - the number of additional arguments. should be zero
  218. argv - the additional arguments
  219. Return Value:
  220. STATUS_SUCCESS if successful
  221. The value of GetLastError() from the point of failure
  222. --*/
  223. {
  224. PCDROM_TOC toc;
  225. PTRACK_DATA track;
  226. ULONG numberOfTracks;
  227. ULONG i;
  228. DebugPrint((2, "ReadToc => Reading Table of Contents\n"));
  229. toc = CddumpGetToc( device );
  230. if (toc == NULL) {
  231. return -1;
  232. }
  233. printf("First Track Number: %d\n", toc->FirstTrack);
  234. printf("Last Track Number: %d\n", toc->LastTrack);
  235. printf("CDDB ID: %08x\n", CDDB_ID(toc));
  236. numberOfTracks = (toc->LastTrack - toc->FirstTrack) + 1;
  237. // parse and print the information
  238. track = (PTRACK_DATA) &(toc->TrackData[0]);
  239. printf("Number ADR Control Start End Bytes\n");
  240. printf("------ --- ------- ---------- ---------- ----------\n");
  241. for(i = 0; i < numberOfTracks; i++) {
  242. ULONG trackStart;
  243. ULONG trackEnd;
  244. ULONG trackBytes;
  245. trackStart = MSF_TO_LBA(track->Address[1],
  246. track->Address[2],
  247. track->Address[3]);
  248. trackEnd = MSF_TO_LBA((track+1)->Address[1],
  249. (track+1)->Address[2],
  250. (track+1)->Address[3]);
  251. trackEnd--;
  252. trackBytes = (trackEnd - trackStart) * RAW_SECTOR_SIZE;
  253. printf(" %2d %2d %2d %10d %10d %8dk \n",
  254. track->TrackNumber,
  255. track->Adr,
  256. track->Control,
  257. trackStart,
  258. trackEnd,
  259. trackBytes / 1000
  260. );
  261. track++;
  262. }
  263. return STATUS_SUCCESS;
  264. }
  265. ULONG32 DumpTrackCommand(HANDLE device, int argc, char *argv[])
  266. /*++
  267. Routine Description:
  268. Reads a section of disc in raw read mode
  269. Arguments:
  270. device - a file handle to send the ioctl to
  271. argc - the number of additional arguments.
  272. argv[1] - the starting LBA. Starts at zero if this is not here
  273. argv[2] - the ending LBA. if not specified, equal to start
  274. Return Value:
  275. STATUS_SUCCESS if successful
  276. The value of GetLastError() from the point of failure
  277. --*/
  278. {
  279. PCDROM_TOC toc;
  280. HANDLE outputFile = (HANDLE)-1;
  281. ULONG track;
  282. ULONG endingSector;
  283. ULONG numberOfSectors; // actually useful data
  284. ULONG numberOfReads;
  285. ULONG status;
  286. ULONG startingSector;
  287. LONG i;
  288. ULONG cddbId = 0;
  289. UCHAR fileName[1024]; // randomly chosen size.
  290. PSAMPLE sample;
  291. toc = NULL;
  292. sample = NULL;
  293. TRY {
  294. track = atoi(argv[1]);
  295. if (track==0) {
  296. printf( "Cannot read track 0.\n" );
  297. status = -1;
  298. LEAVE;
  299. }
  300. toc = CddumpGetToc( device );
  301. if (toc==NULL) {
  302. status = -1;
  303. LEAVE;
  304. }
  305. cddbId = CDDB_ID(toc);
  306. sprintf(fileName, "%08x - Track %02d.wav", cddbId, track);
  307. DebugPrint((2, "DumpTrack => output filename: %s\n", fileName));
  308. //
  309. // account for zero-index
  310. //
  311. startingSector = MSF_TO_LBA(toc->TrackData[track-1].Address[1],
  312. toc->TrackData[track-1].Address[2],
  313. toc->TrackData[track-1].Address[3]
  314. );
  315. endingSector = MSF_TO_LBA(toc->TrackData[track].Address[1],
  316. toc->TrackData[track].Address[2],
  317. toc->TrackData[track].Address[3]
  318. );
  319. endingSector--; // no overlap
  320. numberOfSectors = endingSector - startingSector;
  321. DebugPrint((3, "DumpTrack => old sectors: start %8d end %8d count %d\n",
  322. startingSector, endingSector, numberOfSectors));
  323. sample = (PSAMPLE)malloc( RAW_SECTOR_SIZE );
  324. if ( sample == NULL ) {
  325. printf("Insufficient resources (sample)\n");
  326. status = -1;
  327. LEAVE;
  328. }
  329. //
  330. // first find a fully zero'd sample -- that will be
  331. // the _real_ start address of the track after adjusting
  332. // for redbook inaccuracies.
  333. //
  334. for (i=REDBOOK_INACCURACY; i > -(REDBOOK_INACCURACY); i--) {
  335. RAW_READ_INFO info;
  336. ULONG bytesReturned;
  337. ULONG j;
  338. BOOLEAN foundZeroSector = FALSE;
  339. if ((LONG)startingSector + i > 0 ) { // only read positive
  340. info.DiskOffset.QuadPart = (ULONGLONG)((startingSector + i)*(ULONGLONG)2048);
  341. info.SectorCount = 1;
  342. info.TrackMode = CDDA;
  343. if(DeviceIoControl(device,
  344. IOCTL_CDROM_RAW_READ,
  345. &info, // pointer to inputbuffer
  346. sizeof(RAW_READ_INFO), // sizeof inputbuffer
  347. sample, // pointer to outputbuffer
  348. RAW_SECTOR_SIZE, // sizeof outputbuffer
  349. &bytesReturned, // pointer to number of bytes returned
  350. FALSE)) {
  351. //
  352. // read succeeded, see if all zero'd
  353. //
  354. assert(bytesReturned == RAW_SECTOR_SIZE);
  355. foundZeroSector = TRUE;
  356. for (j=0;j<SAMPLES_PER_SECTOR;j++) {
  357. if (sample[j].AsUlong32 != 0) foundZeroSector = FALSE;
  358. }
  359. }
  360. if (foundZeroSector) {
  361. DebugPrint((1, "DumpTrack => New starting sector is "
  362. "offset by %d\n", i));
  363. startingSector += i; // change to real starting sector
  364. break; // stop looping.
  365. }
  366. } // end of positive check
  367. } // end of loop
  368. //
  369. // then find a fully zero'd sample at the end -- that will
  370. // be the _real_ end address of the track after adjusting
  371. // for redbook inaccuracies.
  372. //
  373. for (i=-(REDBOOK_INACCURACY); i < REDBOOK_INACCURACY; i++) {
  374. RAW_READ_INFO info;
  375. ULONG bytesReturned;
  376. ULONG j;
  377. BOOLEAN foundZeroSector = FALSE;
  378. if ((LONG)endingSector + i > 0 ) { // only read positive
  379. info.DiskOffset.QuadPart = (ULONGLONG)((endingSector + i)*(ULONGLONG)2048);
  380. info.SectorCount = 1;
  381. info.TrackMode = CDDA;
  382. if(DeviceIoControl(device,
  383. IOCTL_CDROM_RAW_READ,
  384. &info, // pointer to inputbuffer
  385. sizeof(RAW_READ_INFO), // sizeof inputbuffer
  386. sample, // pointer to outputbuffer
  387. RAW_SECTOR_SIZE, // sizeof outputbuffer
  388. &bytesReturned, // pointer to number of bytes returned
  389. FALSE)) {
  390. //
  391. // read succeeded, see if all zero'd
  392. //
  393. assert(bytesReturned == RAW_SECTOR_SIZE);
  394. foundZeroSector = TRUE;
  395. for (j=0;j<SAMPLES_PER_SECTOR;j++) {
  396. if (sample[j].AsUlong32 != 0) foundZeroSector = FALSE;
  397. }
  398. }
  399. if (foundZeroSector) {
  400. DebugPrint((2, "DumpTrack => New starting sector is "
  401. "offset by %d\n", i));
  402. endingSector += i; // change to real starting sector
  403. break; // stop looping.
  404. }
  405. } // end of positive check
  406. } // end of loop
  407. numberOfSectors = endingSector - startingSector;
  408. DebugPrint((2, "DumpTrack => new sectors: start %8d end %8d count %d\n",
  409. startingSector, endingSector, numberOfSectors));
  410. //
  411. // a bit of debugging info...
  412. //
  413. DebugPrint((2, "DumpTrack => Reading %d sectors starting at sector %d\n",
  414. numberOfSectors, startingSector));
  415. //
  416. // create the file
  417. //
  418. outputFile = CreateFile(fileName,
  419. GENERIC_WRITE,
  420. 0,
  421. NULL,
  422. CREATE_ALWAYS,
  423. FILE_ATTRIBUTE_NORMAL,
  424. (HANDLE)NULL);
  425. if (outputFile == INVALID_HANDLE_VALUE) {
  426. printf( "Cannot open output file.\n" );
  427. status = -1;
  428. LEAVE;
  429. }
  430. //
  431. // dump the wav header info
  432. //
  433. DumpWavHeader(outputFile,
  434. numberOfSectors * SAMPLES_PER_SECTOR,
  435. 44100, // 44.1KHz sound
  436. 2, // stereo sound
  437. 16 // 16-bit sound
  438. );
  439. CddumpDumpLba(device,
  440. outputFile,
  441. startingSector,
  442. endingSector
  443. );
  444. DebugPrint((2, "DumpTrack => Done!\n"));
  445. } FINALLY {
  446. free(toc);
  447. free(sample);
  448. }
  449. return STATUS_SUCCESS;
  450. }