/*! Convert an LBA into a string representation of the MSF. \warning cdio_lba_to_msf_str returns new allocated string */ char * cdio_lba_to_msf_str (lba_t lba) { if (CDIO_INVALID_LBA == lba) { return strdup("*INVALID"); } else { msf_t msf; msf.m = msf.s = msf.f = 0; cdio_lba_to_msf (lba, &msf); return cdio_msf_to_str(&msf); } }
/*! Return the starting MSF (minutes/secs/frames) for track number i_track in cdio. Track numbers start at 1. The "leadout" track is specified either by using i_track LEADOUT_TRACK or the total tracks+1. False is returned if there is no track entry. */ bool cdio_get_track_msf(const CdIo_t *p_cdio, track_t i_track, /*out*/ msf_t *msf) { if (!p_cdio) return false; if (p_cdio->op.get_track_msf) { return p_cdio->op.get_track_msf (p_cdio->env, i_track, msf); } else if (p_cdio->op.get_track_lba) { lba_t lba = p_cdio->op.get_track_lba (p_cdio->env, i_track); if (lba == CDIO_INVALID_LBA) return false; cdio_lba_to_msf(lba, msf); return true; } else { return false; } }
/*! Return the starting MSF (minutes/secs/frames) for track number track_num in cdio. Track numbers start at 1. The "leadout" track is specified either by using track_num LEADOUT_TRACK or the total tracks+1. False is returned if there is no track entry. */ bool cdio_get_track_msf(const CdIo *cdio, track_t track_num, /*out*/ msf_t *msf) { cdio_assert (cdio != NULL); if (cdio->op.get_track_msf) { return cdio->op.get_track_msf (cdio->env, track_num, msf); } else if (cdio->op.get_track_lba) { lba_t lba = cdio->op.get_track_lba (cdio->env, track_num); if (lba == CDIO_INVALID_LBA) return false; cdio_lba_to_msf(lba, msf); return true; } else { return false; } }
/*! Reads a single mode2 sector from cd device into data starting from lsn. Returns 0 if no error. */ static int _cdio_read_mode2_sector (void *env, void *data, lsn_t lsn, bool mode2_form2) { char buf[M2RAW_SECTOR_SIZE] = { 0, }; struct cdrom_msf *msf = (struct cdrom_msf *) &buf; msf_t _msf; _img_private_t *_obj = env; cdio_lba_to_msf (cdio_lsn_to_lba(lsn), &_msf); msf->cdmsf_min0 = from_bcd8(_msf.m); msf->cdmsf_sec0 = from_bcd8(_msf.s); msf->cdmsf_frame0 = from_bcd8(_msf.f); retry: switch (_obj->access_mode) { case _AM_NONE: cdio_error ("no way to read mode2"); return 1; break; case _AM_IOCTL: if (ioctl (_obj->gen.fd, CDROMREADMODE2, &buf) == -1) { perror ("ioctl()"); return 1; /* exit (EXIT_FAILURE); */ } break; case _AM_READ_CD: case _AM_READ_10: if (_read_packet_mode2_sectors (_obj->gen.fd, buf, lsn, 1, (_obj->access_mode == _AM_READ_10))) { perror ("ioctl()"); if (_obj->access_mode == _AM_READ_CD) { cdio_info ("READ_CD failed; switching to READ_10 mode..."); _obj->access_mode = _AM_READ_10; goto retry; } else { cdio_info ("READ_10 failed; switching to ioctl(CDROMREADMODE2) mode..."); _obj->access_mode = _AM_IOCTL; goto retry; } return 1; } break; } if (mode2_form2) memcpy (data, buf, M2RAW_SECTOR_SIZE); else memcpy (((char *)data), buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE); return 0; }
/* Updates internal track TOC, so we can later simulate ioctl(CDROMREADTOCENTRY). */ static void _register_mapping (_img_private_t *env, lsn_t start_lsn, uint32_t sec_count, uint64_t img_offset, uint32_t blocksize, track_format_t track_format, bool track_green) { const int track_num=env->gen.i_tracks; track_info_t *this_track=&(env->tocent[env->gen.i_tracks]); _mapping_t *_map = calloc(1, sizeof (_mapping_t)); _map->start_lsn = start_lsn; _map->sec_count = sec_count; _map->img_offset = img_offset; _map->blocksize = blocksize; if (!env->mapping) env->mapping = _cdio_list_new (); _cdio_list_append (env->mapping, _map); env->size = MAX (env->size, (start_lsn + sec_count)); /* Update *this_track and track_num. These structures are in a sense redundant witht the obj->mapping list. Perhaps one or the other can be eliminated. */ cdio_lba_to_msf (cdio_lsn_to_lba(start_lsn), &(this_track->start_msf)); this_track->start_lba = cdio_msf_to_lba(&this_track->start_msf); this_track->track_num = track_num+1; this_track->blocksize = blocksize; if (env->is_cues) this_track->datastart = img_offset; else this_track->datastart = 0; if (track_green) this_track->datastart += CDIO_CD_SUBHEADER_SIZE; this_track->sec_count = sec_count; this_track->track_format= track_format; this_track->track_green = track_green; switch (this_track->track_format) { case TRACK_FORMAT_AUDIO: this_track->blocksize = CDIO_CD_FRAMESIZE_RAW; this_track->datasize = CDIO_CD_FRAMESIZE_RAW; /*this_track->datastart = 0;*/ this_track->endsize = 0; break; case TRACK_FORMAT_CDI: this_track->datasize=CDIO_CD_FRAMESIZE; break; case TRACK_FORMAT_XA: if (track_green) { this_track->blocksize = CDIO_CD_FRAMESIZE; /*this_track->datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE;*/ this_track->datasize = M2RAW_SECTOR_SIZE; this_track->endsize = 0; } else { /*this_track->datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE;*/ this_track->datasize = CDIO_CD_FRAMESIZE; this_track->endsize = CDIO_CD_SYNC_SIZE + CDIO_CD_ECC_SIZE; } break; case TRACK_FORMAT_DATA: if (track_green) { /*this_track->datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE;*/ this_track->datasize = CDIO_CD_FRAMESIZE; this_track->endsize = CDIO_CD_EDC_SIZE + CDIO_CD_M1F1_ZERO_SIZE + CDIO_CD_ECC_SIZE; } else { /* Is the below correct? */ /*this_track->datastart = 0;*/ this_track->datasize = CDIO_CD_FRAMESIZE; this_track->endsize = 0; } break; default: /*this_track->datasize=CDIO_CD_FRAMESIZE_RAW;*/ cdio_warn ("track %d has unknown format %d", env->gen.i_tracks, this_track->track_format); } env->gen.i_tracks++; cdio_debug ("start lsn: %lu sector count: %0lu -> %8ld (%08lx)", (long unsigned int) start_lsn, (long unsigned int) sec_count, (long unsigned int) img_offset, (long unsigned int) img_offset); }
static bool parse_tocfile (_img_private_t *cd, const char *psz_cue_name) { /* The below declarations may be common in other image-parse routines. */ FILE *fp; char psz_line[MAXLINE]; /* text of current line read in file fp. */ unsigned int i_line=0; /* line number in file of psz_line. */ int i = -1; /* Position in tocent. Same as cd->gen.i_tracks - 1 */ char *psz_keyword, *psz_field, *psz_cue_name_dup; cdio_log_level_t log_level = (cd) ? CDIO_LOG_WARN : CDIO_LOG_INFO ; cdtext_field_t cdtext_key; /* The below declaration(s) may be unique to this image-parse routine. */ unsigned int i_cdtext_nest = 0; if (NULL == psz_cue_name) return false; psz_cue_name_dup = _cdio_strdup_fixpath(psz_cue_name); if (NULL == psz_cue_name_dup) return false; fp = CDIO_FOPEN (psz_cue_name_dup, "r"); cdio_free(psz_cue_name_dup); if (fp == NULL) { cdio_log(log_level, "error opening %s for reading: %s", psz_cue_name, strerror(errno)); return false; } if (cd) { cd->gen.b_cdtext_error = false; } while (fgets(psz_line, MAXLINE, fp)) { i_line++; /* strip comment from line */ /* todo: // in quoted strings? */ /* //comment */ if ((psz_field = strstr (psz_line, "//"))) *psz_field = '\0'; if ((psz_keyword = strtok (psz_line, " \t\n\r"))) { /* CATALOG "ddddddddddddd" */ if (0 == strcmp ("CATALOG", psz_keyword)) { if (-1 == i) { if (NULL != (psz_field = strtok (NULL, "\"\t\n\r"))) { if (13 != strlen(psz_field)) { cdio_log(log_level, "%s line %d after word CATALOG:", psz_cue_name, i_line); cdio_log(log_level, "Token %s has length %ld. Should be 13 digits.", psz_field, (long int) strlen(psz_field)); goto err_exit; } else { /* Check that we have all digits*/ unsigned int j; for (j=0; j<13; j++) { if (!isdigit((unsigned char) psz_field[j])) { cdio_log(log_level, "%s line %d after word CATALOG:", psz_cue_name, i_line); cdio_log(log_level, "Character \"%c\" at postition %i of token \"%s\"" " is not all digits.", psz_field[j], j+1, psz_field); goto err_exit; } } if (NULL != cd) cd->psz_mcn = strdup (psz_field); } } else { cdio_log(log_level, "%s line %d after word CATALOG:", psz_cue_name, i_line); cdio_log(log_level, "Expecting 13 digits; nothing seen."); goto err_exit; } } else { goto err_exit; } /* CD_DA | CD_ROM | CD_ROM_XA */ } else if (0 == strcmp ("CD_DA", psz_keyword)) { if (-1 == i) { if (NULL != cd) cd->disc_mode = CDIO_DISC_MODE_CD_DA; } else { goto not_in_global_section; } } else if (0 == strcmp ("CD_ROM", psz_keyword)) { if (-1 == i) { if (NULL != cd) cd->disc_mode = CDIO_DISC_MODE_CD_DATA; } else { goto not_in_global_section; } } else if (0 == strcmp ("CD_ROM_XA", psz_keyword)) { if (-1 == i) { if (NULL != cd) cd->disc_mode = CDIO_DISC_MODE_CD_XA; } else { goto not_in_global_section; } /* TRACK <track-mode> [<sub-channel-mode>] */ } else if (0 == strcmp ("TRACK", psz_keyword)) { i++; if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) { if (0 == strcmp ("AUDIO", psz_field)) { if (NULL != cd) { cd->tocent[i].track_format = TRACK_FORMAT_AUDIO; cd->tocent[i].blocksize = CDIO_CD_FRAMESIZE_RAW; cd->tocent[i].datasize = CDIO_CD_FRAMESIZE_RAW; cd->tocent[i].datastart = 0; cd->tocent[i].endsize = 0; switch(cd->disc_mode) { case CDIO_DISC_MODE_NO_INFO: cd->disc_mode = CDIO_DISC_MODE_CD_DA; break; case CDIO_DISC_MODE_CD_DA: case CDIO_DISC_MODE_CD_MIXED: case CDIO_DISC_MODE_ERROR: /* Disc type stays the same. */ break; case CDIO_DISC_MODE_CD_DATA: case CDIO_DISC_MODE_CD_XA: cd->disc_mode = CDIO_DISC_MODE_CD_MIXED; break; default: cd->disc_mode = CDIO_DISC_MODE_ERROR; } } } else if (0 == strcmp ("MODE1", psz_field)) { if (NULL != cd) { cd->tocent[i].track_format = TRACK_FORMAT_DATA; cd->tocent[i].blocksize = CDIO_CD_FRAMESIZE_RAW; cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE; cd->tocent[i].datasize = CDIO_CD_FRAMESIZE; cd->tocent[i].endsize = CDIO_CD_EDC_SIZE + CDIO_CD_M1F1_ZERO_SIZE + CDIO_CD_ECC_SIZE; switch(cd->disc_mode) { case CDIO_DISC_MODE_NO_INFO: cd->disc_mode = CDIO_DISC_MODE_CD_DATA; break; case CDIO_DISC_MODE_CD_DATA: case CDIO_DISC_MODE_CD_MIXED: case CDIO_DISC_MODE_ERROR: /* Disc type stays the same. */ break; case CDIO_DISC_MODE_CD_DA: case CDIO_DISC_MODE_CD_XA: cd->disc_mode = CDIO_DISC_MODE_CD_MIXED; break; default: cd->disc_mode = CDIO_DISC_MODE_ERROR; } } } else if (0 == strcmp ("MODE1_RAW", psz_field)) { if (NULL != cd) { cd->tocent[i].track_format = TRACK_FORMAT_DATA; cd->tocent[i].blocksize = CDIO_CD_FRAMESIZE_RAW; cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE; cd->tocent[i].datasize = CDIO_CD_FRAMESIZE; cd->tocent[i].endsize = CDIO_CD_EDC_SIZE + CDIO_CD_M1F1_ZERO_SIZE + CDIO_CD_ECC_SIZE; switch(cd->disc_mode) { case CDIO_DISC_MODE_NO_INFO: cd->disc_mode = CDIO_DISC_MODE_CD_DATA; break; case CDIO_DISC_MODE_CD_DATA: case CDIO_DISC_MODE_CD_MIXED: case CDIO_DISC_MODE_ERROR: /* Disc type stays the same. */ break; case CDIO_DISC_MODE_CD_DA: case CDIO_DISC_MODE_CD_XA: cd->disc_mode = CDIO_DISC_MODE_CD_MIXED; break; default: cd->disc_mode = CDIO_DISC_MODE_ERROR; } } } else if (0 == strcmp ("MODE2", psz_field)) { if (NULL != cd) { cd->tocent[i].track_format = TRACK_FORMAT_XA; cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE; cd->tocent[i].datasize = M2RAW_SECTOR_SIZE; cd->tocent[i].endsize = 0; switch(cd->disc_mode) { case CDIO_DISC_MODE_NO_INFO: cd->disc_mode = CDIO_DISC_MODE_CD_XA; break; case CDIO_DISC_MODE_CD_XA: case CDIO_DISC_MODE_CD_MIXED: case CDIO_DISC_MODE_ERROR: /* Disc type stays the same. */ break; case CDIO_DISC_MODE_CD_DA: case CDIO_DISC_MODE_CD_DATA: cd->disc_mode = CDIO_DISC_MODE_CD_MIXED; break; default: cd->disc_mode = CDIO_DISC_MODE_ERROR; } } } else if (0 == strcmp ("MODE2_FORM1", psz_field)) { if (NULL != cd) { cd->tocent[i].track_format = TRACK_FORMAT_XA; cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE; cd->tocent[i].datasize = CDIO_CD_FRAMESIZE_RAW; cd->tocent[i].endsize = 0; switch(cd->disc_mode) { case CDIO_DISC_MODE_NO_INFO: cd->disc_mode = CDIO_DISC_MODE_CD_XA; break; case CDIO_DISC_MODE_CD_XA: case CDIO_DISC_MODE_CD_MIXED: case CDIO_DISC_MODE_ERROR: /* Disc type stays the same. */ break; case CDIO_DISC_MODE_CD_DA: case CDIO_DISC_MODE_CD_DATA: cd->disc_mode = CDIO_DISC_MODE_CD_MIXED; break; default: cd->disc_mode = CDIO_DISC_MODE_ERROR; } } } else if (0 == strcmp ("MODE2_FORM2", psz_field)) { if (NULL != cd) { cd->tocent[i].track_format = TRACK_FORMAT_XA; cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE; cd->tocent[i].datasize = CDIO_CD_FRAMESIZE; cd->tocent[i].endsize = CDIO_CD_SYNC_SIZE + CDIO_CD_ECC_SIZE; switch(cd->disc_mode) { case CDIO_DISC_MODE_NO_INFO: cd->disc_mode = CDIO_DISC_MODE_CD_XA; break; case CDIO_DISC_MODE_CD_XA: case CDIO_DISC_MODE_CD_MIXED: case CDIO_DISC_MODE_ERROR: /* Disc type stays the same. */ break; case CDIO_DISC_MODE_CD_DA: case CDIO_DISC_MODE_CD_DATA: cd->disc_mode = CDIO_DISC_MODE_CD_MIXED; break; default: cd->disc_mode = CDIO_DISC_MODE_ERROR; } } } else if (0 == strcmp ("MODE2_FORM_MIX", psz_field)) { if (NULL != cd) { cd->tocent[i].track_format = TRACK_FORMAT_XA; cd->tocent[i].datasize = M2RAW_SECTOR_SIZE; cd->tocent[i].blocksize = CDIO_CD_FRAMESIZE_RAW; cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE; cd->tocent[i].track_green = true; cd->tocent[i].endsize = 0; switch(cd->disc_mode) { case CDIO_DISC_MODE_NO_INFO: cd->disc_mode = CDIO_DISC_MODE_CD_XA; break; case CDIO_DISC_MODE_CD_XA: case CDIO_DISC_MODE_CD_MIXED: case CDIO_DISC_MODE_ERROR: /* Disc type stays the same. */ break; case CDIO_DISC_MODE_CD_DA: case CDIO_DISC_MODE_CD_DATA: cd->disc_mode = CDIO_DISC_MODE_CD_MIXED; break; default: cd->disc_mode = CDIO_DISC_MODE_ERROR; } } } else if (0 == strcmp ("MODE2_RAW", psz_field)) { if (NULL != cd) { cd->tocent[i].track_format = TRACK_FORMAT_XA; cd->tocent[i].blocksize = CDIO_CD_FRAMESIZE_RAW; cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE; cd->tocent[i].datasize = CDIO_CD_FRAMESIZE; cd->tocent[i].track_green = true; cd->tocent[i].endsize = 0; switch(cd->disc_mode) { case CDIO_DISC_MODE_NO_INFO: cd->disc_mode = CDIO_DISC_MODE_CD_XA; break; case CDIO_DISC_MODE_CD_XA: case CDIO_DISC_MODE_CD_MIXED: case CDIO_DISC_MODE_ERROR: /* Disc type stays the same. */ break; case CDIO_DISC_MODE_CD_DA: case CDIO_DISC_MODE_CD_DATA: cd->disc_mode = CDIO_DISC_MODE_CD_MIXED; break; default: cd->disc_mode = CDIO_DISC_MODE_ERROR; } } } else { cdio_log(log_level, "%s line %d after TRACK:", psz_cue_name, i_line); cdio_log(log_level, "'%s' not a valid mode.", psz_field); goto err_exit; } } if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) { /* \todo: set sub-channel-mode */ #ifdef TODO if (0 == strcmp ("RW", psz_field)) ; else if (0 == strcmp ("RW_RAW", psz_field)) ; #endif } if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) { goto format_error; } /* track flags */ /* [NO] COPY | [NO] PRE_EMPHASIS */ } else if (0 == strcmp ("NO", psz_keyword)) { if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) { if (0 == strcmp ("COPY", psz_field)) { if (NULL != cd) cd->tocent[i].flags &= ~CDIO_TRACK_FLAG_COPY_PERMITTED; } else if (0 == strcmp ("PRE_EMPHASIS", psz_field)) if (NULL != cd) { cd->tocent[i].flags &= ~CDIO_TRACK_FLAG_PRE_EMPHASIS; } } else { goto format_error; } if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) { goto format_error; } } else if (0 == strcmp ("COPY", psz_keyword)) { if (NULL != cd && i >= 0) cd->tocent[i].flags |= CDIO_TRACK_FLAG_COPY_PERMITTED; } else if (0 == strcmp ("PRE_EMPHASIS", psz_keyword)) { if (NULL != cd && i >= 0) cd->tocent[i].flags |= CDIO_TRACK_FLAG_PRE_EMPHASIS; /* TWO_CHANNEL_AUDIO */ } else if (0 == strcmp ("TWO_CHANNEL_AUDIO", psz_keyword)) { if (NULL != cd && i >= 0) cd->tocent[i].flags &= ~CDIO_TRACK_FLAG_FOUR_CHANNEL_AUDIO; /* FOUR_CHANNEL_AUDIO */ } else if (0 == strcmp ("FOUR_CHANNEL_AUDIO", psz_keyword)) { if (NULL != cd && i >= 0) cd->tocent[i].flags |= CDIO_TRACK_FLAG_FOUR_CHANNEL_AUDIO; /* ISRC "CCOOOYYSSSSS" */ } else if (0 == strcmp ("ISRC", psz_keyword)) { if (NULL != (psz_field = strtok (NULL, "\"\t\n\r"))) { if (NULL != cd) cd->tocent[i].isrc = strdup(psz_field); } else { goto format_error; } /* SILENCE <length> */ } else if (0 == strcmp ("SILENCE", psz_keyword)) { if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) { if (NULL != cd) cd->tocent[i].silence = cdio_mmssff_to_lba (psz_field); } else { goto format_error; } cdio_log(log_level, "%s line %d: SILENCE not fully implimented", psz_cue_name, i_line); /* ZERO <length> */ } else if (0 == strcmp ("ZERO", psz_keyword)) { UNIMPLIMENTED_MSG; /* [FILE|AUDIOFILE] "<filename>" <start-msf> [<length-msf>] */ } else if (0 == strcmp ("FILE", psz_keyword) || 0 == strcmp ("AUDIOFILE", psz_keyword)) { if (0 <= i) { if (NULL != (psz_field = strtok (NULL, "\"\t\n\r"))) { /* Handle "<filename>" */ if (cd) { char *psz_dirname = cdio_dirname(psz_cue_name); char *psz_filename = cdio_abspath(psz_dirname, psz_field); cd->tocent[i].filename = strdup (psz_filename); free(psz_filename); free(psz_dirname); /* To do: do something about reusing existing files. */ if (!(cd->tocent[i].data_source = cdio_stdio_new (psz_field))) { cdio_log (log_level, "%s line %d: can't open file `%s' for reading", psz_cue_name, i_line, psz_field); goto err_exit; } } else { CdioDataSource_t *s = cdio_stdio_new (psz_field); if (!s) { cdio_log (log_level, "%s line %d: can't open file `%s' for reading", psz_cue_name, i_line, psz_field); goto err_exit; } cdio_stdio_destroy (s); } } if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) { /* Handle <start-msf> */ lba_t i_start_lba = cdio_lsn_to_lba(cdio_mmssff_to_lba (psz_field)); if (CDIO_INVALID_LBA == i_start_lba) { cdio_log(log_level, "%s line %d: invalid MSF string %s", psz_cue_name, i_line, psz_field); goto err_exit; } if (NULL != cd) { cd->tocent[i].start_lba = i_start_lba; cdio_lba_to_msf(i_start_lba, &(cd->tocent[i].start_msf)); } } if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) { /* Handle <length-msf> */ lba_t lba = cdio_mmssff_to_lba (psz_field); if (CDIO_INVALID_LBA == lba) { cdio_log(log_level, "%s line %d: invalid MSF string %s", psz_cue_name, i_line, psz_field); goto err_exit; } if (cd) { off_t i_size = cdio_stream_stat(cd->tocent[i].data_source); if (lba) { if ( (lba * cd->tocent[i].datasize) > i_size) { cdio_log(log_level, "%s line %d: MSF length %s exceeds end of file", psz_cue_name, i_line, psz_field); goto err_exit; } } else { lba = (lba_t) (i_size / cd->tocent[i].blocksize); } cd->tocent[i].sec_count = lba; } } if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) { goto format_error; } } else { goto not_in_global_section; } /* DATAFILE "<filename>" #byte-offset <start-msf> */ } else if (0 == strcmp ("DATAFILE", psz_keyword)) { if (0 <= i) { if (NULL != (psz_field = strtok (NULL, "\"\t\n\r"))) { /* Handle <filename> */ char *psz_dirname = cdio_dirname(psz_cue_name); char *psz_filename = cdio_abspath(psz_dirname, psz_field); if (cd) { cd->tocent[i].filename = strdup(psz_filename); /* To do: do something about reusing existing files. */ if (!(cd->tocent[i].data_source = cdio_stdio_new (psz_field))) { cdio_log (log_level, "%s line %d: can't open file `%s' for reading", psz_cue_name, i_line, psz_field); free(psz_filename); free(psz_dirname); goto err_exit; } } else { CdioDataSource_t *s = cdio_stdio_new (psz_filename); if (!s) { cdio_log (log_level, "%s line %d: can't open file `%s' for reading", psz_cue_name, i_line, psz_field); free(psz_filename); free(psz_dirname); goto err_exit; } cdio_stdio_destroy (s); } free(psz_filename); free(psz_dirname); } psz_field = strtok (NULL, " \t\n\r"); if (psz_field) { /* Handle optional #byte-offset */ if ( psz_field[0] == '#') { long int offset; psz_field++; errno = 0; offset = strtol(psz_field, (char **)NULL, 10); if ( (LONG_MIN == offset || LONG_MAX == offset) && 0 != errno ) { cdio_log (log_level, "%s line %d: can't convert `%s' to byte offset", psz_cue_name, i_line, psz_field); goto err_exit; } else { if (NULL != cd) { cd->tocent[i].offset = offset; } } psz_field = strtok (NULL, " \t\n\r"); } } if (psz_field) { /* Handle start-msf */ lba_t lba = cdio_mmssff_to_lba (psz_field); if (CDIO_INVALID_LBA == lba) { cdio_log(log_level, "%s line %d: invalid MSF string %s", psz_cue_name, i_line, psz_field); goto err_exit; } if (cd) { cd->tocent[i].start_lba = lba; cdio_lba_to_msf(cd->tocent[i].start_lba, &(cd->tocent[i].start_msf)); } } else { /* No start-msf. */ if (cd) { if (i) { uint16_t i_blocksize = cd->tocent[i-1].blocksize; off_t i_size = cdio_stream_stat(cd->tocent[i-1].data_source); check_track_is_blocksize_multiple(cd->tocent[i-1].filename, i-1, i_size, i_blocksize); /* Append size of previous datafile. */ cd->tocent[i].start_lba = (lba_t) (cd->tocent[i-1].start_lba + (i_size / i_blocksize)); } cd->tocent[i].offset = 0; cd->tocent[i].start_lba += CDIO_PREGAP_SECTORS; cdio_lba_to_msf(cd->tocent[i].start_lba, &(cd->tocent[i].start_msf)); } } } else { goto not_in_global_section; } /* FIFO "<fifo path>" [<length>] */ } else if (0 == strcmp ("FIFO", psz_keyword)) { goto unimplimented_error; /* START MM:SS:FF */ } else if (0 == strcmp ("START", psz_keyword)) { if (0 <= i) { if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) { /* todo: line is too long! */ if (NULL != cd) { cd->tocent[i].pregap = cd->tocent[i].start_lba; cd->tocent[i].start_lba += cdio_mmssff_to_lba (psz_field); cdio_lba_to_msf(cd->tocent[i].start_lba, &(cd->tocent[i].start_msf)); } } if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) { goto format_error; } } else { goto not_in_global_section; } /* PREGAP MM:SS:FF */ } else if (0 == strcmp ("PREGAP", psz_keyword)) { if (0 <= i) { if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) { if (NULL != cd) cd->tocent[i].pregap = cdio_mmssff_to_lba (psz_field); } else { goto format_error; } if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) { goto format_error; } } else { goto not_in_global_section; } /* INDEX MM:SS:FF */ } else if (0 == strcmp ("INDEX", psz_keyword)) { if (0 <= i) { if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) { if (NULL != cd) { #if 0 if (1 == cd->tocent[i].nindex) { cd->tocent[i].indexes[1] = cd->tocent[i].indexes[0]; cd->tocent[i].nindex++; } cd->tocent[i].indexes[cd->tocent[i].nindex++] = cdio_mmssff_to_lba (psz_field) + cd->tocent[i].indexes[0]; #else ; #endif } } else { goto format_error; } if (NULL != strtok (NULL, " \t\n\r")) { goto format_error; } } else { goto not_in_global_section; } /* CD_TEXT { ... } */ /* todo: opening { must be on same line as CD_TEXT */ } else if (0 == strcmp ("CD_TEXT", psz_keyword)) { if (NULL == (psz_field = strtok (NULL, " \t\n\r"))) { goto format_error; } if ( 0 == strcmp( "{", psz_field ) ) { i_cdtext_nest++; } else { cdio_log (log_level, "%s line %d: expecting '{'", psz_cue_name, i_line); goto err_exit; } // TODO: implement language mapping } else if (0 == strcmp ("LANGUAGE_MAP", psz_keyword)) { /* LANGUAGE d { ... } */ } else if (0 == strcmp ("LANGUAGE", psz_keyword)) { /* Language number */ if (NULL == (psz_field = strtok (NULL, " \t\n\r"))) { goto format_error; } if ( 0 == strcmp( "{", psz_field ) ) { i_cdtext_nest++; } } else if (0 == strcmp ("{", psz_keyword)) { i_cdtext_nest++; } else if (0 == strcmp ("}", psz_keyword)) { if (i_cdtext_nest > 0) i_cdtext_nest--; } else if ( CDTEXT_FIELD_INVALID != (cdtext_key = cdtext_is_field (psz_keyword)) ) { if (NULL != cd) { if (NULL == cd->gen.cdtext) { cd->gen.cdtext = cdtext_init (); /* until language mapping is implemented ...*/ cd->gen.cdtext->block[cd->gen.cdtext->block_i].language_code = CDTEXT_LANGUAGE_ENGLISH; } cdtext_set (cd->gen.cdtext, cdtext_key, (uint8_t*) strtok (NULL, "\"\t\n\r"), (-1 == i ? 0 : cd->gen.i_first_track + i), "ISO-8859-1"); } /* unrecognized line */ } else { cdio_log(log_level, "%s line %d: warning: unrecognized word: %s", psz_cue_name, i_line, psz_keyword); goto err_exit; } } } if (NULL != cd) { cd->gen.i_tracks = i+1; cd->gen.toc_init = true; } fclose (fp); return true; unimplimented_error: UNIMPLIMENTED_MSG; goto err_exit; format_error: cdio_log(log_level, "%s line %d after word %s", psz_cue_name, i_line, psz_keyword); goto err_exit; not_in_global_section: cdio_log(log_level, "%s line %d: word %s only allowed in global section", psz_cue_name, i_line, psz_keyword); err_exit: fclose (fp); return false; }