📄 cdrdao.c
字号:
/* $Id: cdrdao.c,v 1.1 2005/01/01 02:43:58 rockyb Exp $ Copyright (C) 2004 Rocky Bernstein <rocky@panix.com> toc reading routine adapted from cuetools Copyright (C) 2003 Svend Sanjay Sorensen <ssorensen@fastmail.fm> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*//* This code implements low-level access functions for a CD images residing inside a disk file (*.bin) and its associated cue sheet. (*.cue).*/static const char _rcsid[] = "$Id: cdrdao.c,v 1.1 2005/01/01 02:43:58 rockyb Exp $";#include "image.h"#include "cdio_assert.h"#include "_cdio_stdio.h"#include <cdio/logging.h>#include <cdio/sector.h>#include <cdio/util.h>#include <cdio/version.h>#ifdef HAVE_STDIO_H#include <stdio.h>#endif#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#ifdef HAVE_STRING_H#include <string.h>#endif#ifdef HAVE_STRINGS_H#include <strings.h>#endif#ifdef HAVE_GLOB_H#include <glob.h>#endif#ifdef HAVE_ERRNO_H#include <errno.h>#endif#include <ctype.h>#include "portable.h"/* reader */#define DEFAULT_CDIO_DEVICE "videocd.bin"#define DEFAULT_CDIO_CDRDAO "videocd.toc"typedef struct { /* Things common to all drivers like this. This must be first. */ generic_img_private_t gen; internal_position_t pos; char *psz_cue_name; char *psz_mcn; /* Media Catalog Number (5.22.3) exactly 13 bytes */ track_info_t tocent[CDIO_CD_MAX_TRACKS+1]; /* entry info for each track add 1 for leadout. */ discmode_t disc_mode;} _img_private_t;static uint32_t _stat_size_cdrdao (void *user_data);static bool parse_tocfile (_img_private_t *cd, const char *toc_name);#define NEED_MEDIA_EJECT_IMAGE#include "image_common.h"/*! Initialize image structures. */static bool_init_cdrdao (_img_private_t *env){ lsn_t lead_lsn; if (env->gen.init) return false; /* Have to set init before calling _stat_size_cdrdao() or we will get into infinite recursion calling passing right here. */ env->gen.init = true; env->gen.i_first_track = 1; env->psz_mcn = NULL; env->disc_mode = CDIO_DISC_MODE_NO_INFO; cdtext_init (&(env->gen.cdtext)); /* Read in TOC sheet. */ if ( !parse_tocfile(env, env->psz_cue_name) ) return false; lead_lsn = _stat_size_cdrdao( (_img_private_t *) env); if (-1 == lead_lsn) return false; /* Fake out leadout track and sector count for last track*/ cdio_lsn_to_msf (lead_lsn, &env->tocent[env->gen.i_tracks].start_msf); env->tocent[env->gen.i_tracks].start_lba = cdio_lsn_to_lba(lead_lsn); env->tocent[env->gen.i_tracks-env->gen.i_first_track].sec_count = cdio_lsn_to_lba(lead_lsn - env->tocent[env->gen.i_tracks-1].start_lba); return true;}/*! Reads into buf the next size bytes. Returns -1 on error. Would be libc's seek() but we have to adjust for the extra track header information in each sector.*/static off_t_lseek_cdrdao (void *user_data, off_t offset, int whence){ _img_private_t *env = user_data; /* real_offset is the real byte offset inside the disk image The number below was determined empirically. I'm guessing the 1st 24 bytes of a bin file are used for something. */ off_t real_offset=0; unsigned int i; env->pos.lba = 0; for (i=0; i<env->gen.i_tracks; i++) { track_info_t *this_track=&(env->tocent[i]); env->pos.index = i; if ( (this_track->sec_count*this_track->datasize) >= offset) { int blocks = offset / this_track->datasize; int rem = offset % this_track->datasize; int block_offset = blocks * this_track->blocksize; real_offset += block_offset + rem; env->pos.buff_offset = rem; env->pos.lba += blocks; break; } real_offset += this_track->sec_count*this_track->blocksize; offset -= this_track->sec_count*this_track->datasize; env->pos.lba += this_track->sec_count; } if (i==env->gen.i_tracks) { cdio_warn ("seeking outside range of disk image"); return -1; } else { real_offset += env->tocent[i].datastart; return cdio_stream_seek(env->tocent[i].data_source, real_offset, whence); }}/*! Reads into buf the next size bytes. Returns -1 on error. FIXME: At present we assume a read doesn't cross sector or track boundaries.*/static ssize_t_read_cdrdao (void *user_data, void *data, size_t size){ _img_private_t *env = user_data; char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; char *p = data; ssize_t final_size=0; ssize_t this_size; track_info_t *this_track=&(env->tocent[env->pos.index]); ssize_t skip_size = this_track->datastart + this_track->endsize; while (size > 0) { int rem = this_track->datasize - env->pos.buff_offset; if (size <= rem) { this_size = cdio_stream_read(this_track->data_source, buf, size, 1); final_size += this_size; memcpy (p, buf, this_size); break; } /* Finish off reading this sector. */ cdio_warn ("Reading across block boundaries not finished"); size -= rem; this_size = cdio_stream_read(this_track->data_source, buf, rem, 1); final_size += this_size; memcpy (p, buf, this_size); p += this_size; this_size = cdio_stream_read(this_track->data_source, buf, rem, 1); /* Skip over stuff at end of this sector and the beginning of the next. */ cdio_stream_read(this_track->data_source, buf, skip_size, 1); /* Get ready to read another sector. */ env->pos.buff_offset=0; env->pos.lba++; /* Have gone into next track. */ if (env->pos.lba >= env->tocent[env->pos.index+1].start_lba) { env->pos.index++; this_track=&(env->tocent[env->pos.index]); skip_size = this_track->datastart + this_track->endsize; } } return final_size;}/*! Return the size of the CD in logical block address (LBA) units. */static uint32_t _stat_size_cdrdao (void *user_data){ _img_private_t *env = user_data; long size; size = cdio_stream_stat (env->tocent[0].data_source); if (size % CDIO_CD_FRAMESIZE_RAW) { cdio_warn ("image %s size (%ld) not multiple of blocksize (%d)", env->tocent[0].filename, size, CDIO_CD_FRAMESIZE_RAW); if (size % M2RAW_SECTOR_SIZE == 0) cdio_warn ("this may be a 2336-type disc image"); else if (size % CDIO_CD_FRAMESIZE_RAW == 0) cdio_warn ("this may be a 2352-type disc image"); /* exit (EXIT_FAILURE); */ } size /= CDIO_CD_FRAMESIZE_RAW; return size;}#define MAXLINE 512#define UNIMPLIMENTED_MSG \ cdio_log(log_level, "%s line %d: unimplimented keyword: %s", \ psz_cue_name, i_line, psz_keyword)static boolparse_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; cdio_log_level_t log_level = (NULL == cd) ? CDIO_LOG_INFO : CDIO_LOG_WARN; 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; fp = fopen (psz_cue_name, "r"); 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_init = true; cd->gen.b_cdtext_error = false; } while ((fgets(psz_line, MAXLINE, fp)) != NULL) { i_line++; /* strip comment from line */ /* todo: // in quoted strings? */ /* //comment */ if (NULL != (psz_field = strstr (psz_line, "//"))) *psz_field = '\0'; if (NULL != (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 i; for (i=0; i<13; i++) { if (!isdigit(psz_field[i])) { 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[i], i+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 != cd) cdtext_init (&(cd->gen.cdtext_track[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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -