/* Changes: * - 64-bit fixes * - BigEndian fixes * - Enable sanity checking * - Various bugfixes */ #include #include #include #include #include #include #include #include #define DEBUG 0 #define CHECK 1 typedef uint16_t le16_t; /* Little-endian 16-bit */ typedef uint32_t le32_t; /* Little-endian 32-bit */ //----------------Wave Stuff---------------------/ typedef struct wavHdr { uint8_t riff[4]; le32_t bytestoend; uint8_t wavetxt[4]; uint8_t fmttxt[4]; le32_t formatsize; // 16 byte format specifier le16_t format; // Windows PCM le16_t channels; // 2 channels le32_t samplerate; // 44,100 Samples/sec le32_t avgbyterate; // 176,400 Bytes/sec le16_t samplebytes; // 4 bytes/sample le16_t channelbits; // 16 bits/channel uint8_t datatxt[4]; le32_t blocksize; } tWavHead; #define HEADBYTES 36 #define WINDOWS_PCM 0x0001 //-------------------------------------------------/ /* G L O B A L D E F I N E S */ typedef uint8_t byte; #define SIZERAW 2352 #define SIZEISO_MODE1 2048 #define SIZEISO_MODE2_RAW 2352 #define SIZEISO_MODE2_FORM1 2048 #define SIZEISO_MODE2_FORM2 2336 #define AUDIO 0 #define MODE1 1 #define MODE2 2 #define MODE1_2352 10 #define MODE2_2352 20 #define MODE1_2048 30 #define MODE2_2336 40 #define PROG_INTERVAL 1024 #define UNKNOWN -1 #define OFFSET 150 // got this from easycd pro by looking at a blank disk so it may be off... #define CD74_MAX_SECTORS 334873 // 653.75 Mb static inline le16_t cpu_to_le16(uint16_t value) { uint8_t *bytes = (uint8_t *)&value; le16_t ret; ret = bytes[0]; ret |= (uint16_t)(bytes[1]) << 8; return ret; } static inline le32_t cpu_to_le32(uint32_t value) { uint8_t *bytes = (uint8_t *)&value; le32_t ret; ret = bytes[0]; ret |= (uint32_t)(bytes[1]) << 8; ret |= (uint32_t)(bytes[2]) << 16; ret |= (uint32_t)(bytes[3]) << 24; return ret; } unsigned long int Index(char m, char s, char f) { unsigned long int temp; temp = (((m >> 4) * 10) + (m & 0xf)) * 60; temp = (temp + (((s >> 4) * 10) + (s & 0xf))) * 75; temp = temp + (((f >> 4) * 10) + (f & 0xf)); return temp; } void unIndex(unsigned long int index, char *ptr) { char m, s, f; f = (char)(index % 75); s = (char)((index / 75) % 60); m = (char)(index / (75 * 60)); sprintf(ptr, "%d%d:%d%d:%d%d", m / 10, m % 10, s / 10, s % 10, f / 10, f % 10); } // global variables static FILE *fdBinFile; static FILE *fdCueFile; static FILE *fdOutFile; static char sBinFilename[PATH_MAX]; static char sOutFilename[PATH_MAX]; static unsigned long int writepos = 0; // for inplace conversions... #define OUTBUF_SIZE 4*1024*1024 #define INBUF_SIZE 4*1024*1024 static unsigned char OUTBUF[OUTBUF_SIZE]; static unsigned int OUTBUF_IDX = 0; static unsigned char INBUF[INBUF_SIZE]; static unsigned int INBUF_RIDX = 0; static unsigned int INBUF_WIDX = 0; static int mode2to1 = 0; typedef struct track { unsigned short mode; unsigned long idx0; unsigned long idx1; char num[3]; char name[80]; unsigned long offset0; unsigned long offset1; unsigned long size; /* track size in bytes */ } tTrack; static int buffered_fread(unsigned char *array, unsigned int size) { unsigned int i; if (INBUF_WIDX == 0) { INBUF_WIDX += fread(INBUF, 1, (INBUF_SIZE / size) * size, fdBinFile); } if (INBUF_WIDX == 0) return 0; // read failed. for (i = 0; i < size; i++) { array[i] = INBUF[INBUF_RIDX++]; if ((INBUF_RIDX == INBUF_WIDX) && (i < (size - 1))) { printf(" Warning: Premature EOF\n"); while (i++ < size) { array[i] = 0; } /* zero fill the rest */ break; } } if (INBUF_RIDX == INBUF_WIDX) { INBUF_RIDX = 0; INBUF_WIDX = 0; } return 1; // read passed } static void buffered_fwrite(unsigned char *array, unsigned int size) { unsigned int idx; unsigned long int readpos = 0; if (OUTBUF_IDX + size >= OUTBUF_SIZE) { if (fdOutFile == fdBinFile) { readpos = ftell(fdOutFile); if (0 != fseek(fdOutFile, writepos, SEEK_SET)) { perror("\nbin2iso(fseek)"); exit(1); } } // printf("\nWriting \n"); if (1 != fwrite(OUTBUF, OUTBUF_IDX, 1, fdOutFile)) { perror("\nbin2iso(fwrite)"); fclose(fdOutFile); // remove(sOutFilename); exit(1); } if (1 != fwrite(array, size, 1, fdOutFile)) { perror("\nbin2iso(fwrite)"); fclose(fdOutFile); // remove(sOutFilename); exit(1); } // printf("\nWrote %d bytes \n", OUTBUF_IDX+size); OUTBUF_IDX = 0; if (fdOutFile == fdBinFile) { writepos = ftell(fdOutFile); if (0 != fseek(fdOutFile, readpos, SEEK_SET)) { perror("\nbin2iso(fseek)"); exit(1); } } } else { for (idx = 0; idx < size; idx++) { OUTBUF[OUTBUF_IDX + idx] = array[idx]; } OUTBUF_IDX += size; } } static void flush_buffers(void) { unsigned long int readpos = 0; if (fdOutFile == fdBinFile) { readpos = ftell(fdOutFile); if (0 != fseek(fdOutFile, writepos, SEEK_SET)) { perror("\nbin2iso(fseek)"); exit(1); } } if (1 != fwrite(OUTBUF, OUTBUF_IDX, 1, fdOutFile)) { perror("\nbin2iso(fwrite)"); fclose(fdOutFile); // remove(sOutFilename); exit(1); } // printf("\nWrote %d bytes \n", OUTBUF_IDX); OUTBUF_IDX = 0; INBUF_RIDX = 0; INBUF_WIDX = 0; if (fdOutFile == fdBinFile) { writepos = ftell(fdOutFile); if (0 != fseek(fdOutFile, readpos, SEEK_SET)) { perror("\nbin2iso(fseek)"); exit(1); } } } // presumes Line is preloaded with the "current" line of the file static int getTrackinfo(char *Line, tTrack * track) { // char tnum[3]; char inum[3]; char min; char sec; char block; track->idx0 = -1; track->idx1 = -1; // Get the 'mode' if (strncmp(&Line[2], "TRACK ", 6) == 0) { strncpy(track->num, &Line[8], 2); track->num[2] = '\0'; track->mode = UNKNOWN; if (strncmp(&Line[11], "AUDIO", 5) == 0) track->mode = AUDIO; if (strncmp(&Line[11], "MODE1/2352", 10) == 0) track->mode = MODE1_2352; if (strncmp(&Line[11], "MODE1/2048", 10) == 0) track->mode = MODE1_2048; if (strncmp(&Line[11], "MODE2/2352", 10) == 0) track->mode = MODE2_2352; if (strncmp(&Line[11], "MODE2/2336", 10) == 0) track->mode = MODE2_2336; } else return (1); // Set the name strcpy(track->name, sBinFilename); track->name[strlen(sBinFilename) - 4] = '\0'; strcat(track->name, "-"); strcat(track->name, track->num); if ((track->mode == MODE1_2352) || (track->mode == MODE1_2048) || (track->mode == MODE2_2352) || (track->mode == MODE2_2336)) { strcat(track->name, ".iso"); } else if (track->mode == AUDIO) { strcat(track->name, ".wav"); } else { printf("Track %s Unsupported mode\n", track->num); return (1); } // Get the track indexes while (1) { if (!fgets(Line, 256, fdCueFile)) { break; } if (strncmp(&Line[2], "TRACK ", 6) == 0) { break; // next track starting } if (strncmp(&Line[4], "INDEX ", 6) == 0) { strncpy(inum, &Line[10], 2); inum[2] = '\0'; min = ((Line[13] - '0') << 4) | (Line[14] - '0'); sec = ((Line[16] - '0') << 4) | (Line[17] - '0'); block = ((Line[19] - '0') << 4) | (Line[20] - '0'); if (strcmp(inum, "00") == 0) track->idx0 = Index(min, sec, block); else if (strcmp(inum, "01") == 0) track->idx1 = Index(min, sec, block); else { printf("Unexpected Index number: %s\n", inum); exit(1); } } else if (strncmp(&Line[4], "PREGAP ", 7) == 0) {; /* ignore, handled below */ } else if (strncmp(&Line[4], "FLAGS ", 6) == 0) {; /* ignore */ } else { printf("Unexpected cuefile line: %s\n", Line); } } if (track->idx0 == -1) track->idx0 = track->idx1; if (track->idx1 == -1) track->idx1 = track->idx0; return (0); } static void dotrack(short mode, long preidx, long startidx, long endidx, unsigned long offset) { unsigned char buf[SIZERAW + 100]; unsigned long blockswritten = 0; unsigned int uiLastIndex; #if CHECK unsigned int uiCurrentIndex; #endif unsigned int write = 1; tWavHead wavhead = { "RIFF", cpu_to_le32(0), "WAVE", "fmt ", cpu_to_le32(16), // 16 byte format specifier cpu_to_le16(WINDOWS_PCM), // format cpu_to_le16(2), // 2 Channels cpu_to_le32(44100), // 44,100 Samples/sec cpu_to_le32(176400), // 176,400 Bytes/sec cpu_to_le16(4), // 4 bytes/sample cpu_to_le16(16), // 16 bits/channel "data", cpu_to_le32(0), }; uiLastIndex = startidx - 1; // Input -- process -- Output if (startidx != 0) printf("\nNote: PreGap = %ld frames\n", startidx - preidx); else printf("\nNote: PreGap = %d frames\n", OFFSET); // cd standard: starting offset // - of course this isn't true for bootable cd's... if (sOutFilename[0] != '\0') { printf("Creating %s (%06ld,%06ld) ", sOutFilename, startidx, endidx - 1); } else { printf("Converting (%06ld,%06ld) ", startidx, endidx - 1); } switch (mode) { case AUDIO: printf("Audio"); break; case MODE1_2352: printf("Mode1/2048"); break; case MODE2_2336: printf("Mode2/2352"); break; case MODE2_2352: if (mode2to1 != 1) printf("Mode2/2352"); else printf("Mode1/2048"); break; case MODE1_2048: printf("Mode1/2048"); break; default: printf("Huh? What's going on?"); exit(1); } printf(" : "); if (sOutFilename[0] != '\0') { if (NULL == (fdOutFile = fopen(sOutFilename, "wb"))) { perror("bin2iso(fopen)"); } // printf("\nOpened File %s: %d\n", sOutFilename, fdOutFile); } else { fdOutFile = fdBinFile; } if (fdOutFile == NULL) { printf(" Unable to create %s\n", sOutFilename); exit(1); } if (0 != fseek(fdBinFile, offset, SEEK_SET)) { perror("\nbin2iso(fseek)"); exit(1); } #if (DEBUG == 0) if (mode == AUDIO) { if (1 != fwrite(&wavhead, sizeof(wavhead), 1, fdOutFile)) { // write placeholder perror("\nbin2iso(fwrite)"); fclose(fdOutFile); // remove(sOutFilename); exit(1); } } #endif memset(&buf[0], '\0', sizeof(buf)); if (mode == MODE2_2336) { unsigned int M = 0, S = 2, F = 0; while (buffered_fread(&buf[16], SIZEISO_MODE2_FORM2)) { //setup headed area (probably not necessary though... //buf[0] = 0; memset(&buf[1], 0xFF, sizeof(buf[0]) * 10); //buf[11] = 0; buf[12] = M; buf[13] = S; buf[14] = F; buf[15] = MODE2; if ((++F & 0xF) == 0xA) F += 6; if (F == 0x75) { S++; F = 0; } if ((S & 0xF) == 0xA) S += 6; if (S == 0x60) { M++; S = 0; } if ((M & 0xF) == 0xA) M += 6; // printf("\n%x:%x:%x", M, S, F); buffered_fwrite(buf, SIZERAW); uiLastIndex++; memset(&buf[0], '\0', sizeof(buf)); if (startidx % PROG_INTERVAL == 0) { printf("\b\b\b\b\b\b%06ld", startidx); } if (++startidx == endidx) { printf("\b\b\b\b\b\bComplete\n"); break; } } } else if (mode == MODE1_2048) { while (buffered_fread(buf, SIZEISO_MODE1)) { buffered_fwrite(buf, SIZEISO_MODE1); uiLastIndex++; if (startidx % PROG_INTERVAL == 0) { printf("\b\b\b\b\b\b%06ld", startidx); } if (++startidx == endidx) { printf("\b\b\b\b\b\bComplete\n"); break; } } } else { while (buffered_fread(buf, SIZERAW)) { switch (mode) { case AUDIO: #if (DEBUG == 0) buffered_fwrite(buf, SIZERAW); #endif uiLastIndex++; blockswritten++; break; case MODE1_2352: // should put a crc check in here... #if CHECK if (buf[15] != MODE1) { printf("\nWarning: Mode Error in bin file!\n"); printf(" %02x:%02x:%02x : mode %02x\n", buf[12], buf[13], buf[14], buf[15]); //exit(1); } uiCurrentIndex = Index(buf[12], buf[13], buf[14]) - OFFSET; if (uiCurrentIndex != uiLastIndex + 1) { printf("\nWarning: Frame Error in bin file!\n"); printf("Last %02d:%02d:%02d (%d)\n", ((uiLastIndex + OFFSET) / 75) / 60, ((uiLastIndex + OFFSET) / 75) % 60, (uiLastIndex + OFFSET) % 75, uiLastIndex); printf("Current %02x:%02x:%02x (%d)\n", buf[12], buf[13], buf[14], uiCurrentIndex); printf("Expecting %02d:%02d:%02d (%d)\n", ((uiLastIndex + OFFSET + 1) / 75) / 60, ((uiLastIndex + OFFSET + 1) / 75) % 60, (uiLastIndex + OFFSET + 1) % 75, uiLastIndex + 1); } #endif #if (DEBUG == 0) buffered_fwrite(&buf[16], SIZEISO_MODE1); #endif #if CHECK uiLastIndex = uiCurrentIndex; #endif break; case MODE2_2352: #if CHECK if ((buf[15] & 0xf) != MODE2) { printf("\nWarning: Mode Error in bin file!\n"); printf(" %02x:%02x:%02x : mode %02x\n", buf[12], buf[13], buf[14], buf[15]); //exit(1); } uiCurrentIndex = Index(buf[12], buf[13], buf[14]) - OFFSET; if (uiCurrentIndex != uiLastIndex + 1) { printf("\nWarning: Frame Error in bin file!\n"); printf("Last %02d:%02d:%02d (%d)\n", ((uiLastIndex + OFFSET) / 75) / 60, ((uiLastIndex + OFFSET) / 75) % 60, (uiLastIndex + OFFSET) % 75, uiLastIndex); printf("Current %02x:%02x:%02x (%d)\n", buf[12], buf[13], buf[14], uiCurrentIndex); printf("Expecting %02d:%02d:%02d (%d)\n", ((uiLastIndex + OFFSET + 1) / 75) / 60, ((uiLastIndex + OFFSET + 1) / 75) % 60, (uiLastIndex + OFFSET + 1) % 75, uiLastIndex + 1); } #endif #if (DEBUG == 0) if (mode2to1) buffered_fwrite(&buf[16 + 8], SIZEISO_MODE1); else if (write) buffered_fwrite(&buf[0], SIZEISO_MODE2_RAW); #endif #if CHECK uiLastIndex = uiCurrentIndex; #endif break; default: printf("Unkown Mode\n"); exit(1); break; } memset(&buf[0], '\0', sizeof(buf)); if (startidx % PROG_INTERVAL == 0) { printf("\b\b\b\b\b\b%06ld", startidx); } if (++startidx == endidx) { printf("\b\b\b\b\b\bComplete\n"); break; } } } flush_buffers(); // flushes write buffer // and clears read buffer. if (mode == AUDIO) { wavhead.blocksize = cpu_to_le32(blockswritten * SIZERAW); wavhead.bytestoend = cpu_to_le32((blockswritten * SIZERAW) + HEADBYTES); // rewind to the beginning if (0 != fseek(fdOutFile, 0, SEEK_SET)) { perror("\nbin2iso(fseek)"); exit(1); } #if (DEBUG == 0) fwrite(&wavhead, sizeof(wavhead), 1, fdOutFile); #endif } fclose(fdOutFile); } static void doCueFile(void) { int track = 1; unsigned long int binIndex = 0; unsigned long int trackIndex = 0; const int gapThreshold = 20; // look for 0.266 sec gap const int valueThreshold = 800; // look for samples < 700 int count = 0; int i, blank; int gapon = 0; short value; char mode[12] = "AUDIO"; char index0[9] = "00:00:00"; char index1[9] = "00:00:00"; unsigned char buf[SIZERAW + 100]; printf("FILE %s BINARY\n", sBinFilename); fprintf(fdCueFile, "FILE %s BINARY\n", sBinFilename); memset(buf, '\0', sizeof(buf)); while (fread(buf, 1, SIZERAW, fdBinFile)) { if (trackIndex == 0) { if ((buf[0] == 0x00) && (buf[1] == 0xFF) && (buf[2] == 0xFF) && (buf[3] == 0xFF) && (buf[4] == 0xFF) && (buf[5] == 0xFF) && (buf[6] == 0xFF) && (buf[7] == 0xFF) && (buf[8] == 0xFF) && (buf[9] == 0xFF) && (buf[10] == 0xFF) && (buf[11] == 0x00) ) { sprintf(mode, "MODE%d/2352", buf[15]); } else { sprintf(mode, "AUDIO"); } } if (binIndex == 0) { printf(" TRACK %02d %s\n", track, mode); fprintf(fdCueFile, " TRACK %02d %s\n", track, mode); printf(" INDEX 01 %s\n", index0); fprintf(fdCueFile, " INDEX 01 %s\n", index0); } blank = 1; for (i = 0; i < SIZERAW; i += 2) { value = buf[i + 1]; value = ((value << 8) | buf[i]); // printf("%f %i\n",(1.0/75)*binIndex, value); if (abs(value) > valueThreshold) { blank = 0; break; } } // if(i == SIZERAW) printf("%f ~blank~\n", (1.0/75)*binIndex); if (blank == 1) count++; else if (gapon == 1) { gapon = 0; unIndex(binIndex - count, index0); count = 0; unIndex(binIndex, index1); printf(" TRACK %02d %s\n", track, mode); fprintf(fdCueFile, " TRACK %02d %s\n", track, mode); printf(" INDEX 00 %s\n", index0); fprintf(fdCueFile, " INDEX 00 %s\n", index0); printf(" INDEX 01 %s\n", index1); fprintf(fdCueFile, " INDEX 01 %s\n", index1); } if ((count > gapThreshold) && (gapon == 0)) { gapon = 1; track++; trackIndex = -1; } memset(buf, '\0', sizeof(buf)); binIndex++; trackIndex++; } } // return 0 to when no data found, 1 when there is. static int checkGaps(FILE * fdBinFile, tTrack tracks[], int nTracks) { int i, k; unsigned long int j; unsigned char buf[SIZERAW]; int writegap = 0; short value; int count; if (nTracks == 2) { return 0; }; // don't need to bother with single track images printf("Checking gap data:\n"); for (i = 0; i < nTracks; i++) { if ((tracks[i].offset0 != tracks[i].offset1) && (tracks[i - 1].mode == AUDIO)) { if (0 != fseek(fdBinFile, tracks[i].offset0, SEEK_SET)) { perror("\nbin2iso(fseek)"); exit(1); } count = 0; for (j = tracks[i].idx0; j < tracks[i].idx1; j++) { if (0 == fread(buf, SIZERAW, 1, fdBinFile)) { perror("bin2iso(fread)"); exit(1); } for (k = 0; k < SIZERAW; k += 2) { value = buf[k + 1]; value = ((value << 8) | buf[k]); if (value != 0) { count++; // printf("%10d: %2x\n", count ,value ); } } } if (count != 0) { printf (" Track%02d - %d values of Non-Zero gap data encountered\n", i - 1, count); if ((count > SIZERAW / 2 / 2) && (writegap == 0)) { printf(" -->Threashold reached\n"); writegap = 1; } } } } return writegap; } static void string_tolower(char *str, size_t len) { while (len && *str) { *str = tolower(*str); str++; len--; } } static void string_toupper(char *str, size_t len) { while (len && *str) { *str = toupper(*str); str++; len--; } } static FILE * fopen_filecase(const char *path, const char *file, const char *openmode) { char filename[PATH_MAX] = { 0, }; char final[PATH_MAX] = { 0, }; FILE *fd; char *pos; /* Try original */ strncpy(filename, file, sizeof(filename) - 1); snprintf(final, sizeof(final), "%s/%s", path, filename); fd = fopen(final, openmode); if (fd) goto ok; /* Try lower.lower */ strncpy(filename, file, sizeof(filename) - 1); string_tolower(filename, (size_t)-1); snprintf(final, sizeof(final), "%s/%s", path, filename); fd = fopen(final, openmode); if (fd) goto ok; /* Try UPPER.UPPER */ strncpy(filename, file, sizeof(filename) - 1); string_toupper(filename, (size_t)-1); snprintf(final, sizeof(final), "%s/%s", path, filename); fd = fopen(final, openmode); if (fd) goto ok; /* Try lower.UPPER */ strncpy(filename, file, sizeof(filename) - 1); string_tolower(filename, (size_t)-1); pos = strrchr(filename, '.'); if (pos) string_toupper(pos, (size_t)-1); snprintf(final, sizeof(final), "%s/%s", path, filename); fd = fopen(final, openmode); if (fd) goto ok; /* Try UPPER.lower */ strncpy(filename, file, sizeof(filename) - 1); string_toupper(filename, (size_t)-1); pos = strrchr(filename, '.'); if (pos) string_tolower(pos, (size_t)-1); snprintf(final, sizeof(final), "%s/%s", path, filename); fd = fopen(final, openmode); if (fd) goto ok; return NULL; ok: printf("%s: Opening file %s\n", file, final); return fd; } /* /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ */ int main(int argc, char **argv) { // int printon = 0; char sLine[256]; int i, j, q; // int writegap = -1; // auto detect pregap data action by default. int writegap = 1; // keep pregap data by default. int no_overburn = 0; int createCue = 0; char sTrack[3] = "00"; int doOneTrack = 0; int doInPlace = 0; tTrack trackA; tTrack trackB; tTrack tracks[100]; int nTracks = 0; char sOutdir[PATH_MAX]; const char *cueFilename; char cuePathBuf[PATH_MAX]; char *cuePath; sOutFilename[0] = '\0'; /* Tell them what I am. */ printf("\n%s, %s", __DATE__, __TIME__); printf("\nbin2iso V1.9b - Converts RAW format (.bin) files to ISO/WAV format"); printf("\n Bob Doiron, ICQ#280251 \n"); printf("\nCheck for updates at http://users.andara.com/~doiron\n\n"); if (argc < 2) { printf("Usage: bin2iso [] [-[a]wg] [-t XX] [-i] [-nob]\n"); printf("or : bin2iso -c \n"); printf("\n"); printf("Where:\n"); printf(" - the .cue file that belongs to the .bin file to \n"); printf(" be converted\n"); printf(" - the output directory (defaults to current dir) \n"); printf(" -nwg - indicates that audio data found in the track \n"); printf(" 'gaps' shouldn't be appended to the audio tracks\n"); printf(" -awg - looks for non-zero data in the 'gaps', if found\n"); printf(" then gaps are appended to audio tracks. Looks \n"); printf(" for more than 1/2 of a sector of non-zero values\n"); printf(" (%d values), \n", SIZERAW / 2 / 2); printf(" -t XX - Extracts the XX'th track. \n"); printf(" -i - Performs the conversion 'in place'. Meaning it \n"); printf(" truncates the binfile after each track is \n"); printf(" created to minimize diskspace requirements. \n"); printf(" [not valid with -t] \n"); printf(" -nob - Doesn't use overburn data past %d sectors. \n", CD74_MAX_SECTORS); printf(" This of course presumes that the data is not \n"); printf(" useful. \n"); printf(" -c - Attempts to create a from an existing\n"); printf(" \n"); exit(1); } strcpy(sOutdir, "./"); // default path printf("\n"); for (i = 2; i < argc; i++) { if (argv[i][0] == '-') { /* if (strncmp(&(argv[i][1]), "wg", 2)==0) { writegap = 1; } else */ if (strncmp(&(argv[i][1]), "awg", 3) == 0) { writegap = -1; printf("Note: Auto-detecting pregap data\n"); } else if (strncmp(&(argv[i][1]), "nwg", 3) == 0) { writegap = 0; } else if (strncmp(&(argv[i][1]), "m2to1", 5) == 0) { mode2to1 = 1; printf("Note: Converting Mode2 ISO to Mode1\n"); } else if (strncmp(&(argv[i][1]), "t", 1) == 0) { strcpy(sTrack, argv[i + 1]); doOneTrack = 1; i++; } else if (strncmp(&(argv[i][1]), "i", 1) == 0) { if (doOneTrack == 1) { printf("Invalid combination of options...\n"); exit(1); } printf("Bin file will be truncated after each track created\n"); doInPlace = 1; } else if (strncmp(&(argv[i][1]), "c", 1) == 0) { createCue = 1; strcpy(sBinFilename, argv[i + 1]); i++; } else if (strncmp(&(argv[i][1]), "nob", 3) == 0) { no_overburn = 1; } } else { strcpy(sOutdir, argv[2]); } } cueFilename = argv[1]; strcpy(cuePathBuf, cueFilename); cuePath = dirname(cuePathBuf); if (createCue == 1) { fdBinFile = fopen(sBinFilename, "rb"); if (fdBinFile == NULL) { printf("Unable to open %s\n", sBinFilename); exit(1); } fdCueFile = fopen(cueFilename, "w"); if (fdCueFile == NULL) { printf("Unable to create %s\n", cueFilename); exit(1); } if ((strcmp(&sBinFilename[strlen(sBinFilename) - 4], ".wav") == 0) || (strcmp(&sBinFilename[strlen(sBinFilename) - 4], ".WAV") == 0)) { printf(".wav binfile - Skipping wav header\n"); fread(sLine, 1, sizeof(tWavHead), fdBinFile); } doCueFile(); } else { fdCueFile = fopen(cueFilename, "r"); if (fdCueFile == NULL) { printf("Unable to open %s\n", cueFilename); exit(1); } // get bin filename from cuefile... why? why not. if (!fgets(sLine, 256, fdCueFile)) { printf("Error Reading Cuefile\n"); exit(1); } if (strncmp(sLine, "FILE ", 5) == 0) { i = 0; j = 0; q = 0; // track open and closed quotes do { sBinFilename[j] = sLine[5 + i]; i++; j++; if ((sBinFilename[j - 1] == '\\') || (sBinFilename[j - 1] == '/')) { j = 0; } //strip out path info if (sBinFilename[j - 1] == '"') { j--; q++; } // strip out quotes } while ((sLine[5 + i - 1] != ' ') || (q == 1)); sBinFilename[j] = '\0'; //bug?? Why did a trailing space show up?? while (sBinFilename[--j] == ' ') sBinFilename[j] = '\0'; } else { printf("Error: Filename not found on first line of cuefile.\n"); exit(1); } // Open the bin file if (doInPlace == 1) { fdBinFile = fopen_filecase(cuePath, sBinFilename, "rb+"); } else { fdBinFile = fopen_filecase(cuePath, sBinFilename, "rb"); } if (fdBinFile == NULL) { printf("Unable to open %s\n", sBinFilename); perror("\nbin2iso(fopen)"); exit(1); } // Get next line if (!fgets(sLine, 256, fdCueFile)) { printf("Error Reading Cuefile\n"); exit(1); } if (strlen(sOutdir) > 0) { if ((sOutdir[strlen(sOutdir) - 1] != '/') && (sOutdir[strlen(sOutdir) - 1] != ':')) { strcat(sOutdir, "/"); } } while (!feof(fdCueFile)) { getTrackinfo(sLine, &tracks[nTracks++]); } tracks[nTracks].idx0 = tracks[nTracks].idx1 = -1; switch (tracks[0].mode) { case MODE1_2048: tracks[0].offset0 = tracks[0].idx0 * SIZEISO_MODE1; break; case MODE2_2336: tracks[0].offset0 = tracks[0].idx0 * SIZEISO_MODE2_FORM2; break; default: // AUDIO, MODE1_2352, MODE2_2352: tracks[0].offset0 = tracks[0].idx0 * SIZERAW; break; } /* set offsets */ if (0 != fseek(fdBinFile, 0, SEEK_END)) { perror("\nbin2iso(fseek)"); exit(1); } tracks[nTracks].offset0 = tracks[nTracks].offset1 = ftell(fdBinFile); for (i = 0; i < nTracks; i++) { switch (tracks[i].mode) { case MODE1_2048: tracks[i].offset1 = tracks[i].offset0 + (tracks[i].idx1 - tracks[i].idx0) * SIZEISO_MODE1; if (tracks[i + 1].idx0 != -1) tracks[i + 1].offset0 = tracks[i].offset1 + (tracks[i + 1].idx0 - tracks[i].idx1) * SIZEISO_MODE1; else { tracks[i + 1].idx0 = tracks[i + 1].idx1 = (tracks[i + 1].offset0 - tracks[i].offset1) / SIZEISO_MODE1 + tracks[i].idx1; if (((tracks[i + 1].offset0 - tracks[i].offset1) % SIZEISO_MODE1) != 0) printf ("Warning: Bin file has invalid byte count for cuefile.\n"); } break; case MODE2_2336: tracks[i].offset1 = tracks[i].offset0 + (tracks[i].idx1 - tracks[i].idx0) * SIZEISO_MODE2_FORM2; if (tracks[i + 1].idx0 != -1) tracks[i + 1].offset0 = tracks[i].offset1 + (tracks[i + 1].idx0 - tracks[i].idx1) * SIZEISO_MODE2_FORM2; else { tracks[i + 1].idx0 = tracks[i + 1].idx1 = (tracks[i + 1].offset0 - tracks[i].offset1) / SIZEISO_MODE2_FORM2 + tracks[i].idx1; if (((tracks[i + 1].offset0 - tracks[i].offset1) % SIZEISO_MODE2_FORM2) != 0) printf ("Warning: Bin file has invalid byte count for cuefile.\n"); } break; default: // AUDIO, MODE1_2352, MODE2_2352: tracks[i].offset1 = tracks[i].offset0 + (tracks[i].idx1 - tracks[i].idx0) * SIZERAW; if (tracks[i + 1].idx0 != -1) tracks[i + 1].offset0 = tracks[i].offset1 + (tracks[i + 1].idx0 - tracks[i].idx1) * SIZERAW; else { tracks[i + 1].idx0 = tracks[i + 1].idx1 = (tracks[i + 1].offset0 - tracks[i].offset1) / SIZERAW + tracks[i].idx1; if (((tracks[i + 1].offset0 - tracks[i].offset1) % SIZERAW) != 0) printf ("Warning: Bin file has invalid byte count for cuefile.\n"); } break; } } // if not allowing overburn, then create a new track to hold extra data... if (no_overburn == 1) { i = nTracks; if (tracks[i].idx0 > CD74_MAX_SECTORS) { tracks[i + 1] = tracks[nTracks]; strcpy(tracks[i].name, "obdatatemp.bin"); tracks[i].idx0 = CD74_MAX_SECTORS; tracks[i].idx1 = CD74_MAX_SECTORS; switch (tracks[i - 1].mode) { case MODE1_2048: tracks[i].offset0 = tracks[i - 1].offset1 + (tracks[i].idx0 - tracks[i - 1].idx1) * SIZEISO_MODE1; break; case MODE2_2336: tracks[i].offset0 = tracks[i - 1].offset1 + (tracks[i].idx0 - tracks[i - 1].idx1) * SIZEISO_MODE2_FORM2; break; default: // AUDIO, MODE1_2352, MODE2_2352: tracks[i].offset0 = tracks[i - 1].offset1 + (tracks[i].idx0 - tracks[i - 1].idx1) * SIZERAW; break; } tracks[i].offset1 = tracks[i].offset0; tracks[i].mode = tracks[i - 1].mode; nTracks++; } } /* set sizes */ for (i = 0; i < nTracks; i++) { switch (tracks[i].mode) { case MODE1_2352: tracks[i].size = ((tracks[i + 1].offset1 - tracks[i].offset1) / SIZERAW) * SIZEISO_MODE1; break; case MODE2_2336: tracks[i].size = ((tracks[i + 1].offset1 - tracks[i].offset1) / SIZEISO_MODE2_FORM2) * SIZERAW; break; default: // MODE1_2048, MODE2_2352, AUDIO tracks[i].size = tracks[i + 1].offset1 - tracks[i].offset1; break; } } if (writegap == -1) { writegap = checkGaps(fdBinFile, tracks, nTracks); } if (writegap == 1) printf("Note: Appending pregap data to end of audio tracks\n"); else printf("Note: Discarding pregap data\n"); printf("\n"); for (i = 0; i <= nTracks - 1; i++) { printf("%s (%3ld Mb) - sectors %06ld:%06ld (offset %09ld:%09ld)\n", tracks[i].name, tracks[i].size / (1024 * 1024), tracks[i].idx1, (((writegap == 0) || (tracks[i].mode != AUDIO)) ? tracks[i + 1].idx0 : tracks[i + 1].idx1) - 1, tracks[i].offset1, (((writegap == 0) || (tracks[i].mode != AUDIO)) ? tracks[i + 1].offset0 : tracks[i + 1].offset1) - 1); } printf("\n"); if ((((mode2to1 != 1) && (tracks[0].mode == MODE2_2352)) || (tracks[0].mode == MODE1_2048)) && (nTracks == 1)) { if (tracks[0].mode == MODE2_2352) { printf("Mode2/2352"); } if (tracks[0].mode == MODE1_2048) { printf("Mode1/2048"); } printf(" single track bin file indicated by cue file\n"); fclose(fdBinFile); if (0 != rename(sBinFilename, tracks[0].name)) { perror("\nbin2iso(rename)"); exit(1); } printf("%s renamed to %s\n", sBinFilename, tracks[0].name); fclose(fdCueFile); return (0); } for (i = nTracks - 1; i >= 0; i--) { trackA = tracks[i]; trackB = tracks[i + 1]; // audio can't be done in the bin file due to header. // 2336 can't either because it's expanded to 2352 if ((doInPlace == 1) && (i == 0) && (trackA.mode != AUDIO) && (trackA.mode != MODE2_2336)) { sOutFilename[0] = '\0'; } else { strcpy(sOutFilename, sOutdir); strcat(sOutFilename, trackA.name); } if (((doOneTrack == 1) && strcmp(trackA.num, sTrack) == 0) || (doOneTrack == 0)) { if (! ((i == 0) && ((trackA.mode == MODE2_2352) || (trackA.mode == MODE1_2048)) && (doInPlace == 1))) { if (!writegap || (trackA.mode != AUDIO)) { // when not Audio, don't append. dotrack(trackA.mode, trackA.idx0, trackA.idx1, trackB.idx0, trackA.offset1); } else { /* if(trackA.idx0 == 0) // handles first track with pregap. dotrack(trackA.mode, 0, trackA.idx1, trackB.idx1, trackA.offset1); else */ dotrack(trackA.mode, trackA.idx1, trackA.idx1, trackB.idx1, trackA.offset1); } } } /*else { fclose(fdBinFile); // just close bin file. Already MODE1_2048 or MODE2_2352 } */ if ((doOneTrack == 0) && (doInPlace == 1)) { if ((i != 0) || ((i == 0) && ((trackA.mode == AUDIO) || (trackA.mode == MODE2_2336)))) { printf("Truncating bin file to %ld bytes\n", trackA.offset1); if (-1 == ftruncate(fileno(fdBinFile), trackA.offset1)) { perror("\nbin2iso(_chsize)"); exit(1); } } else { printf("Renaming %s to %s\n", sBinFilename, trackA.name); fclose(fdBinFile); if (0 != rename(sBinFilename, trackA.name)) { perror("\nbin2iso(rename)"); exit(1); } // fix writepos for case when simply truncating... if ((trackA.mode == MODE2_2352) || (trackA.mode == MODE1_2048)) { writepos = trackB.offset0; } printf("Truncating to %ld bytes\n", writepos); fdBinFile = fopen(trackA.name, "rb+"); // gets closed in doTrack... if (fdBinFile == NULL) { perror("bin2iso(fopen)"); exit(1); } if (-1 == ftruncate(fileno(fdBinFile), writepos)) { perror("\nbin2iso(_chsize)"); exit(1); } } } } } fclose(fdCueFile); fclose(fdBinFile); return 0; }