/** * Convert album to CDDB text form */ Cddb::Album::operator QString() const { QString ret = "# xmcd\n" "#\n" "# Track frame offsets:\n"; for (int i = 1; i < toc.size(); ++i) ret += "# " + QString::number(msf2lsn(toc[i - 1])) + '\n'; ret += "#\n"; ret += "# Disc length: " + QString::number( msf2sec(toc.last()) + msf2sec(toc[0]) ) + " seconds\n"; ret += "#\n"; ret += "# Revision: " + QString::number(rev) + '\n'; ret += "#\n"; ret += "# Submitted via: " + (!submitter.isEmpty() ? submitter : "MythTV " MYTH_BINARY_VERSION) + '\n'; ret += "#\n"; ret += "DISCID=" + QString::number(discID,16) + '\n'; ret += "DTITLE=" + artist.toUtf8() + " / " + title + '\n'; ret += "DYEAR=" + (year ? QString::number(year) : "")+ '\n'; ret += "DGENRE=" + genre.toUtf8() + '\n'; for (int t = 0; t < tracks.size(); ++t) ret += "TTITLE" + QString::number(t) + "=" + tracks[t].title.toUtf8() + '\n'; ret += "EXTD=" + extd.toUtf8() + '\n'; for (int t = 0; t < tracks.size(); ++t) ret += "EXTT" + QString::number(t) + "=" + ext[t].toUtf8() + '\n'; ret += "PLAYORDER=\n"; return ret; }
// this function tries to get the .ccd file of the given .img // the necessary data is put into the ti (trackinformation)-array static int parseccd(const char *isofile) { char ccdname[MAXPATHLEN]; FILE *fi; char linebuf[256]; unsigned int t; numtracks = 0; // copy name of the iso and change extension from .img to .ccd strncpy(ccdname, isofile, sizeof(ccdname)); ccdname[MAXPATHLEN - 1] = '\0'; if (strlen(ccdname) >= 4) { strcpy(ccdname + strlen(ccdname) - 4, ".ccd"); } else { return -1; } if ((fi = fopen(ccdname, "r")) == NULL) { return -1; } memset(&ti, 0, sizeof(ti)); while (fgets(linebuf, sizeof(linebuf), fi) != NULL) { if (!strncmp(linebuf, "[TRACK", 6)){ numtracks++; } else if (!strncmp(linebuf, "MODE=", 5)) { sscanf(linebuf, "MODE=%d", &t); ti[numtracks].type = ((t == 0) ? CDDA : DATA); } else if (!strncmp(linebuf, "INDEX 1=", 8)) { sscanf(linebuf, "INDEX 1=%d", &t); sec2msf(t + 2 * 75, ti[numtracks].start); ti[numtracks].start_offset = t * 2352; // If we've already seen another track, this is its end if (numtracks > 1) { t = msf2sec(ti[numtracks].start) - msf2sec(ti[numtracks - 1].start); sec2msf(t, ti[numtracks - 1].length); } } } fclose(fi); // Fill out the last track's end based on size if (numtracks >= 1) { fseek(cdHandle, 0, SEEK_END); t = ftell(cdHandle) / 2352 - msf2sec(ti[numtracks].start) + 2 * 75; sec2msf(t, ti[numtracks].length); } return 0; }
static void Find_CurTrack(const u8 *time) { int current, sect; current = msf2sec(time); for (cdr.CurTrack = 1; cdr.CurTrack < cdr.ResultTN[1]; cdr.CurTrack++) { CDR_getTD(cdr.CurTrack + 1, cdr.ResultTD); sect = fsm2sec(cdr.ResultTD); if (sect - current >= 150) break; } }
// return Track Time // buffer: // byte 0 - frame // byte 1 - second // byte 2 - minute static long CALLBACK ISOgetTD(unsigned char track, unsigned char *buffer) { if (track == 0) { unsigned int sect; unsigned char time[3]; sect = msf2sec(ti[numtracks].start) + msf2sec(ti[numtracks].length); sec2msf(sect, (char *)time); buffer[2] = time[0]; buffer[1] = time[1]; buffer[0] = time[2]; } else if (numtracks > 0 && track <= numtracks) { buffer[2] = ti[track].start[0]; buffer[1] = ti[track].start[1]; buffer[0] = ti[track].start[2]; } else { buffer[2] = 0; buffer[1] = 2; buffer[0] = 0; } return 0; }
// return Track Time // buffer: // byte 0 - frame // byte 1 - second // byte 2 - minute static long ISOgetTD(unsigned char track, unsigned char *buffer) { if (track == 0) { // CD length according pcsxr-svn (done a bit different here) unsigned int sect; unsigned char time[3]; sect = msf2sec((char *)ti[numtracks].start) + msf2sec((char *)ti[numtracks].length); sec2msf(sect, (char *)time); buffer[2] = time[0]; buffer[1] = time[1]; buffer[0] = time[2]; } else if (numtracks > 0 && track <= numtracks) { buffer[2] = ti[track].start[0]; buffer[1] = ti[track].start[1]; buffer[0] = ti[track].start[2]; } else { buffer[2] = 0; buffer[1] = 2; buffer[0] = 0; } return 0; }
static void generate_subq(const u8 *time) { unsigned char start[3], next[3]; unsigned int this_s, start_s, next_s, pregap; int relative_s; CDR_getTD(cdr.CurTrack, start); if (cdr.CurTrack + 1 <= cdr.ResultTN[1]) { pregap = 150; CDR_getTD(cdr.CurTrack + 1, next); } else { // last track - cd size pregap = 0; next[0] = cdr.SetSectorEnd[2]; next[1] = cdr.SetSectorEnd[1]; next[2] = cdr.SetSectorEnd[0]; } this_s = msf2sec(time); start_s = fsm2sec(start); next_s = fsm2sec(next); cdr.TrackChanged = FALSE; if (next_s - this_s < pregap) { cdr.TrackChanged = TRUE; cdr.CurTrack++; start_s = next_s; } cdr.subq.Index = 1; relative_s = this_s - start_s; if (relative_s < 0) { cdr.subq.Index = 0; relative_s = -relative_s; } sec2msf(relative_s, cdr.subq.Relative); cdr.subq.Track = itob(cdr.CurTrack); cdr.subq.Relative[0] = itob(cdr.subq.Relative[0]); cdr.subq.Relative[1] = itob(cdr.subq.Relative[1]); cdr.subq.Relative[2] = itob(cdr.subq.Relative[2]); cdr.subq.Absolute[0] = itob(time[0]); cdr.subq.Absolute[1] = itob(time[1]); cdr.subq.Absolute[2] = itob(time[2]); }
/** * Parse CDDB text */ Cddb::Album& Cddb::Album::operator =(const QString& rhs) { discGenre.clear(); discID = 0; artist.clear(); title.clear(); genre.clear(); year = 0; submitter = "MythTV " MYTH_BINARY_VERSION; rev = 1; isCompilation = false; tracks.clear(); toc.clear(); extd.clear(); ext.clear(); enum { kNorm, kToc } eState = kNorm; QString cddb = QString::fromUtf8(rhs.toLatin1().constData()); while (!cddb.isEmpty()) { // Lines should be of the form "FIELD=value\r\n" QString line = cddb.section(QRegExp("[\r\n]"), 0, 0); if (line.startsWith("# Track frame offsets:")) { eState = kToc; } else if (line.startsWith("# Disc length:")) { QString s = line.section(QRegExp("[ \t]"), 3, 3); unsigned secs = s.toULong(); if (toc.size()) secs -= msf2sec(toc[0]); toc.push_back(sec2msf(secs)); eState = kNorm; } else if (line.startsWith("# Revision:")) { QString s = line.section(QRegExp("[ \t]"), 2, 2); bool bValid = false; int v = s.toInt(&bValid); if (bValid) rev = v; } else if (line.startsWith("# Submitted via:")) { submitter = line.section(QRegExp("[ \t]"), 3, 3); } else if (line.startsWith("#")) { if (kToc == eState) { bool bValid = false; QString s = line.section(QRegExp("[ \t]"), 1).trimmed(); unsigned long lsn = s.toUInt(&bValid); if (bValid) toc.push_back(lsn2msf(lsn)); else eState = kNorm; } } else { QString value = line.section('=', 1, 1); QString art; if (value.contains(" / ")) { art = value.section(" / ", 0, 0); // Artist in *TITLE value = value.section(" / ", 1, 1); } if (line.startsWith("DISCID=")) { bool isValid = false; ulong discID2 = value.toULong(&isValid,16); if (isValid) discID = discID2; } else if (line.startsWith("DTITLE=")) { // Albums (and maybe artists?) can wrap over multiple lines: artist += art; title += value; } else if (line.startsWith("DYEAR=")) { bool isValid = false; int val = value.toInt(&isValid); if (isValid) year = val; } else if (line.startsWith("DGENRE=")) { if (!value.isEmpty()) genre = value; } else if (line.startsWith("TTITLE")) { int trk = line.remove("TTITLE").section('=', 0, 0).toInt(); if (trk >= 0 && trk < CDROM_LEADOUT_TRACK) { if (trk >= tracks.size()) tracks.resize(trk + 1); Cddb::Track& track = tracks[trk]; // Titles can wrap over multiple lines, so we load+store: track.title += value; track.artist += art; if (art.length()) isCompilation = true; } } else if (line.startsWith("EXTD=")) { if (!value.isEmpty()) extd = value; } else if (line.startsWith("EXTT")) { int trk = line.remove("EXTT").section('=', 0, 0).toInt(); if (trk >= 0 && trk < CDROM_LEADOUT_TRACK) { if (trk >= ext.size()) ext.resize(trk + 1); ext[trk] = value; } } } // Next response line: cddb = cddb.section('\n', 1); } return *this; }
static int handlepbp(const char *isofile) { struct { unsigned int sig; unsigned int dontcare[8]; unsigned int psar_offs; } pbp_hdr; struct { unsigned char type; unsigned char pad0; unsigned char track; char index0[3]; char pad1; char index1[3]; } toc_entry; struct { unsigned int offset; unsigned int size; unsigned int dontcare[6]; } index_entry; char psar_sig[11]; unsigned int t, cd_length, cdimg_base; unsigned int offsettab[8], psisoimg_offs; const char *ext = NULL; int i, ret; if (strlen(isofile) >= 4) ext = isofile + strlen(isofile) - 4; if (ext == NULL || (strcmp(ext, ".pbp") != 0 && strcmp(ext, ".PBP") != 0)) return -1; numtracks = 0; ret = fread(&pbp_hdr, 1, sizeof(pbp_hdr), cdHandle); if (ret != sizeof(pbp_hdr)) { SysPrintf("failed to read pbp\n"); goto fail_io; } ret = fseek(cdHandle, pbp_hdr.psar_offs, SEEK_SET); if (ret != 0) { SysPrintf("failed to seek to %x\n", pbp_hdr.psar_offs); goto fail_io; } psisoimg_offs = pbp_hdr.psar_offs; fread(psar_sig, 1, sizeof(psar_sig), cdHandle); psar_sig[10] = 0; if (strcmp(psar_sig, "PSTITLEIMG") == 0) { // multidisk image? ret = fseek(cdHandle, pbp_hdr.psar_offs + 0x200, SEEK_SET); if (ret != 0) { SysPrintf("failed to seek to %x\n", pbp_hdr.psar_offs + 0x200); goto fail_io; } if (fread(&offsettab, 1, sizeof(offsettab), cdHandle) != sizeof(offsettab)) { SysPrintf("failed to read offsettab\n"); goto fail_io; } for (i = 0; i < sizeof(offsettab) / sizeof(offsettab[0]); i++) { if (offsettab[i] == 0) break; } cdrIsoMultidiskCount = i; if (cdrIsoMultidiskCount == 0) { SysPrintf("multidisk eboot has 0 images?\n"); goto fail_io; } if (cdrIsoMultidiskSelect >= cdrIsoMultidiskCount) cdrIsoMultidiskSelect = 0; psisoimg_offs += offsettab[cdrIsoMultidiskSelect]; ret = fseek(cdHandle, psisoimg_offs, SEEK_SET); if (ret != 0) { SysPrintf("failed to seek to %x\n", psisoimg_offs); goto fail_io; } fread(psar_sig, 1, sizeof(psar_sig), cdHandle); psar_sig[10] = 0; } if (strcmp(psar_sig, "PSISOIMG00") != 0) { SysPrintf("bad psar_sig: %s\n", psar_sig); goto fail_io; } // seek to TOC ret = fseek(cdHandle, psisoimg_offs + 0x800, SEEK_SET); if (ret != 0) { SysPrintf("failed to seek to %x\n", psisoimg_offs + 0x800); goto fail_io; } // first 3 entries are special fseek(cdHandle, sizeof(toc_entry), SEEK_CUR); fread(&toc_entry, 1, sizeof(toc_entry), cdHandle); numtracks = btoi(toc_entry.index1[0]); fread(&toc_entry, 1, sizeof(toc_entry), cdHandle); cd_length = btoi(toc_entry.index1[0]) * 60 * 75 + btoi(toc_entry.index1[1]) * 75 + btoi(toc_entry.index1[2]); for (i = 1; i <= numtracks; i++) { fread(&toc_entry, 1, sizeof(toc_entry), cdHandle); ti[i].type = (toc_entry.type == 1) ? CDDA : DATA; ti[i].start_offset = btoi(toc_entry.index0[0]) * 60 * 75 + btoi(toc_entry.index0[1]) * 75 + btoi(toc_entry.index0[2]); ti[i].start_offset *= 2352; ti[i].start[0] = btoi(toc_entry.index1[0]); ti[i].start[1] = btoi(toc_entry.index1[1]); ti[i].start[2] = btoi(toc_entry.index1[2]); if (i > 1) { t = msf2sec(ti[i].start) - msf2sec(ti[i - 1].start); sec2msf(t, ti[i - 1].length); } } t = cd_length - ti[numtracks].start_offset / 2352; sec2msf(t, ti[numtracks].length); // seek to ISO index ret = fseek(cdHandle, psisoimg_offs + 0x4000, SEEK_SET); if (ret != 0) { SysPrintf("failed to seek to ISO index\n"); goto fail_io; } compr_img = calloc(1, sizeof(*compr_img)); if (compr_img == NULL) goto fail_io; compr_img->block_shift = 4; compr_img->current_block = (unsigned int)-1; compr_img->index_len = (0x100000 - 0x4000) / sizeof(index_entry); compr_img->index_table = malloc((compr_img->index_len + 1) * sizeof(compr_img->index_table[0])); if (compr_img->index_table == NULL) goto fail_io; cdimg_base = psisoimg_offs + 0x100000; for (i = 0; i < compr_img->index_len; i++) { ret = fread(&index_entry, 1, sizeof(index_entry), cdHandle); if (ret != sizeof(index_entry)) { SysPrintf("failed to read index_entry #%d\n", i); goto fail_index; } if (index_entry.size == 0) break; compr_img->index_table[i] = cdimg_base + index_entry.offset; } compr_img->index_table[i] = cdimg_base + index_entry.offset + index_entry.size; return 0; fail_index: free(compr_img->index_table); compr_img->index_table = NULL; fail_io: if (compr_img != NULL) { free(compr_img); compr_img = NULL; } return -1; }
// this function tries to get the .mds file of the given .mdf // the necessary data is put into the ti (trackinformation)-array static int parsemds(const char *isofile) { char mdsname[MAXPATHLEN]; FILE *fi; unsigned int offset, extra_offset, l, i; unsigned short s; numtracks = 0; // copy name of the iso and change extension from .mdf to .mds strncpy(mdsname, isofile, sizeof(mdsname)); mdsname[MAXPATHLEN - 1] = '\0'; if (strlen(mdsname) >= 4) { strcpy(mdsname + strlen(mdsname) - 4, ".mds"); } else { return -1; } if ((fi = fopen(mdsname, "rb")) == NULL) { return -1; } memset(&ti, 0, sizeof(ti)); // check if it's a valid mds file fread(&i, 1, sizeof(unsigned int), fi); i = SWAP32(i); if (i != 0x4944454D) { // not an valid mds file fclose(fi); return -1; } // get offset to session block fseek(fi, 0x50, SEEK_SET); fread(&offset, 1, sizeof(unsigned int), fi); offset = SWAP32(offset); // get total number of tracks offset += 14; fseek(fi, offset, SEEK_SET); fread(&s, 1, sizeof(unsigned short), fi); s = SWAP16(s); numtracks = s; // get offset to track blocks fseek(fi, 4, SEEK_CUR); fread(&offset, 1, sizeof(unsigned int), fi); offset = SWAP32(offset); // skip lead-in data while (1) { fseek(fi, offset + 4, SEEK_SET); if (fgetc(fi) < 0xA0) { break; } offset += 0x50; } // check if the image contains mixed subchannel data fseek(fi, offset + 1, SEEK_SET); subChanMixed = subChanRaw = (fgetc(fi) ? TRUE : FALSE); // read track data for (i = 1; i <= numtracks; i++) { fseek(fi, offset, SEEK_SET); // get the track type ti[i].type = ((fgetc(fi) == 0xA9) ? CDDA : DATA); fseek(fi, 8, SEEK_CUR); // get the track starting point ti[i].start[0] = fgetc(fi); ti[i].start[1] = fgetc(fi); ti[i].start[2] = fgetc(fi); fread(&extra_offset, 1, sizeof(unsigned int), fi); extra_offset = SWAP32(extra_offset); // get track start offset (in .mdf) fseek(fi, offset + 0x28, SEEK_SET); fread(&l, 1, sizeof(unsigned int), fi); l = SWAP32(l); ti[i].start_offset = l; // get pregap fseek(fi, extra_offset, SEEK_SET); fread(&l, 1, sizeof(unsigned int), fi); l = SWAP32(l); if (l != 0 && i > 1) pregapOffset = msf2sec(ti[i].start); // get the track length fread(&l, 1, sizeof(unsigned int), fi); l = SWAP32(l); sec2msf(l, ti[i].length); offset += 0x50; } fclose(fi); return 0; }
// this function tries to get the .cue file of the given .bin // the necessary data is put into the ti (trackinformation)-array static int parsecue(const char *isofile) { char cuename[MAXPATHLEN]; char filepath[MAXPATHLEN]; char *incue_fname; FILE *fi; char *token; char time[20]; char *tmp; char linebuf[256], tmpb[256], dummy[256]; unsigned int incue_max_len; unsigned int t, file_len, mode, sector_offs; unsigned int sector_size = 2352; numtracks = 0; // copy name of the iso and change extension from .bin to .cue strncpy(cuename, isofile, sizeof(cuename)); cuename[MAXPATHLEN - 1] = '\0'; if (strlen(cuename) >= 4) { strcpy(cuename + strlen(cuename) - 4, ".cue"); } else { return -1; } if ((fi = fopen(cuename, "r")) == NULL) { return -1; } // Some stupid tutorials wrongly tell users to use cdrdao to rip a // "bin/cue" image, which is in fact a "bin/toc" image. So let's check // that... if (fgets(linebuf, sizeof(linebuf), fi) != NULL) { if (!strncmp(linebuf, "CD_ROM_XA", 9)) { // Don't proceed further, as this is actually a .toc file rather // than a .cue file. fclose(fi); return parsetoc(isofile); } fseek(fi, 0, SEEK_SET); } // build a path for files referenced in .cue strncpy(filepath, cuename, sizeof(filepath)); tmp = strrchr(filepath, '/'); if (tmp == NULL) tmp = strrchr(filepath, '\\'); if (tmp != NULL) tmp++; else tmp = filepath; *tmp = 0; filepath[sizeof(filepath) - 1] = 0; incue_fname = tmp; incue_max_len = sizeof(filepath) - (tmp - filepath) - 1; memset(&ti, 0, sizeof(ti)); file_len = 0; sector_offs = 2 * 75; while (fgets(linebuf, sizeof(linebuf), fi) != NULL) { strncpy(dummy, linebuf, sizeof(linebuf)); token = strtok(dummy, " "); if (token == NULL) { continue; } if (!strcmp(token, "TRACK")) { numtracks++; sector_size = 0; if (strstr(linebuf, "AUDIO") != NULL) { ti[numtracks].type = CDDA; sector_size = 2352; } else if (sscanf(linebuf, " TRACK %u MODE%u/%u", &t, &mode, §or_size) == 3) ti[numtracks].type = DATA; else { SysPrintf(".cue: failed to parse TRACK\n"); ti[numtracks].type = numtracks == 1 ? DATA : CDDA; } if (sector_size == 0) sector_size = 2352; } else if (!strcmp(token, "INDEX")) { if (sscanf(linebuf, " INDEX %02d %8s", &t, time) != 2) SysPrintf(".cue: failed to parse INDEX\n"); tok2msf(time, (char *)&ti[numtracks].start); t = msf2sec(ti[numtracks].start); ti[numtracks].start_offset = t * sector_size; t += sector_offs; sec2msf(t, ti[numtracks].start); // default track length to file length t = file_len - ti[numtracks].start_offset / sector_size; sec2msf(t, ti[numtracks].length); if (numtracks > 1 && ti[numtracks].handle == NULL) { // this track uses the same file as the last, // start of this track is last track's end t = msf2sec(ti[numtracks].start) - msf2sec(ti[numtracks - 1].start); sec2msf(t, ti[numtracks - 1].length); } if (numtracks > 1 && pregapOffset == -1) pregapOffset = ti[numtracks].start_offset / sector_size; } else if (!strcmp(token, "PREGAP")) { if (sscanf(linebuf, " PREGAP %8s", time) == 1) { tok2msf(time, dummy); sector_offs += msf2sec(dummy); } pregapOffset = -1; // mark to fill track start_offset } else if (!strcmp(token, "FILE")) { t = sscanf(linebuf, " FILE \"%256[^\"]\"", tmpb); if (t != 1) sscanf(linebuf, " FILE %256s", tmpb); // absolute path? ti[numtracks + 1].handle = fopen(tmpb, "rb"); if (ti[numtracks + 1].handle == NULL) { // relative to .cue? tmp = strrchr(tmpb, '\\'); if (tmp == NULL) tmp = strrchr(tmpb, '/'); if (tmp != NULL) tmp++; else tmp = tmpb; strncpy(incue_fname, tmp, incue_max_len); ti[numtracks + 1].handle = fopen(filepath, "rb"); } // update global offset if this is not first file in this .cue if (numtracks + 1 > 1) { multifile = 1; sector_offs += file_len; } file_len = 0; if (ti[numtracks + 1].handle == NULL) { SysPrintf(_("\ncould not open: %s\n"), filepath); continue; } fseek(ti[numtracks + 1].handle, 0, SEEK_END); file_len = ftell(ti[numtracks + 1].handle) / 2352; if (numtracks == 0 && strlen(isofile) >= 4 && strcmp(isofile + strlen(isofile) - 4, ".cue") == 0) { // user selected .cue as image file, use it's data track instead fclose(cdHandle); cdHandle = fopen(filepath, "rb"); } } } fclose(fi); return 0; }
// this function tries to get the .toc file of the given .bin // the necessary data is put into the ti (trackinformation)-array static int parsetoc(const char *isofile) { char tocname[MAXPATHLEN]; FILE *fi; char linebuf[256], tmp[256], name[256]; char *token; char time[20], time2[20]; unsigned int t, sector_offs, sector_size; unsigned int current_zero_gap = 0; numtracks = 0; // copy name of the iso and change extension from .bin to .toc strncpy(tocname, isofile, sizeof(tocname)); tocname[MAXPATHLEN - 1] = '\0'; if (strlen(tocname) >= 4) { strcpy(tocname + strlen(tocname) - 4, ".toc"); } else { return -1; } if ((fi = fopen(tocname, "r")) == NULL) { // try changing extension to .cue (to satisfy some stupid tutorials) strcpy(tocname + strlen(tocname) - 4, ".cue"); if ((fi = fopen(tocname, "r")) == NULL) { // if filename is image.toc.bin, try removing .bin (for Brasero) strcpy(tocname, isofile); t = strlen(tocname); if (t >= 8 && strcmp(tocname + t - 8, ".toc.bin") == 0) { tocname[t - 4] = '\0'; if ((fi = fopen(tocname, "r")) == NULL) { return -1; } } else { return -1; } } // check if it's really a TOC named as a .cue fgets(linebuf, sizeof(linebuf), fi); token = strtok(linebuf, " "); if (token && strncmp(token, "CD", 2) != 0 && strcmp(token, "CATALOG") != 0) { fclose(fi); return -1; } fseek(fi, 0, SEEK_SET); } memset(&ti, 0, sizeof(ti)); cddaBigEndian = TRUE; // cdrdao uses big-endian for CD Audio sector_size = CD_FRAMESIZE_RAW; sector_offs = 2 * 75; // parse the .toc file while (fgets(linebuf, sizeof(linebuf), fi) != NULL) { // search for tracks strncpy(tmp, linebuf, sizeof(linebuf)); token = strtok(tmp, " "); if (token == NULL) continue; if (!strcmp(token, "TRACK")) { sector_offs += current_zero_gap; current_zero_gap = 0; // get type of track token = strtok(NULL, " "); numtracks++; if (!strncmp(token, "MODE2_RAW", 9)) { ti[numtracks].type = DATA; sec2msf(2 * 75, ti[numtracks].start); // assume data track on 0:2:0 // check if this image contains mixed subchannel data token = strtok(NULL, " "); if (token != NULL && !strncmp(token, "RW", 2)) { sector_size = CD_FRAMESIZE_RAW + SUB_FRAMESIZE; subChanMixed = TRUE; if (!strncmp(token, "RW_RAW", 6)) subChanRaw = TRUE; } } else if (!strncmp(token, "AUDIO", 5)) { ti[numtracks].type = CDDA; } } else if (!strcmp(token, "DATAFILE")) { if (ti[numtracks].type == CDDA) { sscanf(linebuf, "DATAFILE \"%[^\"]\" #%d %8s", name, &t, time2); ti[numtracks].start_offset = t; t = t / sector_size + sector_offs; sec2msf(t, (char *)&ti[numtracks].start); tok2msf((char *)&time2, (char *)&ti[numtracks].length); } else { sscanf(linebuf, "DATAFILE \"%[^\"]\" %8s", name, time); tok2msf((char *)&time, (char *)&ti[numtracks].length); } } else if (!strcmp(token, "FILE")) { sscanf(linebuf, "FILE \"%[^\"]\" #%d %8s %8s", name, &t, time, time2); tok2msf((char *)&time, (char *)&ti[numtracks].start); t += msf2sec(ti[numtracks].start) * sector_size; ti[numtracks].start_offset = t; t = t / sector_size + sector_offs; sec2msf(t, (char *)&ti[numtracks].start); tok2msf((char *)&time2, (char *)&ti[numtracks].length); } else if (!strcmp(token, "ZERO") || !strcmp(token, "SILENCE")) { // skip unneeded optional fields while (token != NULL) { token = strtok(NULL, " "); if (strchr(token, ':') != NULL) break; } if (token != NULL) { tok2msf(token, tmp); current_zero_gap = msf2sec(tmp); } if (numtracks > 1) { t = ti[numtracks - 1].start_offset; t /= sector_size; pregapOffset = t + msf2sec(ti[numtracks - 1].length); } } else if (!strcmp(token, "START")) { token = strtok(NULL, " "); if (token != NULL && strchr(token, ':')) { tok2msf(token, tmp); t = msf2sec(tmp); ti[numtracks].start_offset += (t - current_zero_gap) * sector_size; t = msf2sec(ti[numtracks].start) + t; sec2msf(t, (char *)&ti[numtracks].start); } } } fclose(fi); return 0; }
// this function tries to get the .cue file of the given .bin // the necessary data is put into the ti (trackinformation)-array static int parsecue(const char *isofile) { char cuename[MAXPATHLEN]; FILE *fi; char *token; char time[20]; char *tmp; char linebuf[256], dummy[256]; unsigned int t; numtracks = 0; // copy name of the iso and change extension from .bin to .cue strncpy(cuename, isofile, sizeof(cuename)); cuename[MAXPATHLEN - 1] = '\0'; if (strlen(cuename) >= 4) { strcpy(cuename + strlen(cuename) - 4, ".cue"); } else { return -1; } if ((fi = fopen(cuename, "r")) == NULL) { return -1; } // Some stupid tutorials wrongly tell users to use cdrdao to rip a // "bin/cue" image, which is in fact a "bin/toc" image. So let's check // that... if (fgets(linebuf, sizeof(linebuf), fi) != NULL) { if (!strncmp(linebuf, "CD_ROM_XA", 9)) { // Don't proceed further, as this is actually a .toc file rather // than a .cue file. fclose(fi); return parsetoc(isofile); } fseek(fi, 0, SEEK_SET); } memset(&ti, 0, sizeof(ti)); while (fgets(linebuf, sizeof(linebuf), fi) != NULL) { strncpy(dummy, linebuf, sizeof(linebuf)); token = strtok(dummy, " "); if (token == NULL) { continue; } if (!strcmp(token, "TRACK")){ numtracks++; if (strstr(linebuf, "AUDIO") != NULL) { ti[numtracks].type = CDDA; } else if (strstr(linebuf, "MODE1/2352") != NULL || strstr(linebuf, "MODE2/2352") != NULL) { ti[numtracks].type = DATA; } } else if (!strcmp(token, "INDEX")) { tmp = strstr(linebuf, "INDEX"); if (tmp != NULL) { tmp += strlen("INDEX") + 3; // 3 - space + numeric index while (*tmp == ' ') tmp++; if (*tmp != '\n') sscanf(tmp, "%8s", time); } tok2msf((char *)&time, (char *)&ti[numtracks].start); t = msf2sec(ti[numtracks].start) + 2 * 75; sec2msf(t, ti[numtracks].start); // If we've already seen another track, this is its end if (numtracks > 1) { t = msf2sec(ti[numtracks].start) - msf2sec(ti[numtracks - 1].start); sec2msf(t, ti[numtracks - 1].length); } } } fclose(fi); // Fill out the last track's end based on size if (numtracks >= 1) { fseek(cdHandle, 0, SEEK_END); t = ftell(cdHandle) / 2352 - msf2sec(ti[numtracks].start) + 2 * 75; sec2msf(t, ti[numtracks].length); } return 0; }
// this function tries to get the .toc file of the given .bin // the necessary data is put into the ti (trackinformation)-array static int parsetoc(const char *isofile) { char tocname[MAXPATHLEN]; FILE *fi; char linebuf[256], dummy[256], name[256]; char *token; char time[20], time2[20]; unsigned int t; numtracks = 0; // copy name of the iso and change extension from .bin to .toc strncpy(tocname, isofile, sizeof(tocname)); tocname[MAXPATHLEN - 1] = '\0'; if (strlen(tocname) >= 4) { strcpy(tocname + strlen(tocname) - 4, ".toc"); } else { return -1; } if ((fi = fopen(tocname, "r")) == NULL) { // try changing extension to .cue (to satisfy some stupid tutorials) strcpy(tocname + strlen(tocname) - 4, ".cue"); if ((fi = fopen(tocname, "r")) == NULL) { // if filename is image.toc.bin, try removing .bin (for Brasero) strcpy(tocname, isofile); t = strlen(tocname); if (t >= 8 && strcmp(tocname + t - 8, ".toc.bin") == 0) { tocname[t - 4] = '\0'; if ((fi = fopen(tocname, "r")) == NULL) { return -1; } } else { return -1; } } } memset(&ti, 0, sizeof(ti)); cddaBigEndian = TRUE; // cdrdao uses big-endian for CD Audio // parse the .toc file while (fgets(linebuf, sizeof(linebuf), fi) != NULL) { // search for tracks strncpy(dummy, linebuf, sizeof(linebuf)); token = strtok(dummy, " "); if (token == NULL) continue; if (!strcmp(token, "TRACK")) { // get type of track token = strtok(NULL, " "); numtracks++; if (!strncmp(token, "MODE2_RAW", 9)) { ti[numtracks].type = DATA; sec2msf(2 * 75, ti[numtracks].start); // assume data track on 0:2:0 // check if this image contains mixed subchannel data token = strtok(NULL, " "); if (token != NULL && !strncmp(token, "RW_RAW", 6)) { subChanMixed = TRUE; subChanRaw = TRUE; } } else if (!strncmp(token, "AUDIO", 5)) { ti[numtracks].type = CDDA; } } else if (!strcmp(token, "DATAFILE")) { if (ti[numtracks].type == CDDA) { sscanf(linebuf, "DATAFILE \"%[^\"]\" #%d %8s", name, &t, time2); t /= CD_FRAMESIZE_RAW + (subChanMixed ? SUB_FRAMESIZE : 0); t += 2 * 75; sec2msf(t, (char *)&ti[numtracks].start); tok2msf((char *)&time2, (char *)&ti[numtracks].length); } else { sscanf(linebuf, "DATAFILE \"%[^\"]\" %8s", name, time); tok2msf((char *)&time, (char *)&ti[numtracks].length); } } else if (!strcmp(token, "FILE")) { sscanf(linebuf, "FILE \"%[^\"]\" #%d %8s %8s", name, &t, time, time2); tok2msf((char *)&time, (char *)&ti[numtracks].start); t /= CD_FRAMESIZE_RAW + (subChanMixed ? SUB_FRAMESIZE : 0); t += msf2sec(ti[numtracks].start) + 2 * 75; sec2msf(t, (char *)&ti[numtracks].start); tok2msf((char *)&time2, (char *)&ti[numtracks].length); } } fclose(fi); return 0; }
static int parsepbp(const char *isofile) { struct { unsigned int sig; unsigned int dontcare[8]; unsigned int psar_offs; } pbp_hdr; struct { unsigned char type; unsigned char pad0; unsigned char track; char index0[3]; char pad1; char index1[3]; } toc_entry; struct { unsigned int offset; unsigned int size; unsigned int dontcare[6]; } index_entry; char psar_sig[9]; unsigned int t, cd_length, cdimg_base; const char *ext = NULL; int i, ret; if (strlen(isofile) >= 4) ext = isofile + strlen(isofile) - 4; if (ext == NULL || (strcmp(ext, ".pbp") != 0 && strcmp(ext, ".PBP") != 0)) return -1; numtracks = 0; ret = fread(&pbp_hdr, 1, sizeof(pbp_hdr), cdHandle); if (ret != sizeof(pbp_hdr)) { fprintf(stderr, "failed to read pbp\n"); goto fail_io; } ret = fseek(cdHandle, pbp_hdr.psar_offs, SEEK_SET); if (ret != 0) { fprintf(stderr, "failed to seek to %x\n", pbp_hdr.psar_offs); goto fail_io; } fread(psar_sig, 1, sizeof(psar_sig), cdHandle); psar_sig[8] = 0; if (strcmp(psar_sig, "PSISOIMG") != 0) { fprintf(stderr, "bad psar_sig: %s\n", psar_sig); goto fail_io; } // seek to TOC ret = fseek(cdHandle, pbp_hdr.psar_offs + 0x800, SEEK_SET); if (ret != 0) { fprintf(stderr, "failed to seek to %x\n", pbp_hdr.psar_offs); goto fail_io; } // first 3 entries are special fseek(cdHandle, sizeof(toc_entry), SEEK_CUR); fread(&toc_entry, 1, sizeof(toc_entry), cdHandle); numtracks = btoi(toc_entry.index1[0]); fread(&toc_entry, 1, sizeof(toc_entry), cdHandle); cd_length = btoi(toc_entry.index1[0]) * 60 * 75 + btoi(toc_entry.index1[1]) * 75 + btoi(toc_entry.index1[2]); for (i = 1; i <= numtracks; i++) { fread(&toc_entry, 1, sizeof(toc_entry), cdHandle); ti[i].type = (toc_entry.type == 1) ? trackinfo::CDDA : trackinfo::DATA; ti[i].start_offset = btoi(toc_entry.index0[0]) * 60 * 75 + btoi(toc_entry.index0[1]) * 75 + btoi(toc_entry.index0[2]); ti[i].start[0] = btoi(toc_entry.index1[0]); ti[i].start[1] = btoi(toc_entry.index1[1]); ti[i].start[2] = btoi(toc_entry.index1[2]); if (i > 1) { t = msf2sec((char *)ti[i].start) - msf2sec((char *)ti[i - 1].start); sec2msf(t, (char *)ti[i - 1].length); } } t = cd_length - ti[numtracks].start_offset; sec2msf(t, (char *)ti[numtracks].length); // seek to ISO index ret = fseek(cdHandle, pbp_hdr.psar_offs + 0x4000, SEEK_SET); if (ret != 0) { fprintf(stderr, "failed to seek to ISO index\n"); goto fail_io; } compr_img = (struct compr_img_struct *)calloc(1, sizeof(*compr_img)); if (compr_img == NULL) goto fail_io; compr_img->current_block = (unsigned int)-1; compr_img->index_len = (0x100000 - 0x4000) / sizeof(index_entry); compr_img->index_table = (u32 *)malloc((compr_img->index_len + 1) * sizeof(compr_img->index_table[0])); if (compr_img->index_table == NULL) goto fail_io; cdimg_base = pbp_hdr.psar_offs + 0x100000; for (i = 0; i < compr_img->index_len; i++) { ret = fread(&index_entry, 1, sizeof(index_entry), cdHandle); if (ret != sizeof(index_entry)) { fprintf(stderr, "failed to read index_entry #%d\n", i); goto fail_index; } if (index_entry.size == 0) break; compr_img->index_table[i] = cdimg_base + index_entry.offset; } compr_img->index_table[i] = cdimg_base + index_entry.offset + index_entry.size; return 0; fail_index: free(compr_img->index_table); compr_img->index_table = NULL; fail_io: return -1; }