diff --git a/FloatUtils.cpp b/FloatUtils.cpp old mode 100755 new mode 100644 diff --git a/FloatUtils.h b/FloatUtils.h old mode 100755 new mode 100644 diff --git a/Makefile b/Makefile index 7c6f04a..a20d7b7 100644 --- a/Makefile +++ b/Makefile @@ -1,118 +1,21 @@ -### Generated by Winemaker 0.8.4 -### -### Invocation command line was -### /opt/local/bin/winemaker cdtoimg.sln +OBJS = FloatUtils.o cdtoimg.o +CC = g++ +DEBUG = -g +CFLAGS = -Wall -O0 -W -c $(DEBUG) +LFLAGS = -Wall $(DEBUG) +LIBS = -lm -lcdio +cdtoimg : $(OBJS) + $(CC) $(LFLAGS) $(LIBS) $(OBJS) -o cdtoimg -SRCDIR = . -SUBDIRS = -DLLS = -LIBS = -EXES = cdtoimg.exe +FloatUtils.o : FloatUtils.h FloatUtils.cpp + $(CC) $(CFLAGS) FloatUtils.cpp +cdtoimg.o : cdtoimg.cpp FloatUtils.h + $(CC) $(CFLAGS) cdtoimg.cpp +clean: + \rm *.o cdtoimg -### Common settings - -CEXTRA = -O0 -W \ - -mno-cygwin -CXXEXTRA = -O0 -W -RCEXTRA = -DEFINES = -DWIN32 -D_DEBUG -D_CONSOLE -INCLUDE_PATH = -DLL_PATH = -DLL_IMPORTS = -LIBRARY_PATH = -LIBRARIES = - - -### cdtoimg.exe sources and settings - -cdtoimg_exe_MODULE = cdtoimg.exe -cdtoimg_exe_C_SRCS = -cdtoimg_exe_CXX_SRCS = FloatUtils.cpp \ - cdtoimg.cpp -cdtoimg_exe_RC_SRCS = -cdtoimg_exe_LDFLAGS = -mwindows \ - -mno-cygwin -cdtoimg_exe_ARFLAGS = -cdtoimg_exe_DLL_PATH = -cdtoimg_exe_DLLS = odbc32 \ - ole32 \ - oleaut32 \ - winspool \ - odbccp32 -cdtoimg_exe_LIBRARY_PATH= -cdtoimg_exe_LIBRARIES = uuid - -cdtoimg_exe_OBJS = $(cdtoimg_exe_C_SRCS:.c=.o) \ - $(cdtoimg_exe_CXX_SRCS:.cpp=.o) \ - $(cdtoimg_exe_RC_SRCS:.rc=.res) - - - -### Global source lists - -C_SRCS = $(cdtoimg_exe_C_SRCS) -CXX_SRCS = $(cdtoimg_exe_CXX_SRCS) -RC_SRCS = $(cdtoimg_exe_RC_SRCS) - - -### Tools - -CC = winegcc -CXX = wineg++ -RC = wrc -AR = ar - - -### Generic targets - -all: $(SUBDIRS) $(DLLS:%=%.so) $(LIBS) $(EXES) - -### Build rules - -.PHONY: all clean dummy - -$(SUBDIRS): dummy - @cd $@ && $(MAKE) - -# Implicit rules - -.SUFFIXES: .cpp .cxx .rc .res -DEFINCL = $(INCLUDE_PATH) $(DEFINES) $(OPTIONS) - -.c.o: - $(CC) -c $(CFLAGS) $(CEXTRA) $(DEFINCL) -o $@ $< - -.cpp.o: - $(CXX) -c $(CXXFLAGS) $(CXXEXTRA) $(DEFINCL) -o $@ $< - -.cxx.o: - $(CXX) -c $(CXXFLAGS) $(CXXEXTRA) $(DEFINCL) -o $@ $< - -.rc.res: - $(RC) $(RCFLAGS) $(RCEXTRA) $(DEFINCL) -fo$@ $< - -# Rules for cleaning - -CLEAN_FILES = y.tab.c y.tab.h lex.yy.c core *.orig *.rej \ - \\\#*\\\# *~ *% .\\\#* - -clean:: $(SUBDIRS:%=%/__clean__) $(EXTRASUBDIRS:%=%/__clean__) - $(RM) $(CLEAN_FILES) $(RC_SRCS:.rc=.res) $(C_SRCS:.c=.o) $(CXX_SRCS:.cpp=.o) - $(RM) $(DLLS:%=%.so) $(LIBS) $(EXES) $(EXES:%=%.so) - -$(SUBDIRS:%=%/__clean__): dummy - cd `dirname $@` && $(MAKE) clean - -$(EXTRASUBDIRS:%=%/__clean__): dummy - -cd `dirname $@` && $(RM) $(CLEAN_FILES) - -### Target specific build rules -DEFLIB = $(LIBRARY_PATH) $(LIBRARIES) $(DLL_PATH) $(DLL_IMPORTS:%=-l%) - -$(cdtoimg_exe_MODULE): $(cdtoimg_exe_OBJS) - $(CXX) $(cdtoimg_exe_LDFLAGS) -o $@ $(cdtoimg_exe_OBJS) $(cdtoimg_exe_LIBRARY_PATH) $(cdtoimg_exe_DLL_PATH) $(DEFLIB) $(cdtoimg_exe_DLLS:%=-l%) $(cdtoimg_exe_LIBRARIES:%=-l%) - - +tar: $(OBJS) + tar jcfv cdtoimg.tbz FloatUtils.h FloatUtils.cpp readme.txt Makefile cdtoimg diff --git a/TODO b/TODO new file mode 100644 index 0000000..acb88da --- /dev/null +++ b/TODO @@ -0,0 +1,6 @@ +Move source files to src folder. +Output binaries to obj folder. +Create autoconf, to check libcdio is present on system. +Check with MinGW. +Check if compilable with VisualC++. +Make it use D8 command. diff --git a/cdtoimg.cpp b/cdtoimg.cpp old mode 100755 new mode 100644 index 8449cc3..60118e1 --- a/cdtoimg.cpp +++ b/cdtoimg.cpp @@ -1,888 +1,726 @@ -/* -CDToImg v1.01. -22 Oct 2006. -Written by Truman. - -Language and type: MS Visual Studio .NET 2002, Visual C++ v7, mixed C and C++, -Application type : Win32 console. - -A program that reads an entire CD-ROM (mode 1 or mode 2 form 1) 2048 bytes per -sector and writes to a file - this would be an .ISO file. The CD must be CD-ROM -mode 1 or mode 2 and non-multisession. Note, it does not check if the CD is -valid. TAO writing mode creates link blocks and this program does not detect -them so if encountered will be considered as a normal sector or unreadable. -Unreadable sectors are not supported and will terminate the process. Only up to -80 minutes reading is supported for the moment. Note that some drives will -ignore certain read speeds, e.g. my Plextor 755A can only be set to a minimum -of 4x read speed. On some drives, reading the last few sectors or ejecting the -disc when reading in 2048 byte/sector mode results in a hang (e.g.: LG CDROM -drive: HL-DT-ST CDROM GCR-8485B 1.05). - -As always I do not take any responsibilities if this tool destroys your drive or -even anything else. - -This code uses: -- Win32 IOCTL function with SCSI_PASS_THROUGH_DIRECT. -- The SCSI codes used in this source were taken from the draft documents MMC1, - SPC1 and SAM1. -- MMC1 Read CD command (0xBE, CDB 12) to read sectors (2048 user bytes mode). -- Determine errors, retrieve and decode a few sense data. - -Normally you need the ntddscsi.h file from Microsoft DDK CD, but I shouldn't -distribute it, so instead I have written my own my_ntddscsi.h. - -If you don't have windows.h some of the define constants are listed as comments. - -This is a Win32 console program and only runs in a DOS prompt under Windows -NT4/2K/XP/2003 with appropriate user rights, i.e. you need to log in as -administrator. - -Read readme.txt for more info. -*/ - -#include -#include -#include -#include "my_ntddscsi.h" -#include "sam.h" -#include "FloatUtils.h" - -//Global variables.. -T_SPDT_SBUF sptd_sb; //Includes sense buffer -unsigned char *data_buf; //Buffer for holding transfer data from or to drive. - -/* - 1. Check the drive type to see if it's identified as a CDROM drive - - 2. Uses Win32 CreateFile function to get a handle to a drive - that is specified by cDriveLetter. - - If you don't have windows.h, some of the define constants are - listed as comments. -*/ -HANDLE open_volume(char drive_letter) -{ - HANDLE hVolume; - UINT uDriveType; - char szVolumeName[8]; - char szRootName[5]; - - //Make drive_letter as a null terminated string in the form of e.g.: d:\. - szRootName[0]=drive_letter; - szRootName[1]=':'; - szRootName[2]='\\'; - szRootName[3]='\0'; - - uDriveType = GetDriveType(szRootName); - - //#define GENERIC_READ 0x80000000L - //#define GENERIC_WRITE 0x40000000L - switch(uDriveType) - { - case DRIVE_CDROM: - { - printf("Drive type is recognised as CDROM/DVD.\n"); - break; - } - default: - { - printf("Drive type is not CDROM/DVD, aborting.\n"); - return INVALID_HANDLE_VALUE; //#define INVALID_HANDLE_VALUE (long int *)-1 - } - } - - //Make drive_letter as a null terminated string in the form of e.g.: \\.\d:. - szVolumeName[0]='\\'; - szVolumeName[1]='\\'; - szVolumeName[2]='.'; - szVolumeName[3]='\\'; - szVolumeName[4]=drive_letter; - szVolumeName[5]=':'; - szVolumeName[6]='\0'; - - //#define FILE_SHARE_READ 0x00000001 - //#define FILE_SHARE_WRITE 0x00000002 - //#define OPEN_EXISTING 3 - //#define FILE_ATTRIBUTE_NORMAL 0x00000080 - //This will only work for CD/DVD device on W2K and higher. - hVolume = CreateFile(szVolumeName, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - - if(hVolume == INVALID_HANDLE_VALUE) - { - //Try again for NT4.. - hVolume = CreateFile(szVolumeName, - GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - - if(hVolume == INVALID_HANDLE_VALUE) - { - printf("Could not create handle for CD/DVD device.\n"); - } - } - - return hVolume; -} - -/* Displays sense error information. */ -void disp_sense() -{ - unsigned char key; - unsigned char ASC; - unsigned char ASCQ; - - key=sptd_sb.SenseBuf[2] & 0x0F; //Sense key is only the lower 4 bits - ASC=sptd_sb.SenseBuf[12]; - ASCQ=sptd_sb.SenseBuf[13]; - - printf("Sense data, key:ASC:ASCQ: %02X:%02X:%02X", key, ASC, ASCQ); - - //Decode sense key:ASC:ASCQ. - //It's a very short list - I'm just trying to show you how to decode into text. - //You really need to look into MMC document and change this into an exhaustive list from - //the sense error table that is found in there. - if(key==SEN_KEY_NO_SEN) - { - if(ASC==0x00) - { - if(ASCQ==0x00) - { - printf(" - No additional sense info."); //No errors - } - } - } - else - if(key==SEN_KEY_NOT_READY) - { - if(ASC==0x3A) - { - if(ASCQ==0x00) - { - printf(" - Medium not present."); - } - else - if(ASCQ==0x01) - { - printf(" - Medium not present-tray closed."); - } - else - if(ASCQ==0x02) - { - printf(" - Medium not present-tray open."); - } - } - } - - printf("\n"); -} - -/* - 1. Set up the sptd values. - 2. Set up the CDB for SPC1 test unit ready command. - 3. Send the request to the drive. -*/ -BOOL test_unit_ready(HANDLE hVolume) -{ - DWORD dwBytesReturned; - - sptd_sb.sptd.Length=sizeof(SCSI_PASS_THROUGH_DIRECT); - sptd_sb.sptd.PathId=0; //SCSI card ID will be filled in automatically. - sptd_sb.sptd.TargetId=0; //SCSI target ID will also be filled in. - sptd_sb.sptd.Lun=0; //SCSI lun ID will also be filled in. - sptd_sb.sptd.CdbLength=6; //CDB size. - sptd_sb.sptd.SenseInfoLength=MAX_SENSE_LEN; //Maximum length of sense data to retrieve. - sptd_sb.sptd.DataIn=SCSI_IOCTL_DATA_UNSPECIFIED; //There will be no buffer data to/from drive. - sptd_sb.sptd.DataTransferLength=0; //Size of buffer transfer data. - sptd_sb.sptd.TimeOutValue=108000; //SCSI timeout value (max 108000 sec = time 30 min). - sptd_sb.sptd.DataBuffer=(PVOID)data_buf; - sptd_sb.sptd.SenseInfoOffset=sizeof(SCSI_PASS_THROUGH_DIRECT); - - //CDB with values for Test Unit Ready CDB6 command. - //The values were taken from SPC1 draft paper. - sptd_sb.sptd.Cdb[0]=0x00; //Code for Test Unit Ready CDB6 command. - sptd_sb.sptd.Cdb[1]=0; - sptd_sb.sptd.Cdb[2]=0; - sptd_sb.sptd.Cdb[3]=0; - sptd_sb.sptd.Cdb[4]=0; - sptd_sb.sptd.Cdb[5]=0; - sptd_sb.sptd.Cdb[6]=0; - sptd_sb.sptd.Cdb[7]=0; - sptd_sb.sptd.Cdb[8]=0; - sptd_sb.sptd.Cdb[9]=0; - sptd_sb.sptd.Cdb[10]=0; - sptd_sb.sptd.Cdb[11]=0; - sptd_sb.sptd.Cdb[12]=0; - sptd_sb.sptd.Cdb[13]=0; - sptd_sb.sptd.Cdb[14]=0; - sptd_sb.sptd.Cdb[15]=0; - - ZeroMemory(sptd_sb.SenseBuf, MAX_SENSE_LEN); - - //Send the command to drive. - return DeviceIoControl(hVolume, - IOCTL_SCSI_PASS_THROUGH_DIRECT, - (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), - (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), - &dwBytesReturned, - NULL); -} - -/* - 1. Set up the sptd values. - 2. Set up the CDB for MMC1 set CD speed command. - 3. Send the request to the drive. -*/ -BOOL set_cd_speed(HANDLE hVolume, - unsigned short int in_read_speed, - unsigned short int in_write_speed) -{ - DWORD dwBytesReturned; - - sptd_sb.sptd.Length=sizeof(SCSI_PASS_THROUGH_DIRECT); - sptd_sb.sptd.PathId=0; //SCSI card ID will be filled in automatically. - sptd_sb.sptd.TargetId=0; //SCSI target ID will also be filled in. - sptd_sb.sptd.Lun=0; //SCSI lun ID will also be filled in. - sptd_sb.sptd.CdbLength=12; //CDB size - sptd_sb.sptd.SenseInfoLength=MAX_SENSE_LEN; //Return sense buffer length. - sptd_sb.sptd.DataIn=SCSI_IOCTL_DATA_UNSPECIFIED; //There will be no buffer data to/from drive. - sptd_sb.sptd.DataTransferLength=0; //Size of buffer transfer data. - sptd_sb.sptd.TimeOutValue=108000; //SCSI timeout value (max 108000 sec = time 30 min). - sptd_sb.sptd.DataBuffer=(PVOID)data_buf; - sptd_sb.sptd.SenseInfoOffset=sizeof(SCSI_PASS_THROUGH_DIRECT); - - //CDB with values for set cd speed command. - //The values were taken from MMC1 draft paper. - sptd_sb.sptd.Cdb[0]=0xBB; //Code for set cd speed command. - sptd_sb.sptd.Cdb[1]=0; - sptd_sb.sptd.Cdb[2]=(unsigned char)(in_read_speed>>8); - sptd_sb.sptd.Cdb[3]=(unsigned char)in_read_speed; - sptd_sb.sptd.Cdb[4]=(unsigned char)(in_write_speed>>8); - sptd_sb.sptd.Cdb[5]=(unsigned char)in_write_speed; - sptd_sb.sptd.Cdb[6]=0; - sptd_sb.sptd.Cdb[7]=0; - sptd_sb.sptd.Cdb[8]=0; - sptd_sb.sptd.Cdb[9]=0; - sptd_sb.sptd.Cdb[10]=0; - sptd_sb.sptd.Cdb[11]=0; - sptd_sb.sptd.Cdb[12]=0; - sptd_sb.sptd.Cdb[13]=0; - sptd_sb.sptd.Cdb[14]=0; - sptd_sb.sptd.Cdb[15]=0; - - ZeroMemory(sptd_sb.SenseBuf, MAX_SENSE_LEN); - - //Send the command to drive - return DeviceIoControl(hVolume, - IOCTL_SCSI_PASS_THROUGH_DIRECT, - (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), - (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), - &dwBytesReturned, - NULL); -} - -/* - 1. Set up the sptd values. - 2. Set up the CDB for MMC1 read TOC/PMA/ATIP command. - 3. Send the request to the drive. -*/ -BOOL read_TOC_PMA_ATIP(HANDLE hVolume, - unsigned char in_format, - unsigned char in_trk_sess_no, - unsigned short int in_data_trans_len) -{ - DWORD dwBytesReturned; - - sptd_sb.sptd.Length=sizeof(SCSI_PASS_THROUGH_DIRECT); - sptd_sb.sptd.PathId=0; //SCSI card ID will be filled in automatically. - sptd_sb.sptd.TargetId=0; //SCSI target ID will also be filled in. - sptd_sb.sptd.Lun=0; //SCSI lun ID will also be filled in. - sptd_sb.sptd.CdbLength=10; //CDB size. - sptd_sb.sptd.SenseInfoLength=MAX_SENSE_LEN; //Maximum length of sense data to retrieve. - sptd_sb.sptd.DataIn=SCSI_IOCTL_DATA_IN; //There will be data from drive. - sptd_sb.sptd.DataTransferLength=in_data_trans_len; //Size of input data from drive. - sptd_sb.sptd.TimeOutValue=108000; //SCSI timeout value (max 108000 sec = time 30 min). - sptd_sb.sptd.DataBuffer=(PVOID)data_buf; - sptd_sb.sptd.SenseInfoOffset=sizeof(SCSI_PASS_THROUGH_DIRECT); - - //CDB with values for READ TOC/PMA/ATIP CDB10 command. - //The values were taken from MMC draft paper. - sptd_sb.sptd.Cdb[0]=0x43; //Code for READ TOC/PMA/ATIP CDB10 command. - sptd_sb.sptd.Cdb[1]=0; - sptd_sb.sptd.Cdb[2]=in_format; //Format code. - sptd_sb.sptd.Cdb[3]=0; - sptd_sb.sptd.Cdb[4]=0; - sptd_sb.sptd.Cdb[5]=0; - sptd_sb.sptd.Cdb[6]=in_trk_sess_no; - sptd_sb.sptd.Cdb[7]=(unsigned char)(in_data_trans_len >> 8); //MSB of max length of bytes to receive. - sptd_sb.sptd.Cdb[8]=(unsigned char)in_data_trans_len; //LSB of max length of bytes to receive. - sptd_sb.sptd.Cdb[9]=0; - sptd_sb.sptd.Cdb[10]=0; - sptd_sb.sptd.Cdb[11]=0; - sptd_sb.sptd.Cdb[12]=0; - sptd_sb.sptd.Cdb[13]=0; - sptd_sb.sptd.Cdb[14]=0; - sptd_sb.sptd.Cdb[15]=0; - - ZeroMemory(data_buf, in_data_trans_len); - ZeroMemory(sptd_sb.SenseBuf, MAX_SENSE_LEN); - - //Send the command to drive. - return DeviceIoControl(hVolume, - IOCTL_SCSI_PASS_THROUGH_DIRECT, - (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), - (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), - &dwBytesReturned, - NULL); -} - -/* - 1. Set up the sptd values. - 2. Set up the CDB for MMC1 read CD (0xBE, CDB12) command. - 3. Send the request to the drive. -*/ -BOOL read_cd_2048(HANDLE hVolume, - long int MMC_LBA_sector, - unsigned long int n_sectors, - unsigned char subch_sel_bits) -{ - DWORD dwBytesReturned; - long int MMC_LBA_sector2; - unsigned long int n_sectors2; - - sptd_sb.sptd.Length=sizeof(SCSI_PASS_THROUGH_DIRECT); - sptd_sb.sptd.PathId=0; //SCSI card ID will be filled in automatically. - sptd_sb.sptd.TargetId=0; //SCSI target ID will also be filled in. - sptd_sb.sptd.Lun=0; //SCSI lun ID will also be filled in. - sptd_sb.sptd.CdbLength=12; //CDB size. - sptd_sb.sptd.SenseInfoLength=MAX_SENSE_LEN; //Maximum length of sense data to retrieve. - sptd_sb.sptd.DataIn=SCSI_IOCTL_DATA_IN; //There will be data coming from the drive. - sptd_sb.sptd.DataTransferLength=2048*n_sectors; //Size of read data. - sptd_sb.sptd.TimeOutValue=108000; //SCSI timeout value (max 108000 sec = time 30 min). - sptd_sb.sptd.DataBuffer=(PVOID)data_buf; - sptd_sb.sptd.SenseInfoOffset=sizeof(SCSI_PASS_THROUGH_DIRECT); - - //CDB with values for Read CD command. The values were taken from MMC1 draft paper. - sptd_sb.sptd.Cdb[0]=0xBE; //Code for Read CD command. - sptd_sb.sptd.Cdb[1]=0; - - //Fill in starting MMC sector (CDB[2] to CDB[5]).. - sptd_sb.sptd.Cdb[5]=(unsigned char)MMC_LBA_sector; //Least sig byte of LBA sector no. to read from CD. - MMC_LBA_sector2=MMC_LBA_sector>>8; - sptd_sb.sptd.Cdb[4]=(unsigned char)MMC_LBA_sector2; //2nd byte. - MMC_LBA_sector2=MMC_LBA_sector2>>8; - sptd_sb.sptd.Cdb[3]=(unsigned char)MMC_LBA_sector2; //3rd byte. - MMC_LBA_sector2=MMC_LBA_sector2>>8; - sptd_sb.sptd.Cdb[2]=(unsigned char)MMC_LBA_sector2; //Most significant byte. - - //Fill in no. of sectors to read (CDB[6] to CDB[8]).. - sptd_sb.sptd.Cdb[8]=(unsigned char)n_sectors; //No. of sectors to read from CD byte 0 (LSB). - n_sectors2=n_sectors>>8; - sptd_sb.sptd.Cdb[7]=(unsigned char)n_sectors2; //No. of sectors to read from CD byte 1. - n_sectors2=n_sectors2>>8; - sptd_sb.sptd.Cdb[6]=(unsigned char)n_sectors2; //No. of sectors to read from CD byte 2 (MSB). - - sptd_sb.sptd.Cdb[9]=0x10; //Read user data only, 2048 bytes per sector from CDROM. - sptd_sb.sptd.Cdb[10]=subch_sel_bits; //Sub-channel selection bits. - sptd_sb.sptd.Cdb[11]=0; - sptd_sb.sptd.Cdb[12]=0; - sptd_sb.sptd.Cdb[13]=0; - sptd_sb.sptd.Cdb[14]=0; - sptd_sb.sptd.Cdb[15]=0; - - ZeroMemory(data_buf, 2048*n_sectors); - ZeroMemory(sptd_sb.SenseBuf, MAX_SENSE_LEN); - - //Send the command to drive. - return DeviceIoControl(hVolume, - IOCTL_SCSI_PASS_THROUGH_DIRECT, - (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), - (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb), - &dwBytesReturned, - NULL); -} - -/* -Calculating data rate of digital stereo (2 channels) audio at 44.1 KHz with 16 BITs per channel. ------------------------------------------------------------------------------------------------- -Number of bytes taken up by 1 sample of audio: -16 BIT = 1 word = 2 bytes, but there are 2 channels, so 1 sample takes up -2*2=4 bytes. - -Data rate in kilobytes/sec will be: - s=Number of samples per second - b=Number of bytes per sample - - s*b - ---- = data rate kb/s - 1000 -So data rate of the digital audio is: - 44100*4 - ------- = 176.4 kb/s - 1000 -This data rate is used by CDROM/CD writers as 1X speed. This will of course have to be rounded to -a whole number: 176 kb/s, making prog. easier. Note, kb is in units of 1000. -*/ -unsigned short int kbytes_2_x_speed(unsigned short int speed_kbytes) -{ - return RoundDouble(speed_kbytes/176.4, 0); -} -unsigned short int x_2_kbytes_speed(unsigned short int x_speed) -{ - return RoundDouble(x_speed*176.4, 0); -} - -BOOL verified_set_cd_speed(HANDLE hVolume, - unsigned short int in_read_speed, - unsigned short int in_write_speed) -{ - BOOL success; - - printf("Sending MMC1 CD speed command "); - if(in_read_speed==0xFFFF) - { - printf("(read: max speed, "); - } - else - { - printf("(read: %ukbytes (%ux)", in_read_speed, kbytes_2_x_speed(in_read_speed)); - } - if(in_write_speed==0xFFFF) - { - printf("write: max speed).."); - } - else - { - printf("write: %ukbytes (%ux))..", in_write_speed, kbytes_2_x_speed(in_write_speed)); - } - - //Sends MMC1 set CD speed command to drive. - success=set_cd_speed(hVolume, in_read_speed, in_write_speed); - if(success) - { - printf("done.\n"); - if(sptd_sb.sptd.ScsiStatus==STATUS_GOOD) - { - //Do nothing. - } - else - { - success=FALSE; - if(sptd_sb.sptd.ScsiStatus==STATUS_CHKCOND) - { - disp_sense(); - } - else - { - printf("Command sent but returned with an unhandled status code: %02X\n", sptd_sb.sptd.ScsiStatus); - } - } - } - else - { - printf("failed.\n"); - printf("DeviceIOControl returned with failed status.\n"); - } - - return success; -} - -/* Sends Read TOC/PMA/ATIP command to read TOC, check & display errors and return the success state. */ -BOOL verified_read_TOC(HANDLE hVolume, - unsigned long int data_buffer_size) -{ - BOOL success; - unsigned short int alloc_len=0; - - printf("Sending read TOC command.."); - //Sends MMC1 READ TOC/PMA/ATIP command to drive to get 4 byte header. - success=read_TOC_PMA_ATIP(hVolume, 0, 0, 4); - if(success) - { - if(sptd_sb.sptd.ScsiStatus==STATUS_GOOD) - { - alloc_len=data_buf[0] << 8; - alloc_len=alloc_len | data_buf[1]; - } - else - { - success=FALSE; - printf("done.\n"); - if(sptd_sb.sptd.ScsiStatus==STATUS_CHKCOND) - { - disp_sense(); - } - else - { - printf("Command sent but returned with an unhandled status code: %02X\n", sptd_sb.sptd.ScsiStatus); - } - } - } - else - { - printf("failed.\n"); - printf("Could not return 4 byte Read TOC header.\n"); - } - - if(success && (alloc_len>0)) - { - //Limit alloc len to maximum allowed by size of data transfer buffer length. - if((alloc_len+2)>data_buffer_size) - { - alloc_len=data_buffer_size-2; - } - - //Sends MMC1 READ TOC/PMA/ATIP command to drive to get full data. - success=read_TOC_PMA_ATIP(hVolume, 0, 0, alloc_len+2); - if(success) - { - printf("done.\n"); - if(sptd_sb.sptd.ScsiStatus==STATUS_GOOD) - { - alloc_len=data_buf[0] << 8; - alloc_len=alloc_len | data_buf[1]; - } - else - { - success=FALSE; - if(sptd_sb.sptd.ScsiStatus==STATUS_CHKCOND) - { - disp_sense(); - } - else - { - printf("Command sent but returned with an unhandled status code: %02X\n", sptd_sb.sptd.ScsiStatus); - } - } - } - else - { - printf("failed.\n"); - printf("Could only return 4 byte Read TOC header.\n"); - } - } - - return success; -} - -/* Sends Test Unit Ready command 3 times, check for errors & display error info. */ -BOOL verified_test_unit_ready3(HANDLE hVolume) -{ - unsigned char i=3; - BOOL success; - - /* - Before sending the required command, here we clear any pending sense info from the drive - which may interfere by sending Test Unit Ready command at least 3 times if neccessary. - ----------------------------------------------------------------------------------------*/ - do - { - printf("Sending SPC1 Test Unit CDB6 command.."); - //Sends SPC1 Test Unit Ready command to drive - success=test_unit_ready(hVolume); - if(success) - { - printf("done.\n"); - if(sptd_sb.sptd.ScsiStatus==STATUS_GOOD) - { - printf("Returned good status.\n"); - i=1; - } - else - { - if(sptd_sb.sptd.ScsiStatus==STATUS_CHKCOND) - { - disp_sense(); - } - else - { - printf("Command sent but returned with an unhandled status code: %02X\n", sptd_sb.sptd.ScsiStatus); - } - - success=FALSE; - } - } - else - { - printf("failed.\n"); - printf("DeviceIOControl returned with failed status.\n"); - } - i--; - }while(i>0); - - return success; -} - -//Find lead-out from read TOC data. -BOOL find_leadout_from_TOC(unsigned char *data_buf, - unsigned char &out_n_tracks, - unsigned long int &out_n_sectors) -{ - unsigned long int i; - unsigned long int sector; - unsigned short int alloc_len; - unsigned short int TOC_response_data_len; - BOOL found_leadout; - - alloc_len=data_buf[0] << 8; - alloc_len=alloc_len | data_buf[1]; - TOC_response_data_len=alloc_len+2; - found_leadout=FALSE; - out_n_tracks=0; - //Iterate thru TOC entries to find track 0xAA (leadout track).. - for(i=4;i0) - { - //Total sectors before lead-out. - out_n_sectors=sector; - } - else - { - //Error, this should never happen. - out_n_sectors=0; - } - - out_n_tracks--; //Don't include this track. - - found_leadout=TRUE; - } - - out_n_tracks++; - } - } - } - - return found_leadout; -} - -/* -Main loop of reading the CD and writing to image file. -Various error checking are also done here. -*/ -BOOL read_cd_to_image(char drive_letter, char *file_pathname, unsigned short int x_speed, unsigned long int data_buffer_size) -{ - HANDLE hVolume; - BOOL success; - unsigned char n_tracks; //Total tracks. - unsigned long int n_sectors; //Total sectors on CD. - FILE *file_ptr; - unsigned long int LBA_i; //For counting "from" LBA (starts from 0). - unsigned long int LBA_i2; //For calculating "to" LBA. - unsigned long int n_sectors_to_read; //No. of sectors to read per read command. - unsigned short int speed_kbytes; //Write speed in kbytes. - - hVolume = open_volume(drive_letter); - if (hVolume != INVALID_HANDLE_VALUE) - { - printf("\n"); - success=verified_test_unit_ready3(hVolume); - printf("\n"); - if(success) - { - //Get TOC from CD. - success=verified_read_TOC(hVolume, data_buffer_size); - if(success) - { - if(find_leadout_from_TOC(data_buf, n_tracks, n_sectors)) - { - printf("Total user tracks : %u\n", n_tracks); - printf("Total sectors : %u\n", n_sectors); - - //Do we need to set CD speed? - if(x_speed!=0) - { - if(x_speed==0xFFFF) - { - speed_kbytes=0xFFFF; //Use maximum write speed. - } - else - { - //Convert x speed to kbytes speed. - speed_kbytes=x_2_kbytes_speed(x_speed); - } - - //Attempt to set the cd read speed to specified and write speed to max. - success=verified_set_cd_speed(hVolume, speed_kbytes, 0xFFFF); - } - else - { - //No need to set CD speed. - success=TRUE; - } - if(success) - { - file_ptr=fopen(file_pathname, "wb"); - if(file_ptr!=NULL) - { - n_sectors_to_read=data_buffer_size / 2048; //Block size: E.g.: 65536 / 2048 = 32. - LBA_i=0; //Starting LBA address. - while(LBA_i(n_sectors-LBA_i)) - { - //Alter to the remaining sectors. - n_sectors_to_read=n_sectors-LBA_i; - } - - LBA_i2=LBA_i+n_sectors_to_read-1; - printf("Reading sector %u to %u (total: %u, progress: %.1f%%)\n", LBA_i, LBA_i2, n_sectors, (double)LBA_i2/n_sectors*100); - if(read_cd_2048(hVolume, LBA_i, n_sectors_to_read, 0)) - { - if(sptd_sb.sptd.ScsiStatus==STATUS_GOOD) - { - fwrite(data_buf, 2048*n_sectors_to_read, 1, file_ptr); - if(ferror(file_ptr)) - { - printf("Write file error!\n"); - printf("Aborting process.\n"); - success=FALSE; - break; //Stop while loop. - } - } - else - { - if(sptd_sb.sptd.ScsiStatus==STATUS_CHKCOND) - { - disp_sense(); - } - else - { - printf("Command sent but returned with an unhandled status code: %02X\n", sptd_sb.sptd.ScsiStatus); - } - - printf("Aborting process.\n"); - success=FALSE; - break; //Stop while loop. - } - } - - LBA_i=LBA_i+n_sectors_to_read; - } - - fclose(file_ptr); - } - else - { - printf("Could not create file!\n"); - printf("Aborting process.\n"); - success=FALSE; - } - } - else - { - printf("Could not set read speed!\n"); - printf("Aborting process.\n"); - } - } - else - { - printf("Could not find lead-out entry in TOC to determine total sectors on CD!\n"); - printf("Aborting process.\n"); - success=FALSE; - } - } - else - { - printf("Could not read TOC!\n"); - printf("Aborting process.\n"); - } - } - else - { - printf("Drive is not ready!\n"); - printf("Aborting process.\n"); - } - - CloseHandle(hVolume); //Win32 function. - } - else - { - return FALSE; - } - - return success; -} - -void usage() -{ - printf("CDToImg v1.01. 22 Oct 2006.\n"); - printf("Usage: cdtoimg [x read speed]\n"); - printf("x speed is one of the following:\n"); - printf(" - Enter CD x speed value.\n"); - printf(" - Ommit or enter 0 to use currently set speed.\n"); - printf(" - Enter m for max speed.\n"); - return ; //Exit program here. -} - -int main(int argc, char *argv[]) -{ - unsigned short int x_speed; - - if((argc == 3) || (argc == 4)) - { - //65536 data transfer buffer. - data_buf=(unsigned char *)malloc(65536); - - if(argc == 3) - { - x_speed=0; //Use currently set write speed. - } - else - { - if(x_speed=argv[3][0]=='m') - { - x_speed=0xFFFF; //Use maximum write speed. - } - else - { - x_speed=atoi(argv[3]); //Use specified write speed. - } - } - if(read_cd_to_image(argv[1][0], argv[2], x_speed, 65536)) - { - printf("Process finished."); - } - else - { - printf("Could not create image from drive %c.", argv[1][0]); - } - - free(data_buf); - - return 0; - } - else - { - usage(); - return -1; //Exit program here. - } -} +/* +CDToImg v1.02. +13 Oct 2013. +Written by Truman. + +Modified by Natalia Portillo + +Was language and type: MS Visual Studio .NET 2002, Visual C++ v7, mixed C and C++, +Is: GNU Compiller Collection, mixed C and C++ +Was application type : Win32 console. +Is: UNIX console +Will be: Win32 console (MinGW or Visual C++ yet to see) + +A program that reads an entire CD-ROM (mode 1 or mode 2 form 1) 2048 bytes per +sector and writes to a file - this would be an .ISO file. The CD must be CD-ROM +mode 1 or mode 2 and non-multisession. Note, it does not check if the CD is +valid. TAO writing mode creates link blocks and this program does not detect +them so if encountered will be considered as a normal sector or unreadable. +Unreadable sectors are not supported and will terminate the process. Only up to +80 minutes reading is supported for the moment. Note that some drives will +ignore certain read speeds, e.g. my Plextor 755A can only be set to a minimum +of 4x read speed. On some drives, reading the last few sectors or ejecting the +disc when reading in 2048 byte/sector mode results in a hang (e.g.: LG CDROM +drive: HL-DT-ST CDROM GCR-8485B 1.05). + +As always I do not take any responsibilities if this tool destroys your drive or +even anything else. + +This code uses: +- libcdio as to cross-platform-esque send MMC commands to CD/DVD/BD drives. +- The SCSI codes used in this source were taken from the draft documents MMC1, + SPC1 and SAM1. +- MMC1 Read CD command (0xBE, CDB 12) to read sectors (2048 user bytes mode). +- Determine errors, retrieve and decode a few sense data. + +Read readme.txt for more info. +*/ + +#include +#include +#include "FloatUtils.h" + +// CDIO +#include +#include + +#include // For memset() +#include // For atoi() + +//Global variables.. +unsigned char *data_buf; //Buffer for holding transfer data from or to drive. + +// Opens device using libcdio +CdIo_t *open_volume(char *drive_letter) +{ + return cdio_open (drive_letter, DRIVER_DEVICE); +} + +/* Displays sense error information. */ +void disp_sense(CdIo_t *p_cdio) +{ + cdio_mmc_request_sense_t *pp_sense; + + int cmd_ret; + + cmd_ret = mmc_last_cmd_sense(p_cdio, &pp_sense); + + if(cmd_ret < 0) + printf(" - Error reading last MMC sense."); + else if(cmd_ret == 0) + printf(" - No additional sense info."); + else + { + printf("Sense data, key:ASC:ASCQ: %02X:%02X:%02X", pp_sense->sense_key, pp_sense->asc, pp_sense->ascq); + + //Decode sense key:ASC:ASCQ. + //It's a very short list - I'm just trying to show you how to decode into text. + //You really need to look into MMC document and change this into an exhaustive list from + //the sense error table that is found in there. + if(pp_sense->sense_key==CDIO_MMC_SENSE_KEY_NO_SENSE) + { + if(pp_sense->asc==0x00) + { + if(pp_sense->ascq==0x00) + { + printf(" - No additional sense info."); //No errors + } + } + } + else + if(pp_sense->sense_key==CDIO_MMC_SENSE_KEY_NOT_READY) + { + if(pp_sense->asc==0x3A) + { + if(pp_sense->ascq==0x00) + { + printf(" - Medium not present."); + } + else + if(pp_sense->ascq==0x01) + { + printf(" - Medium not present-tray closed."); + } + else + if(pp_sense->ascq==0x02) + { + printf(" - Medium not present-tray open."); + } + } + } + } + + printf("\n"); +} + +/* + 1. Set up the sptd values. + 2. Set up the CDB for SPC1 test unit ready command. + 3. Send the request to the drive. +*/ +driver_return_code_t test_unit_ready(CdIo_t *p_cdio) +{ + mmc_cdb_t cdb = {{0, }}; + + //CDB with values for Test Unit Ready CDB6 command. + //The values were taken from SPC1 draft paper. + cdb.field[0]=0x00; //Code for Test Unit Ready CDB6 command. + cdb.field[1]=0; + cdb.field[2]=0; + cdb.field[3]=0; + cdb.field[4]=0; + cdb.field[5]=0; + cdb.field[6]=0; + cdb.field[7]=0; + cdb.field[8]=0; + cdb.field[9]=0; + cdb.field[10]=0; + cdb.field[11]=0; + cdb.field[12]=0; + cdb.field[13]=0; + cdb.field[14]=0; + cdb.field[15]=0; + + return mmc_run_cmd(p_cdio, 108000000, &cdb, SCSI_MMC_DATA_NONE, 0, NULL); +} + +/* + 1. Set up the sptd values. + 2. Set up the CDB for MMC1 set CD speed command. + 3. Send the request to the drive. +*/ +// claunia: There is a direct libcdio command for this, should we use it? +driver_return_code_t set_cd_speed(CdIo_t *p_cdio, + unsigned short int in_read_speed, + unsigned short int in_write_speed) +{ + mmc_cdb_t cdb = {{0, }}; + + //CDB with values for set cd speed command. + //The values were taken from MMC1 draft paper. + cdb.field[0]=0xBB; //Code for set cd speed command. + cdb.field[1]=0; + cdb.field[2]=(unsigned char)(in_read_speed>>8); + cdb.field[3]=(unsigned char)in_read_speed; + cdb.field[4]=(unsigned char)(in_write_speed>>8); + cdb.field[5]=(unsigned char)in_write_speed; + cdb.field[6]=0; + cdb.field[7]=0; + cdb.field[8]=0; + cdb.field[9]=0; + cdb.field[10]=0; + cdb.field[11]=0; + cdb.field[12]=0; + cdb.field[13]=0; + cdb.field[14]=0; + cdb.field[15]=0; + + return mmc_run_cmd(p_cdio, 108000000, &cdb, SCSI_MMC_DATA_NONE, 0, NULL); +} + +/* + 1. Set up the sptd values. + 2. Set up the CDB for MMC1 read TOC/PMA/ATIP command. + 3. Send the request to the drive. +*/ +driver_return_code_t read_TOC_PMA_ATIP(CdIo_t *p_cdio, + unsigned char in_format, + unsigned char in_trk_sess_no, + unsigned short int in_data_trans_len) +{ + mmc_cdb_t cdb = {{0, }}; + + //CDB with values for READ TOC/PMA/ATIP CDB10 command. + //The values were taken from MMC draft paper. + cdb.field[0]=0x43; //Code for READ TOC/PMA/ATIP CDB10 command. + cdb.field[1]=0; + cdb.field[2]=in_format; //Format code. + cdb.field[3]=0; + cdb.field[4]=0; + cdb.field[5]=0; + cdb.field[6]=in_trk_sess_no; + cdb.field[7]=(unsigned char)(in_data_trans_len >> 8); //MSB of max length of bytes to receive. + cdb.field[8]=(unsigned char)in_data_trans_len; //LSB of max length of bytes to receive. + cdb.field[9]=0; + cdb.field[10]=0; + cdb.field[11]=0; + cdb.field[12]=0; + cdb.field[13]=0; + cdb.field[14]=0; + cdb.field[15]=0; + + memset(data_buf, 0, in_data_trans_len); + + return mmc_run_cmd(p_cdio, 108000000, &cdb, SCSI_MMC_DATA_READ, in_data_trans_len, (void *)data_buf); +} + +/* + 1. Set up the sptd values. + 2. Set up the CDB for MMC1 read CD (0xBE, CDB12) command. + 3. Send the request to the drive. +*/ +driver_return_code_t read_cd_2048(CdIo_t *p_cdio, + long int MMC_LBA_sector, + unsigned long int n_sectors, + unsigned char subch_sel_bits) +{ + mmc_cdb_t cdb = {{0, }}; + long int MMC_LBA_sector2; + unsigned long int n_sectors2; + + //CDB with values for Read CD command. The values were taken from MMC1 draft paper. + cdb.field[0]=0xBE; //Code for Read CD command. + cdb.field[1]=0; + + //Fill in starting MMC sector (CDB[2] to CDB[5]).. + cdb.field[5]=(unsigned char)MMC_LBA_sector; //Least sig byte of LBA sector no. to read from CD. + MMC_LBA_sector2=MMC_LBA_sector>>8; + cdb.field[4]=(unsigned char)MMC_LBA_sector2; //2nd byte. + MMC_LBA_sector2=MMC_LBA_sector2>>8; + cdb.field[3]=(unsigned char)MMC_LBA_sector2; //3rd byte. + MMC_LBA_sector2=MMC_LBA_sector2>>8; + cdb.field[2]=(unsigned char)MMC_LBA_sector2; //Most significant byte. + + //Fill in no. of sectors to read (CDB[6] to CDB[8]).. + cdb.field[8]=(unsigned char)n_sectors; //No. of sectors to read from CD byte 0 (LSB). + n_sectors2=n_sectors>>8; + cdb.field[7]=(unsigned char)n_sectors2; //No. of sectors to read from CD byte 1. + n_sectors2=n_sectors2>>8; + cdb.field[6]=(unsigned char)n_sectors2; //No. of sectors to read from CD byte 2 (MSB). + + cdb.field[9]=0x10; //Read user data only, 2048 bytes per sector from CDROM. + cdb.field[10]=subch_sel_bits; //Sub-channel selection bits. + cdb.field[11]=0; + cdb.field[12]=0; + cdb.field[13]=0; + cdb.field[14]=0; + cdb.field[15]=0; + + memset(data_buf, 0, 2048*n_sectors); + + return mmc_run_cmd(p_cdio, 108000000, &cdb, SCSI_MMC_DATA_READ, 2048*n_sectors, (void *)data_buf); +} + +/* +Calculating data rate of digital stereo (2 channels) audio at 44.1 KHz with 16 BITs per channel. +------------------------------------------------------------------------------------------------ +Number of bytes taken up by 1 sample of audio: +16 BIT = 1 word = 2 bytes, but there are 2 channels, so 1 sample takes up +2*2=4 bytes. + +Data rate in kilobytes/sec will be: + s=Number of samples per second + b=Number of bytes per sample + + s*b + ---- = data rate kb/s + 1000 +So data rate of the digital audio is: + 44100*4 + ------- = 176.4 kb/s + 1000 +This data rate is used by CDROM/CD writers as 1X speed. This will of course have to be rounded to +a whole number: 176 kb/s, making prog. easier. Note, kb is in units of 1000. +*/ +unsigned short int kbytes_2_x_speed(unsigned short int speed_kbytes) +{ + return RoundDouble(speed_kbytes/176.4, 0); +} +unsigned short int x_2_kbytes_speed(unsigned short int x_speed) +{ + return RoundDouble(x_speed*176.4, 0); +} + +driver_return_code_t verified_set_cd_speed(CdIo_t *p_cdio, + unsigned short int in_read_speed, + unsigned short int in_write_speed) +{ + driver_return_code_t success; + + printf("Sending MMC1 CD speed command "); + if(in_read_speed==0xFFFF) + { + printf("(read: max speed, "); + } + else + { + printf("(read: %ukbytes (%ux)", in_read_speed, kbytes_2_x_speed(in_read_speed)); + } + if(in_write_speed==0xFFFF) + { + printf("write: max speed).."); + } + else + { + printf("write: %ukbytes (%ux))..", in_write_speed, kbytes_2_x_speed(in_write_speed)); + } + + //Sends MMC1 set CD speed command to drive. + success=set_cd_speed(p_cdio, in_read_speed, in_write_speed); + printf("done.\n"); + if(success==DRIVER_OP_SUCCESS) + { + //Do nothing. + } + else + { + if(success==DRIVER_OP_MMC_SENSE_DATA) + { + disp_sense(p_cdio); + } + else + { + printf("Command sent but returned with an unhandled status code: %02X\n", success); + } + } + + return success; +} + +/* Sends Read TOC/PMA/ATIP command to read TOC, check & display errors and return the success state. */ +driver_return_code_t verified_read_TOC(CdIo_t *p_cdio, + unsigned long int data_buffer_size) +{ + driver_return_code_t success; + unsigned short int alloc_len=0; + + printf("Sending read TOC command.."); + //Sends MMC1 READ TOC/PMA/ATIP command to drive to get 4 byte header. + success=read_TOC_PMA_ATIP(p_cdio, 0, 0, 4); + if(success==DRIVER_OP_SUCCESS) + { + alloc_len=data_buf[0] << 8; + alloc_len=alloc_len | data_buf[1]; + } + else + { + printf("done.\n"); + if(success==DRIVER_OP_MMC_SENSE_DATA) + { + disp_sense(p_cdio); + } + else + { + printf("Command sent but returned with an unhandled status code: %02X\n", success); + } + } + + if(success==DRIVER_OP_SUCCESS && (alloc_len>0)) + { + //Limit alloc len to maximum allowed by size of data transfer buffer length. + if((alloc_len+2)>data_buffer_size) + { + alloc_len=data_buffer_size-2; + } + + //Sends MMC1 READ TOC/PMA/ATIP command to drive to get full data. + success=read_TOC_PMA_ATIP(p_cdio, 0, 0, alloc_len+2); + printf("done.\n"); + if(success==DRIVER_OP_SUCCESS) + { + alloc_len=data_buf[0] << 8; + alloc_len=alloc_len | data_buf[1]; + } + else + { + if(success==DRIVER_OP_MMC_SENSE_DATA) + { + disp_sense(p_cdio); + } + else + { + printf("Command sent but returned with an unhandled status code: %02X\n", success); + } + } + } + else + { + printf("failed.\n"); + printf("Could only return 4 byte Read TOC header.\n"); + } + + return success; +} + +/* Sends Test Unit Ready command 3 times, check for errors & display error info. */ +driver_return_code_t verified_test_unit_ready3(CdIo_t *p_cdio) +{ + unsigned char i=3; + driver_return_code_t success; + + /* + Before sending the required command, here we clear any pending sense info from the drive + which may interfere by sending Test Unit Ready command at least 3 times if neccessary. + ----------------------------------------------------------------------------------------*/ + do + { + printf("Sending SPC1 Test Unit CDB6 command.."); + //Sends SPC1 Test Unit Ready command to drive + success=test_unit_ready(p_cdio); + printf("done.\n"); + if(success==DRIVER_OP_SUCCESS) + { + printf("Returned good status.\n"); + i=1; + } + else + { + if(success==DRIVER_OP_MMC_SENSE_DATA) + { + disp_sense(p_cdio); + } + else + { + printf("Command sent but returned with an unhandled status code: %02X\n", success); + } + } + i--; + }while(i>0); + + return success; +} + +//Find lead-out from read TOC data. +bool find_leadout_from_TOC(unsigned char *data_buf, + unsigned char &out_n_tracks, + unsigned long int &out_n_sectors) +{ + unsigned long int i; + unsigned long int sector; + unsigned short int alloc_len; + unsigned short int TOC_response_data_len; + bool found_leadout; + + alloc_len=data_buf[0] << 8; + alloc_len=alloc_len | data_buf[1]; + TOC_response_data_len=alloc_len+2; + found_leadout=false; + out_n_tracks=0; + //Iterate thru TOC entries to find track 0xAA (leadout track).. + for(i=4;i0) + { + //Total sectors before lead-out. + out_n_sectors=sector; + } + else + { + //Error, this should never happen. + out_n_sectors=0; + } + + out_n_tracks--; //Don't include this track. + + found_leadout=true; + } + + out_n_tracks++; + } + } + } + + return found_leadout; +} + +/* +Main loop of reading the CD and writing to image file. +Various error checking are also done here. +*/ +bool read_cd_to_image(char *drive_letter, char *file_pathname, unsigned short int x_speed, unsigned long int data_buffer_size) +{ + CdIo_t *p_cdio; + bool cmd_ret; + driver_return_code_t success; + unsigned char n_tracks; //Total tracks. + unsigned long int n_sectors; //Total sectors on CD. + FILE *file_ptr; + unsigned long int LBA_i; //For counting "from" LBA (starts from 0). + unsigned long int LBA_i2; //For calculating "to" LBA. + unsigned long int n_sectors_to_read; //No. of sectors to read per read command. + unsigned short int speed_kbytes; //Write speed in kbytes. + + p_cdio = open_volume(drive_letter); + if (p_cdio != NULL) + { + printf("\n"); + success=verified_test_unit_ready3(p_cdio); + printf("\n"); + if(success==DRIVER_OP_SUCCESS) + { + //Get TOC from CD. + success=verified_read_TOC(p_cdio, data_buffer_size); + if(success==DRIVER_OP_SUCCESS) + { + if(find_leadout_from_TOC(data_buf, n_tracks, n_sectors)) + { + printf("Total user tracks : %u\n", n_tracks); + printf("Total sectors : %lu\n", n_sectors); + + //Do we need to set CD speed? + if(x_speed!=0) + { + if(x_speed==0xFFFF) + { + speed_kbytes=0xFFFF; //Use maximum write speed. + } + else + { + //Convert x speed to kbytes speed. + speed_kbytes=x_2_kbytes_speed(x_speed); + } + + //Attempt to set the cd read speed to specified and write speed to max. + success=verified_set_cd_speed(p_cdio, speed_kbytes, 0xFFFF); + } +// claunia: no need for this +/* else + { + //No need to set CD speed. + success=true; + }*/ + if(success==DRIVER_OP_SUCCESS) + { + file_ptr=fopen(file_pathname, "wb"); + if(file_ptr!=NULL) + { + n_sectors_to_read=data_buffer_size / 2048; //Block size: E.g.: 65536 / 2048 = 32. + LBA_i=0; //Starting LBA address. + while(LBA_i(n_sectors-LBA_i)) + { + //Alter to the remaining sectors. + n_sectors_to_read=n_sectors-LBA_i; + } + + LBA_i2=LBA_i+n_sectors_to_read-1; + printf("Reading sector %lu to %lu (total: %lu, progress: %.1f%%)\n", LBA_i, LBA_i2, n_sectors, (double)LBA_i2/n_sectors*100); + if(read_cd_2048(p_cdio, LBA_i, n_sectors_to_read, 0)==DRIVER_OP_SUCCESS) + { + if(success==DRIVER_OP_SUCCESS) + { + fwrite(data_buf, 2048*n_sectors_to_read, 1, file_ptr); + if(ferror(file_ptr)) + { + printf("Write file error!\n"); + printf("Aborting process.\n"); + cmd_ret=false; + break; //Stop while loop. + } + } + else + { + if(success==DRIVER_OP_MMC_SENSE_DATA) + { + disp_sense(p_cdio); + } + else + { + printf("Command sent but returned with an unhandled status code: %02X\n", success); + } + + printf("Aborting process.\n"); + break; //Stop while loop. + } + } + else + { + if(success==DRIVER_OP_MMC_SENSE_DATA) + { + disp_sense(p_cdio); + } + else + { + printf("Command sent but returned with an unhandled status code: %02X\n", success); + } + + printf("Aborting process.\n"); + break; //Stop while loop. + } + + LBA_i=LBA_i+n_sectors_to_read; + } + + fclose(file_ptr); + cmd_ret=true; + } + else + { + printf("Could not create file!\n"); + printf("Aborting process.\n"); + cmd_ret = false; + } + } + else + { + printf("Could not set read speed!\n"); + printf("Aborting process.\n"); + cmd_ret = false; + } + } + else + { + printf("Could not find lead-out entry in TOC to determine total sectors on CD!\n"); + printf("Aborting process.\n"); + cmd_ret = false; + } + } + else + { + printf("Could not read TOC!\n"); + printf("Aborting process.\n"); + cmd_ret = false; + } + } + else + { + printf("Drive is not ready!\n"); + printf("Aborting process.\n"); + cmd_ret = false; + } + + cdio_destroy(p_cdio); //Win32 function. + } + else + { + return false; + } + + return cmd_ret; +} + +void usage() +{ + printf("CDToImg v1.02. 13 Oct 2013.\n"); + printf("Usage: cdtoimg [x read speed]\n"); + printf("x speed is one of the following:\n"); + printf(" - Enter CD x speed value.\n"); + printf(" - Ommit or enter 0 to use currently set speed.\n"); + printf(" - Enter m for max speed.\n"); + return ; //Exit program here. +} + +int main(int argc, char *argv[]) +{ + unsigned short int x_speed; + + if((argc == 3) || (argc == 4)) + { + //65536 data transfer buffer. + data_buf=(unsigned char *)malloc(65536); + + if(argc == 3) + { + x_speed=0; //Use currently set write speed. + } + else + { + if(x_speed=argv[3][0]=='m') + { + x_speed=0xFFFF; //Use maximum write speed. + } + else + { + x_speed=atoi(argv[3]); //Use specified write speed. + } + } + if(read_cd_to_image(argv[1], argv[2], x_speed, 65536)) + { + printf("Process finished."); + } + else + { + printf("Could not create image from drive %c.", argv[1][0]); + } + + free(data_buf); + + return 0; + } + else + { + usage(); + return -1; //Exit program here. + } +} \ No newline at end of file diff --git a/cdtoimg.ncb b/cdtoimg.ncb deleted file mode 100755 index 0438045..0000000 Binary files a/cdtoimg.ncb and /dev/null differ diff --git a/cdtoimg.sln b/cdtoimg.sln deleted file mode 100755 index c1d24fb..0000000 --- a/cdtoimg.sln +++ /dev/null @@ -1,21 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 7.00 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cdtoimg", "cdtoimg.vcproj", "{2C7E8552-DC0B-42AC-BE6F-84F6237FE52E}" -EndProject -Global - GlobalSection(SolutionConfiguration) = preSolution - ConfigName.0 = Debug - ConfigName.1 = Release - EndGlobalSection - GlobalSection(ProjectDependencies) = postSolution - EndGlobalSection - GlobalSection(ProjectConfiguration) = postSolution - {2C7E8552-DC0B-42AC-BE6F-84F6237FE52E}.Debug.ActiveCfg = Release|Win32 - {2C7E8552-DC0B-42AC-BE6F-84F6237FE52E}.Debug.Build.0 = Release|Win32 - {2C7E8552-DC0B-42AC-BE6F-84F6237FE52E}.Release.ActiveCfg = Release|Win32 - {2C7E8552-DC0B-42AC-BE6F-84F6237FE52E}.Release.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - EndGlobalSection - GlobalSection(ExtensibilityAddIns) = postSolution - EndGlobalSection -EndGlobal diff --git a/cdtoimg.suo b/cdtoimg.suo deleted file mode 100755 index c10393c..0000000 Binary files a/cdtoimg.suo and /dev/null differ diff --git a/cdtoimg.vcproj b/cdtoimg.vcproj deleted file mode 100755 index 34400ba..0000000 --- a/cdtoimg.vcproj +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/my_ntddscsi.h b/my_ntddscsi.h deleted file mode 100755 index b96f33f..0000000 --- a/my_ntddscsi.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef MY_NTDDSCSI_H -#define MY_NTDDSCSI_H - -#include "spc.h" - -//** Defines taken from ntddscsi.h in MS Windows DDK CD -#define SCSI_IOCTL_DATA_OUT 0 //Give data to SCSI device (e.g. for writing) -#define SCSI_IOCTL_DATA_IN 1 //Get data from SCSI device (e.g. for reading) -#define SCSI_IOCTL_DATA_UNSPECIFIED 2 //No data (e.g. for ejecting) - -#define IOCTL_SCSI_PASS_THROUGH 0x4D004 -typedef struct _SCSI_PASS_THROUGH { - USHORT Length; - UCHAR ScsiStatus; - UCHAR PathId; - UCHAR TargetId; - UCHAR Lun; - UCHAR CdbLength; - UCHAR SenseInfoLength; - UCHAR DataIn; - ULONG DataTransferLength; - ULONG TimeOutValue; - ULONG_PTR DataBufferOffset; - ULONG SenseInfoOffset; - UCHAR Cdb[16]; -}SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH; - -#define IOCTL_SCSI_PASS_THROUGH_DIRECT 0x4D014 -typedef struct _SCSI_PASS_THROUGH_DIRECT { - USHORT Length; - UCHAR ScsiStatus; - UCHAR PathId; - UCHAR TargetId; - UCHAR Lun; - UCHAR CdbLength; - UCHAR SenseInfoLength; - UCHAR DataIn; - ULONG DataTransferLength; - ULONG TimeOutValue; - PVOID DataBuffer; - ULONG SenseInfoOffset; - UCHAR Cdb[16]; -}SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT; -//** End of defines taken from ntddscsi.h from MS Windows DDK CD - -typedef struct _SCSI_PASS_THROUGH_AND_BUFFERS { - SCSI_PASS_THROUGH spt; - BYTE DataBuffer[64*1024]; -}T_SPT_BUFS; - -typedef struct _SCSI_PASS_THROUGH_DIRECT_AND_SENSE_BUFFER { - SCSI_PASS_THROUGH_DIRECT sptd; - UCHAR SenseBuf[MAX_SENSE_LEN]; -}T_SPDT_SBUF; - -#endif diff --git a/sam.h b/sam.h deleted file mode 100755 index 244eac8..0000000 --- a/sam.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - SCSI-3 SCSI Architecture Model definitions (SAM), taken from SCSI-3 SAM1 draft. - Computer Programming Language: MS Visual Studio NET 2002 C/C++. - Author: Truman - Date written: 07 Aug 2005. -*/ -#ifndef SAM_H -#define SAM_H - -//SCSI return status codes. -#define STATUS_GOOD 0x00 // Status Good -#define STATUS_CHKCOND 0x02 // Check Condition -#define STATUS_CONDMET 0x04 // Condition Met -#define STATUS_BUSY 0x08 // Busy -#define STATUS_INTERM 0x10 // Intermediate -#define STATUS_INTCDMET 0x14 // Intermediate-condition met -#define STATUS_RESCONF 0x18 // Reservation conflict -#define STATUS_COMTERM 0x22 // Command Terminated -#define STATUS_QFULL 0x28 // Queue full -#define STATUS_ACA 0x30 // ACA active - -#endif diff --git a/spc.h b/spc.h deleted file mode 100755 index b74ca43..0000000 --- a/spc.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - SCSI-3 Primary Control definitions (SPC). 09 Oct 2006. - Definitions taken from SCSI-3 SPC1 draft. - Computer Programming Language: MS Visual Studio NET 2002 C/C++. - Author: Truman -*/ -#ifndef SPC_H -#define SPC_H - -#define MAX_SENSE_LEN 18 //Sense data max length -//Sense key codes.. -#define SEN_KEY_NO_SEN 0x00 //No sense key info. -#define SEN_KEY_NOT_READY 0x02 //Device not ready error. -#define SEN_KEY_ILLEGAL_REQ 0x05 //Illegal request, error/s in parameters or cmd. - -//CDB for test unit ready command -typedef struct -{ - unsigned char cmd; - unsigned char reserved1; - unsigned char reserved2; - unsigned char reserved3; - unsigned char reserved4; - unsigned char control; -}T_test_unit_ready; - -//Request sense return data format -typedef struct -{ - unsigned char response_code; - unsigned char segment_no; - unsigned char flags_sensekey; - unsigned char info0; - unsigned char info1; - unsigned char info2; - unsigned char info3; - unsigned char add_len; - unsigned char com_spec_info0; - unsigned char com_spec_info1; - unsigned char com_spec_info2; - unsigned char com_spec_info3; - unsigned char ASC; - unsigned char ASCQ; - unsigned char field_rep_ucode; - unsigned char sen_key_spec15; - unsigned char sen_key_spec16; - unsigned char sen_key_spec17; - unsigned char add_sen_bytes; -}T_sense_data; - -#endif