driver_return_code_t audio_get_volume_win32ioctl (void *p_user_data, /*out*/ cdio_audio_volume_t *p_volume) { const _img_private_t *p_env = p_user_data; DWORD dw_bytes_returned; bool b_success = DeviceIoControl(p_env->h_device_handle, IOCTL_CDROM_GET_VOLUME, NULL, 0, p_volume, (DWORD) sizeof(cdio_audio_volume_t), &dw_bytes_returned, NULL); if ( ! b_success ) { char *psz_msg = NULL; long int i_err = GetLastError(); FORMAT_ERROR(i_err, psz_msg); if (psz_msg) cdio_info("Error: %s", psz_msg); else cdio_info("Error: %ld", i_err); LocalFree(psz_msg); return DRIVER_OP_ERROR; } return DRIVER_OP_SUCCESS; }
/*! Read the Super block of an ISO 9660 image. This is the Primary Volume Descriptor (PVD) and perhaps a Supplemental Volume Descriptor if (Joliet) extensions are acceptable. */ bool iso9660_fs_read_superblock (CdIo_t *p_cdio, iso_extension_mask_t iso_extension_mask) { if (!p_cdio) return false; { generic_img_private_t *p_env = (generic_img_private_t *) p_cdio->env; iso9660_pvd_t *p_pvd = &(p_env->pvd); iso9660_svd_t *p_svd = &(p_env->svd); char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; driver_return_code_t driver_return; if ( !iso9660_fs_read_pvd(p_cdio, p_pvd) ) return false; p_env->i_joliet_level = 0; driver_return = cdio_read_data_sectors ( p_cdio, buf, ISO_PVD_SECTOR+1, ISO_BLOCKSIZE, 1 ); if (DRIVER_OP_SUCCESS == driver_return) { /* The size of a PVD or SVD is smaller than a sector. So we allocated a bigger block above (buf) and now we'll copy just the part we need to save. */ cdio_assert (sizeof(buf) >= sizeof (iso9660_svd_t)); memcpy(p_svd, buf, sizeof(iso9660_svd_t)); if ( ISO_VD_SUPPLEMENTARY == from_711(p_svd->type) ) { if (p_svd->escape_sequences[0] == 0x25 && p_svd->escape_sequences[1] == 0x2f) { switch (p_svd->escape_sequences[2]) { case 0x40: if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL1) p_env->i_joliet_level = 1; break; case 0x43: if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL2) p_env->i_joliet_level = 2; break; case 0x45: if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL3) p_env->i_joliet_level = 3; break; default: cdio_info("Supplementary Volume Descriptor found, but not Joliet"); } if (p_env->i_joliet_level > 0) { cdio_info("Found Extension: Joliet Level %d", p_env->i_joliet_level); } } } } } return true; }
/*! Reads an audio device using the DeviceIoControl method into data starting from lsn. Returns 0 if no error. */ driver_return_code_t read_audio_sectors_win32ioctl (_img_private_t *p_env, void *data, lsn_t lsn, unsigned int nblocks) { DWORD dw_bytes_returned; RAW_READ_INFO cdrom_raw; /* Initialize CDROM_RAW_READ structure */ cdrom_raw.DiskOffset.QuadPart = (long long) CDIO_CD_FRAMESIZE_RAW * lsn; cdrom_raw.SectorCount = nblocks; cdrom_raw.TrackMode = CDDA; if( DeviceIoControl( p_env->h_device_handle, IOCTL_CDROM_RAW_READ, &cdrom_raw, sizeof(RAW_READ_INFO), data, CDIO_CD_FRAMESIZE_RAW * nblocks, &dw_bytes_returned, NULL ) == 0 ) { char *psz_msg = NULL; long int i_err = GetLastError(); FORMAT_ERROR(i_err, psz_msg); if (psz_msg) { cdio_info("Error reading audio-mode lsn %lu\n%s (%ld))", (long unsigned int) lsn, psz_msg, i_err); } else { cdio_info("Error reading audio-mode lsn %lu\n (%ld))", (long unsigned int) lsn, i_err); } LocalFree(psz_msg); return DRIVER_OP_ERROR; } return DRIVER_OP_SUCCESS; }
/*! Playing starting at given MSF through analog output @param p_cdio the CD object to be acted upon. */ driver_return_code_t audio_play_msf_win32ioctl (void *p_user_data, msf_t *p_start_msf, msf_t *p_end_msf) { const _img_private_t *p_env = p_user_data; CDROM_PLAY_AUDIO_MSF play; DWORD dw_bytes_returned; play.StartingM = cdio_from_bcd8(p_start_msf->m); play.StartingS = cdio_from_bcd8(p_start_msf->s); play.StartingF = cdio_from_bcd8(p_start_msf->f); play.EndingM = cdio_from_bcd8(p_end_msf->m); play.EndingS = cdio_from_bcd8(p_end_msf->s); play.EndingF = cdio_from_bcd8(p_end_msf->f); bool b_success = DeviceIoControl(p_env->h_device_handle, IOCTL_CDROM_PLAY_AUDIO_MSF, &play, sizeof(play), NULL, 0, &dw_bytes_returned, NULL); if ( ! b_success ) { char *psz_msg = NULL; long int i_err = GetLastError(); FORMAT_ERROR(i_err, psz_msg); if (psz_msg) cdio_info("Error: %s", psz_msg); else cdio_info("Error: %ld", i_err); LocalFree(psz_msg); return DRIVER_OP_ERROR; } return DRIVER_OP_SUCCESS; }
/*! Read Audio Subchannel information @param p_cdio the CD object to be acted upon. */ driver_return_code_t audio_read_subchannel_win32ioctl (void *p_user_data, cdio_subchannel_t *p_subchannel) { const _img_private_t *p_env = p_user_data; DWORD dw_bytes_returned; CDROM_SUB_Q_DATA_FORMAT q_data_format; SUB_Q_CHANNEL_DATA q_subchannel_data; q_data_format.Format = CDIO_SUBCHANNEL_CURRENT_POSITION; q_data_format.Track=0; /* Not sure if this has to be set or if so what it should be. */ if( ! DeviceIoControl( p_env->h_device_handle, IOCTL_CDROM_READ_Q_CHANNEL, &q_data_format, sizeof(q_data_format), &q_subchannel_data, sizeof(q_subchannel_data), &dw_bytes_returned, NULL ) ) { char *psz_msg = NULL; long int i_err = GetLastError(); FORMAT_ERROR(i_err, psz_msg); if (psz_msg) cdio_info("Error: %s", psz_msg); else cdio_info("Error: %ld", i_err); LocalFree(psz_msg); return DRIVER_OP_ERROR; } p_subchannel->audio_status = q_subchannel_data.CurrentPosition.Header.AudioStatus; p_subchannel->track = q_subchannel_data.CurrentPosition.TrackNumber; p_subchannel->index = q_subchannel_data.CurrentPosition.IndexNumber; p_subchannel->index = q_subchannel_data.CurrentPosition.IndexNumber; p_subchannel->address = q_subchannel_data.CurrentPosition.ADR; p_subchannel->control = q_subchannel_data.CurrentPosition.Control; { const UCHAR *abs_addr = q_subchannel_data.CurrentPosition.AbsoluteAddress; const UCHAR *rel_addr = q_subchannel_data.CurrentPosition.TrackRelativeAddress; p_subchannel->abs_addr.m = cdio_to_bcd8(abs_addr[1]); p_subchannel->abs_addr.s = cdio_to_bcd8(abs_addr[2]); p_subchannel->abs_addr.f = cdio_to_bcd8(abs_addr[3]); p_subchannel->rel_addr.m = cdio_to_bcd8(rel_addr[1]); p_subchannel->rel_addr.s = cdio_to_bcd8(rel_addr[2]); p_subchannel->rel_addr.f = cdio_to_bcd8(rel_addr[3]); } return DRIVER_OP_SUCCESS; }
static bool ucs2be_to_locale(ICONV_CONST char *psz_ucs2be, size_t i_inlen, char **p_psz_out, size_t i_outlen) { iconv_t ic = #if defined(HAVE_LANGINFO_CODESET) iconv_open(nl_langinfo(CODESET), "UCS-2BE"); #else iconv_open("ASCII", "UCS-2BE"); #endif int rc; char *psz_buf = NULL; char *psz_buf2; int i_outlen_max = i_outlen; int i_outlen_actual; if (-1 == (size_t) ic) { #if defined(HAVE_LANGINFO_CODESET) cdio_info("Failed to get conversion table for locale, trying ASCII"); ic = iconv_open("ASCII", "UCS-2BE"); if (-1 == (size_t) ic) { cdio_info("Failed to get conversion table for ASCII too"); return false; } #else cdio_info("Failed to get conversion table for locale"); return false; #endif } psz_buf = (char *) realloc(psz_buf, i_outlen); psz_buf2 = psz_buf; if (!psz_buf) { /* XXX: report out of memory error */ goto error; } rc = iconv(ic, &psz_ucs2be, &i_inlen, &psz_buf2, &i_outlen); iconv_close(ic); if ((rc == -1) && (errno != E2BIG)) { /* conversion failed */ goto error; } i_outlen_actual = i_outlen_max - i_outlen; *p_psz_out = malloc(i_outlen_actual + 1); memcpy(*p_psz_out, psz_buf, i_outlen_actual); *(*p_psz_out + i_outlen_actual) = '\0'; free(psz_buf); return true; error: free(psz_buf); *p_psz_out = NULL; return false; }
/*! Close the tray of a CD-ROM @param p_user_data the CD object to be acted upon. */ driver_return_code_t close_tray_win32ioctl (const char *psz_win32_drive) { #ifdef WIN32 DWORD dw_bytes_returned; DWORD dw_access_flags; OSVERSIONINFO ov; HANDLE h_device_handle; bool b_success; memset(&ov,0,sizeof(OSVERSIONINFO)); ov.dwOSVersionInfoSize=sizeof(OSVERSIONINFO); GetVersionEx(&ov); if((ov.dwPlatformId==VER_PLATFORM_WIN32_NT) && (ov.dwMajorVersion>4)) dw_access_flags = GENERIC_READ|GENERIC_WRITE; /* add gen write on W2k/XP */ else dw_access_flags = GENERIC_READ; h_device_handle = CreateFile( psz_win32_drive, dw_access_flags, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if( h_device_handle == INVALID_HANDLE_VALUE ) { return DRIVER_OP_ERROR; } b_success = DeviceIoControl(h_device_handle, IOCTL_STORAGE_LOAD_MEDIA2, NULL, (DWORD) 0, NULL, 0, &dw_bytes_returned, NULL); CloseHandle(h_device_handle); if ( ! b_success ) { char *psz_msg = NULL; long int i_err = GetLastError(); FORMAT_ERROR(i_err, psz_msg); if (psz_msg) cdio_info("Error: %s", psz_msg); else cdio_info("Error: %ld", i_err); LocalFree(psz_msg); return DRIVER_OP_ERROR; } return DRIVER_OP_SUCCESS; #else return DRIVER_OP_UNSUPPORTED; #endif }
/*! Run a SCSI MMC command. env private CD structure i_timeout time in milliseconds we will wait for the command to complete. If this value is -1, use the default time-out value. p_buf Buffer for data, both sending and receiving i_buf Size of buffer e_direction direction the transfer is to go. cdb CDB bytes. All values that are needed should be set on input. We'll figure out what the right CDB length should be. Return 0 if command completed successfully. */ int run_mmc_cmd_win32ioctl( void *p_user_data, unsigned int i_timeout_ms, unsigned int i_cdb, const mmc_cdb_t * p_cdb, cdio_mmc_direction_t e_direction, unsigned int i_buf, /*in/out*/ void *p_buf ) { const _img_private_t *p_env = p_user_data; SCSI_PASS_THROUGH_DIRECT sptd; bool b_success; DWORD dw_bytes_returned; sptd.Length = sizeof(sptd); sptd.PathId = 0; /* SCSI card ID will be filled in automatically */ sptd.TargetId= 0; /* SCSI target ID will also be filled in */ sptd.Lun=0; /* SCSI lun ID will also be filled in */ sptd.CdbLength = i_cdb; sptd.SenseInfoLength = 0; /* Don't return any sense data */ sptd.DataIn = SCSI_MMC_DATA_READ == e_direction ? SCSI_IOCTL_DATA_IN : SCSI_IOCTL_DATA_OUT; sptd.DataTransferLength= i_buf; sptd.TimeOutValue = msecs2secs(i_timeout_ms); sptd.DataBuffer = (void *) p_buf; sptd.SenseInfoOffset = 0; memcpy(sptd.Cdb, p_cdb, i_cdb); /* Send the command to drive */ b_success = DeviceIoControl(p_env->h_device_handle, IOCTL_SCSI_PASS_THROUGH_DIRECT, (void *)&sptd, (DWORD)sizeof(SCSI_PASS_THROUGH_DIRECT), NULL, 0, &dw_bytes_returned, NULL); if ( !b_success ) { char *psz_msg = NULL; long int i_err = GetLastError(); FORMAT_ERROR(i_err, psz_msg); if (psz_msg) cdio_info("Error: %s", psz_msg); else cdio_info("Error: %ld", i_err); LocalFree(psz_msg); return DRIVER_OP_ERROR; } return DRIVER_OP_SUCCESS; }
/*! Run a SCSI MMC command. p_user_data internal CD structure. i_timeout_ms time in milliseconds we will wait for the command to complete. If this value is -1, use the default time-out value. i_cdb Size of p_cdb p_cdb CDB bytes. e_direction direction the transfer is to go. i_buf Size of buffer p_buf Buffer for data, both sending and receiving */ static driver_return_code_t run_mmc_cmd_freebsd( void *p_user_data, unsigned int i_timeout_ms, unsigned int i_cdb, const mmc_cdb_t *p_cdb, cdio_mmc_direction_t e_direction, unsigned int i_buf, /*in/out*/ void *p_buf ) { const _img_private_t *p_env = p_user_data; int ret; switch (p_env->access_mode) { case _AM_CAM: case _AM_MMC_RDWR: case _AM_MMC_RDWR_EXCL: ret = run_mmc_cmd_freebsd_cam( p_user_data, i_timeout_ms, i_cdb, p_cdb, e_direction, i_buf, p_buf ); if (ret != 0) return DRIVER_OP_ERROR; return 0; case _AM_IOCTL: return DRIVER_OP_UNSUPPORTED; case _AM_NONE: cdio_info ("access mode not set"); return DRIVER_OP_ERROR; } return DRIVER_OP_ERROR; }
/*! Read the Super block of an ISO 9660 image. This is the Primary Volume Descriptor (PVD) and perhaps a Supplemental Volume Descriptor if (Joliet) extensions are acceptable. */ bool iso9660_ifs_read_superblock (iso9660_t *p_iso, iso_extension_mask_t iso_extension_mask) { iso9660_svd_t p_svd; /* Secondary volume descriptor. */ int i; if (!p_iso || !iso9660_ifs_read_pvd(p_iso, &(p_iso->pvd))) return false; p_iso->u_joliet_level = 0; /* There may be multiple Secondary Volume Descriptors (eg. El Torito + Joliet) */ for (i=1; (0 != iso9660_iso_seek_read (p_iso, &p_svd, ISO_PVD_SECTOR+i, 1)); i++) { if (ISO_VD_END == from_711(p_svd.type) ) /* Last SVD */ break; if ( ISO_VD_SUPPLEMENTARY == from_711(p_svd.type) ) { /* We're only interested in Joliet => make sure the SVD isn't overwritten */ if (p_iso->u_joliet_level == 0) memcpy(&(p_iso->svd), &p_svd, sizeof(iso9660_svd_t)); if (p_svd.escape_sequences[0] == 0x25 && p_svd.escape_sequences[1] == 0x2f) { switch (p_svd.escape_sequences[2]) { case 0x40: if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL1) p_iso->u_joliet_level = 1; break; case 0x43: if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL2) p_iso->u_joliet_level = 2; break; case 0x45: if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL3) p_iso->u_joliet_level = 3; break; default: cdio_info("Supplementary Volume Descriptor found, but not Joliet"); } if (p_iso->u_joliet_level > 0) { cdio_info("Found Extension: Joliet Level %d", p_iso->u_joliet_level); } } } } return true; }
static bool check_track_is_blocksize_multiple(const char *psz_fname, track_t i_track, long i_size, uint16_t i_blocksize) { if (i_size % i_blocksize) { cdio_info ("image %s track %d size (%ld) not a multiple" " of the blocksize (%ld)", psz_fname, i_track, i_size, (long int) i_blocksize); if (i_size % M2RAW_SECTOR_SIZE == 0) cdio_info ("this may be a 2336-type disc image"); else if (i_size % CDIO_CD_FRAMESIZE_RAW == 0) cdio_info ("this may be a 2352-type disc image"); return false; } return true; }
/*! Read the Super block of an ISO 9660 image. This is the Primary Volume Descriptor (PVD) and perhaps a Supplemental Volume Descriptor if (Joliet) extensions are acceptable. */ bool iso9660_ifs_read_superblock (iso9660_t *p_iso, iso_extension_mask_t iso_extension_mask) { iso9660_svd_t *p_svd; /* Secondary volume descriptor. */ if (!p_iso || !iso9660_ifs_read_pvd(p_iso, &(p_iso->pvd))) return false; p_svd = &(p_iso->svd); p_iso->i_joliet_level = 0; if (0 != iso9660_iso_seek_read (p_iso, p_svd, ISO_PVD_SECTOR+1, 1)) { if ( ISO_VD_SUPPLEMENTARY == from_711(p_svd->type) ) { if (p_svd->escape_sequences[0] == 0x25 && p_svd->escape_sequences[1] == 0x2f) { switch (p_svd->escape_sequences[2]) { case 0x40: if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL1) p_iso->i_joliet_level = 1; break; case 0x43: if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL2) p_iso->i_joliet_level = 2; break; case 0x45: if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL3) p_iso->i_joliet_level = 3; break; default: cdio_info("Supplementary Volume Descriptor found, but not Joliet"); } if (p_iso->i_joliet_level > 0) { cdio_info("Found Extension: Joliet Level %d", p_iso->i_joliet_level); } } } } return true; }
static void get_drive_cap_freebsd (const void *p_user_data, cdio_drive_read_cap_t *p_read_cap, cdio_drive_write_cap_t *p_write_cap, cdio_drive_misc_cap_t *p_misc_cap) { const _img_private_t *p_env = p_user_data; switch (p_env->access_mode) { case _AM_CAM: case _AM_MMC_RDWR: case _AM_MMC_RDWR_EXCL: get_drive_cap_mmc (p_user_data, p_read_cap, p_write_cap, p_misc_cap); case _AM_IOCTL: cdio_info ("get_drive_cap not supported in ioctl access mode"); return; case _AM_NONE: cdio_info ("access mode not set"); return; } }
/*! Stop playing an audio CD. @param p_user_data the CD object to be acted upon. */ driver_return_code_t audio_stop_win32ioctl (void *p_user_data) { const _img_private_t *p_env = p_user_data; DWORD dw_bytes_returned; bool b_success = DeviceIoControl(p_env->h_device_handle, IOCTL_CDROM_STOP_AUDIO, NULL, (DWORD) 0, NULL, 0, &dw_bytes_returned, NULL); if ( ! b_success ) { char *psz_msg = NULL; long int i_err = GetLastError(); FORMAT_ERROR(i_err, psz_msg); if (psz_msg) cdio_info("Error: %s", psz_msg); else cdio_info("Error: %ld", i_err); LocalFree(psz_msg); return DRIVER_OP_ERROR; } return DRIVER_OP_SUCCESS; }
/*! Return the media catalog number MCN. Note: string is malloc'd so caller should free() then returned string when done with it. FIXME: This is just a guess. */ static char * get_mcn_freebsd (const void *p_user_data) { const _img_private_t *p_env = p_user_data; switch (p_env->access_mode) { case _AM_CAM: case _AM_MMC_RDWR: case _AM_MMC_RDWR_EXCL: return mmc_get_mcn(p_env->gen.cdio); case _AM_IOCTL: return mmc_get_mcn(p_env->gen.cdio); case _AM_NONE: cdio_info ("access mode not set"); return NULL; } return NULL; }
/*! Eject media. Return 1 if successful, 0 otherwise. */ static int eject_media_freebsd (void *p_user_data) { _img_private_t *p_env = p_user_data; switch (p_env->access_mode) { case _AM_CAM: case _AM_MMC_RDWR: case _AM_MMC_RDWR_EXCL: return eject_media_freebsd_cam(p_env); case _AM_IOCTL: return eject_media_freebsd_ioctl(p_env); case _AM_NONE: cdio_info ("access mode not set"); return 0; } return 0; }
/*! Reads a single mode2 sector from cd device into data starting from i_lsn. Returns 0 if no error. */ static driver_return_code_t read_mode2_sector_freebsd (void *p_user_data, void *data, lsn_t i_lsn, bool b_form2) { _img_private_t *p_env = p_user_data; switch (p_env->access_mode) { case _AM_CAM: case _AM_MMC_RDWR: case _AM_MMC_RDWR_EXCL: return read_mode2_sector_freebsd_cam(p_env, data, i_lsn, b_form2); case _AM_IOCTL: return read_mode2_sector_freebsd_ioctl(p_env, data, i_lsn, b_form2); case _AM_NONE: cdio_info ("access mode not set"); return DRIVER_OP_ERROR; } return DRIVER_OP_ERROR; }
/*! Eject media. */ static driver_return_code_t eject_media_win32 (void *p_user_data) { const _img_private_t *p_env = p_user_data; char psz_drive[4]; unsigned int i_device = strlen(p_env->gen.source_name); strcpy( psz_drive, "X:" ); if (6 == i_device) { psz_drive[0] = p_env->gen.source_name[4]; } else if (2 == i_device) { psz_drive[0] = p_env->gen.source_name[0]; } else { cdio_info ("Can't pick out drive letter from device %s", p_env->gen.source_name); return DRIVER_OP_ERROR; } return open_close_media_win32(psz_drive, MCI_SET_DOOR_OPEN); }
/*! Reads i_blocks of audio sectors from cd device into data starting from lsn. Returns 0 if no error. */ static driver_return_code_t read_audio_sectors_freebsd (void *p_user_data, void *p_buf, lsn_t i_lsn, unsigned int i_blocks) { _img_private_t *p_env = p_user_data; switch (p_env->access_mode) { case _AM_CAM: case _AM_MMC_RDWR: case _AM_MMC_RDWR_EXCL: return mmc_read_sectors( p_env->gen.cdio, p_buf, i_lsn, CDIO_MMC_READ_TYPE_CDDA, i_blocks); case _AM_IOCTL: return read_audio_sectors_freebsd_ioctl(p_user_data, p_buf, i_lsn, i_blocks); case _AM_NONE: cdio_info ("access mode not set"); return DRIVER_OP_ERROR; } return DRIVER_OP_ERROR; }
/*! Return the size of the CD in logical block address (LBA) units. @return the lsn. On error return CDIO_INVALID_LSN. */ static lsn_t get_disc_last_lsn_freebsd (void *p_obj) { _img_private_t *p_env = p_obj; if (!p_env) return CDIO_INVALID_LSN; switch (p_env->access_mode) { case _AM_CAM: case _AM_MMC_RDWR: case _AM_MMC_RDWR_EXCL: return get_disc_last_lsn_mmc(p_env); case _AM_IOCTL: return get_disc_last_lsn_freebsd_ioctl(p_env); case _AM_NONE: cdio_info ("access mode not set"); return DRIVER_OP_ERROR; } return DRIVER_OP_ERROR; }
/*! Get @return length of name field; 0: not found, -1: to be ignored */ int get_rock_ridge_filename(iso9660_dir_t * p_iso9660_dir, /*out*/ char * psz_name, /*in/out*/ iso9660_stat_t *p_stat) { int len; unsigned char *chr; int symlink_len = 0; CONTINUE_DECLS; int i_namelen = 0; int truncate=0; if (!p_stat || nope == p_stat->rr.b3_rock) return 0; *psz_name = 0; SETUP_ROCK_RIDGE(p_iso9660_dir, chr, len); /*repeat:*/ { iso_extension_record_t * rr; int sig; int rootflag; while (len > 1){ /* There may be one byte for padding somewhere */ rr = (iso_extension_record_t *) chr; if (rr->len == 0) goto out; /* Something got screwed up here */ sig = *chr+(*(chr+1) << 8); chr += rr->len; len -= rr->len; switch(sig){ case SIG('S','P'): CHECK_SP(goto out); break; case SIG('C','E'): { iso711_t i_fname = from_711(p_iso9660_dir->filename.len); if ('\0' == p_iso9660_dir->filename.str[1] && 1 == i_fname) break; if ('\1' == p_iso9660_dir->filename.str[1] && 1 == i_fname) break; } CHECK_CE; break; case SIG('E','R'): p_stat->rr.b3_rock = yep; cdio_debug("ISO 9660 Extensions: "); { int p; for(p=0;p<rr->u.ER.len_id;p++) cdio_debug("%c",rr->u.ER.data[p]); } break; case SIG('N','M'): /* Alternate name */ p_stat->rr.b3_rock = yep; if (truncate) break; if (rr->u.NM.flags & ISO_ROCK_NM_PARENT) { i_namelen = sizeof(".."); strncat(psz_name, "..", i_namelen); } else if (rr->u.NM.flags & ISO_ROCK_NM_CURRENT) { i_namelen = sizeof("."); strncat(psz_name, ".", i_namelen); break; } if (rr->u.NM.flags & ~1) { cdio_info("Unsupported NM flag settings (%d)",rr->u.NM.flags); break; } if((strlen(psz_name) + rr->len - 5) >= 254) { truncate = 1; break; } strncat(psz_name, rr->u.NM.name, rr->len - 5); i_namelen += rr->len - 5; break; case SIG('P','X'): /* POSIX file attributes */ p_stat->rr.st_mode = from_733(rr->u.PX.st_mode); p_stat->rr.st_nlinks = from_733(rr->u.PX.st_nlinks); p_stat->rr.st_uid = from_733(rr->u.PX.st_uid); p_stat->rr.st_gid = from_733(rr->u.PX.st_gid); p_stat->rr.b3_rock = yep; break; case SIG('S','L'): { /* Symbolic link */ uint8_t slen; iso_rock_sl_part_t * p_sl; iso_rock_sl_part_t * p_oldsl; slen = rr->len - 5; p_sl = &rr->u.SL.link; p_stat->rr.i_symlink = symlink_len; while (slen > 1){ rootflag = 0; switch(p_sl->flags &~1){ case 0: realloc_symlink(p_stat, p_sl->len); memcpy(&(p_stat->rr.psz_symlink[p_stat->rr.i_symlink]), p_sl->text, p_sl->len); p_stat->rr.i_symlink += p_sl->len; break; case 4: realloc_symlink(p_stat, 1); p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '.'; /* continue into next case. */ case 2: realloc_symlink(p_stat, 1); p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '.'; break; case 8: rootflag = 1; realloc_symlink(p_stat, 1); p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '/'; break; default: cdio_warn("Symlink component flag not implemented"); } slen -= p_sl->len + 2; p_oldsl = p_sl; p_sl = (iso_rock_sl_part_t *) (((char *) p_sl) + p_sl->len + 2); if (slen < 2) { if (((rr->u.SL.flags & 1) != 0) && ((p_oldsl->flags & 1) == 0)) p_stat->rr.i_symlink += 1; break; } /* * If this component record isn't continued, then append a '/'. */ if (!rootflag && (p_oldsl->flags & 1) == 0) { realloc_symlink(p_stat, 1); p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '/'; } } } symlink_len = p_stat->rr.i_symlink; realloc_symlink(p_stat, 1); p_stat->rr.psz_symlink[symlink_len]='\0'; break; case SIG('R','E'): free(buffer); return -1; case SIG('T','F'): /* Time stamp(s) for a file */ { int cnt = 0; add_time(ISO_ROCK_TF_CREATE, create); add_time(ISO_ROCK_TF_MODIFY, modify); add_time(ISO_ROCK_TF_ACCESS, access); add_time(ISO_ROCK_TF_ATTRIBUTES, attributes); add_time(ISO_ROCK_TF_BACKUP, backup); add_time(ISO_ROCK_TF_EXPIRATION, expiration); add_time(ISO_ROCK_TF_EFFECTIVE, effective); p_stat->rr.b3_rock = yep; break; } default: break; } } } free(buffer); return i_namelen; /* If 0, this file did not have a NM field */ out: free(buffer); return 0; }
/*! 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; }
/*! Read the Super block of an ISO 9660 image. This is the Primary Volume Descriptor (PVD) and perhaps a Supplemental Volume Descriptor if (Joliet) extensions are acceptable. */ bool iso9660_fs_read_superblock (CdIo_t *p_cdio, iso_extension_mask_t iso_extension_mask) { if (!p_cdio) return false; { generic_img_private_t *p_env = (generic_img_private_t *) p_cdio->env; iso9660_pvd_t *p_pvd = &(p_env->pvd); iso9660_svd_t *p_svd = &(p_env->svd); char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; bool b_mode2; int i_rc; /* A bit of a hack, we'll assume track 1 contains ISO_PVD_SECTOR.*/ switch(cdio_get_track_format(p_cdio, 1)) { case TRACK_FORMAT_CDI: case TRACK_FORMAT_XA: b_mode2 = true; break; case TRACK_FORMAT_DATA: b_mode2 = false; break; case TRACK_FORMAT_AUDIO: case TRACK_FORMAT_PSX: case TRACK_FORMAT_ERROR: default: return false; } if ( !iso9660_fs_read_pvd(p_cdio, p_pvd) ) return false; p_env->i_joliet_level = 0; i_rc = (b_mode2) ? cdio_read_mode2_sector (p_cdio, buf, ISO_PVD_SECTOR+1, false) : cdio_read_mode1_sector (p_cdio, buf, ISO_PVD_SECTOR+1, false); if (0 == i_rc) { /* The size of a PVD or SVD is smaller than a sector. So we allocated a bigger block above (buf) and now we'll copy just the part we need to save. */ cdio_assert (sizeof(buf) >= sizeof (iso9660_svd_t)); memcpy(p_svd, buf, sizeof(iso9660_svd_t)); if ( ISO_VD_SUPPLEMENTARY == from_711(p_svd->type) ) { if (p_svd->escape_sequences[0] == 0x25 && p_svd->escape_sequences[1] == 0x2f) { switch (p_svd->escape_sequences[2]) { case 0x40: if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL1) p_env->i_joliet_level = 1; break; case 0x43: if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL2) p_env->i_joliet_level = 2; break; case 0x45: if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL3) p_env->i_joliet_level = 3; break; default: cdio_info("Supplementary Volume Descriptor found, but not Joliet"); } if (p_env->i_joliet_level > 0) { cdio_info("Found Extension: Joliet Level %d", p_env->i_joliet_level); } } } } } return true; }
/*! Initialization routine. This is the only thing that doesn't get called via a function pointer. In fact *we* are the ones to set that up. */ CdIo * cdio_open_am_freebsd (const char *psz_orig_source_name, const char *psz_access_mode) { #ifdef HAVE_FREEBSD_CDROM CdIo *ret; _img_private_t *_data; char *psz_source_name; if (!psz_access_mode) psz_access_mode = get_access_mode(psz_orig_source_name); cdio_funcs_t _funcs = { .audio_get_volume = audio_get_volume_freebsd, .audio_pause = audio_pause_freebsd, .audio_play_msf = audio_play_msf_freebsd, .audio_play_track_index = audio_play_track_index_freebsd, .audio_read_subchannel = audio_read_subchannel_freebsd, .audio_resume = audio_resume_freebsd, .audio_set_volume = audio_set_volume_freebsd, .audio_stop = audio_stop_freebsd, .eject_media = eject_media_freebsd, .free = free_freebsd, .get_arg = get_arg_freebsd, .get_blocksize = get_blocksize_mmc, .get_cdtext = get_cdtext_generic, .get_default_device = cdio_get_default_device_freebsd, .get_devices = cdio_get_devices_freebsd, .get_disc_last_lsn = get_disc_last_lsn_freebsd, .get_discmode = get_discmode_generic, .get_drive_cap = get_drive_cap_freebsd, .get_first_track_num = get_first_track_num_generic, .get_media_changed = get_media_changed_freebsd, .get_mcn = get_mcn_freebsd, .get_num_tracks = get_num_tracks_generic, .get_track_channels = get_track_channels_generic, .get_track_copy_permit = get_track_copy_permit_generic, .get_track_format = get_track_format_freebsd, .get_track_green = get_track_green_freebsd, .get_track_lba = get_track_lba_freebsd, .get_track_preemphasis = get_track_preemphasis_generic, .get_track_msf = NULL, .lseek = cdio_generic_lseek, .read = cdio_generic_read, .read_audio_sectors = read_audio_sectors_freebsd, .read_data_sectors = read_data_sectors_mmc, .read_mode2_sector = read_mode2_sector_freebsd, .read_mode2_sectors = read_mode2_sectors_freebsd, .read_toc = read_toc_freebsd, .run_mmc_cmd = run_mmc_cmd_freebsd, .set_arg = set_arg_freebsd, .set_blocksize = set_blocksize_mmc, .set_speed = set_speed_freebsd, }; _data = calloc(1, sizeof (_img_private_t)); _data->access_mode = str_to_access_mode_freebsd(psz_access_mode); _data->gen.init = false; _data->gen.fd = -1; _data->gen.toc_init = false; _data->gen.b_cdtext_init = false; _data->gen.b_cdtext_error = false; if (NULL == psz_orig_source_name) { psz_source_name=cdio_get_default_device_freebsd(); if (NULL == psz_source_name) return NULL; _data->device = psz_source_name; set_arg_freebsd(_data, "source", psz_source_name); } else { if (cdio_is_device_generic(psz_orig_source_name)) { set_arg_freebsd(_data, "source", psz_orig_source_name); _data->device = strdup(psz_orig_source_name); } else { /* The below would be okay if all device drivers worked this way. */ #if 0 cdio_info ("source %s is a not a device", psz_orig_source_name); #endif free(_data); return NULL; } } ret = cdio_new ((void *)_data, &_funcs); if (ret == NULL) return NULL; if (cdio_generic_init(_data, O_RDONLY)) if ( _data->access_mode == _AM_IOCTL ) { return ret; } else { if (init_freebsd_cam(_data)) return ret; else { cdio_generic_free (_data); return NULL; } } else { cdio_generic_free (_data); return NULL; } #else return NULL; #endif /* HAVE_FREEBSD_CDROM */ }
/*! Initialization routine. This is the only thing that doesn't get called via a function pointer. In fact *we* are the ones to set that up. */ CdIo * cdio_open_am_win32 (const char *psz_orig_source, const char *psz_access_mode) { #ifdef HAVE_WIN32_CDROM CdIo *ret; _img_private_t *_data; char *psz_source; cdio_funcs_t _funcs; memset( &_funcs, 0, sizeof(_funcs) ); _funcs.eject_media = _cdio_eject_media; _funcs.free = _free_win32; _funcs.get_arg = _get_arg_win32; _funcs.get_cdtext = get_cdtext_generic; _funcs.get_default_device = cdio_get_default_device_win32; _funcs.get_devices = cdio_get_devices_win32; _funcs.get_disc_last_lsn = get_disc_last_lsn_win32; _funcs.get_discmode = get_discmode_win32; _funcs.get_drive_cap = get_drive_cap_mmc; _funcs.get_first_track_num= get_first_track_num_generic; _funcs.get_hwinfo = NULL; _funcs.get_mcn = _cdio_get_mcn; _funcs.get_num_tracks = get_num_tracks_generic; _funcs.get_track_channels = get_track_channels_generic, _funcs.get_track_copy_permit = get_track_copy_permit_generic, _funcs.get_track_format = _cdio_get_track_format; _funcs.get_track_green = _cdio_get_track_green; _funcs.get_track_lba = NULL; /* This could be done if need be. */ _funcs.get_track_msf = _cdio_get_track_msf; _funcs.get_track_preemphasis = get_track_preemphasis_generic, _funcs.lseek = NULL; _funcs.read = NULL; _funcs.read_audio_sectors = _cdio_read_audio_sectors; _funcs.read_mode1_sector = _cdio_read_mode1_sector; _funcs.read_mode1_sectors = _cdio_read_mode1_sectors; _funcs.read_mode2_sector = _cdio_read_mode2_sector; _funcs.read_mode2_sectors = _cdio_read_mode2_sectors; _funcs.read_toc = &read_toc_win32; _funcs.run_scsi_mmc_cmd = &run_scsi_cmd_win32; _funcs.set_arg = set_arg_win32; _funcs.set_blocksize = set_blocksize_mmc; _funcs.set_speed = set_speed_mmc; _data = _cdio_malloc (sizeof (_img_private_t)); _data->access_mode = str_to_access_mode_win32(psz_access_mode); _data->gen.init = false; _data->gen.fd = -1; if (NULL == psz_orig_source) { psz_source=cdio_get_default_device_win32(); if (NULL == psz_source) return NULL; set_arg_win32(_data, "source", psz_source); free(psz_source); } else { if (cdio_is_device_win32(psz_orig_source)) set_arg_win32(_data, "source", psz_orig_source); else { /* The below would be okay if all device drivers worked this way. */ #if 0 cdio_info ("source %s is a not a device", psz_orig_source); #endif free(_data); return NULL; } } ret = cdio_new ((void *)_data, &_funcs); if (ret == NULL) return NULL; if (_cdio_init_win32(_data)) return ret; else { _free_win32 (_data); return NULL; } #else return NULL; #endif /* HAVE_WIN32_CDROM */ }
/*! Initialization routine. This is the only thing that doesn't get called via a function pointer. In fact *we* are the ones to set that up. */ CdIo * cdio_open_am_freebsd (const char *psz_orig_source_name, const char *psz_access_mode) { #ifdef HAVE_FREEBSD_CDROM CdIo *ret; _img_private_t *_data; char *psz_source_name; int open_access_mode; /* Access mode passed to cdio_generic_init. */ cdio_funcs_t _funcs = { .audio_get_volume = audio_get_volume_freebsd, .audio_pause = audio_pause_freebsd, .audio_play_msf = audio_play_msf_freebsd, .audio_play_track_index = audio_play_track_index_freebsd, .audio_read_subchannel = audio_read_subchannel_freebsd, .audio_resume = audio_resume_freebsd, .audio_set_volume = audio_set_volume_freebsd, .audio_stop = audio_stop_freebsd, .eject_media = eject_media_freebsd, .free = free_freebsd, .get_arg = get_arg_freebsd, .get_blocksize = get_blocksize_mmc, .get_cdtext = get_cdtext_generic, .get_cdtext_raw = read_cdtext_generic, .get_default_device = cdio_get_default_device_freebsd, .get_devices = cdio_get_devices_freebsd, .get_disc_last_lsn = get_disc_last_lsn_freebsd, .get_discmode = get_discmode_generic, .get_drive_cap = get_drive_cap_freebsd, .get_first_track_num = get_first_track_num_generic, .get_media_changed = get_media_changed_freebsd, .get_mcn = get_mcn_freebsd, .get_num_tracks = get_num_tracks_generic, .get_track_channels = get_track_channels_generic, .get_track_copy_permit = get_track_copy_permit_generic, .get_track_format = get_track_format_freebsd, .get_track_green = get_track_green_freebsd, .get_track_lba = get_track_lba_freebsd, .get_track_preemphasis = get_track_preemphasis_generic, .get_track_msf = NULL, .get_track_isrc = get_track_isrc_freebsd, .lseek = cdio_generic_lseek, .read = cdio_generic_read, .read_audio_sectors = read_audio_sectors_freebsd, .read_data_sectors = read_data_sectors_mmc, .read_mode2_sector = read_mode2_sector_freebsd, .read_mode2_sectors = read_mode2_sectors_freebsd, .read_toc = read_toc_freebsd, .run_mmc_cmd = run_mmc_cmd_freebsd, .set_arg = set_arg_freebsd, .set_blocksize = set_blocksize_mmc, .set_speed = set_speed_freebsd, }; if (!psz_access_mode) psz_access_mode = get_access_mode(psz_orig_source_name); _data = calloc(1, sizeof (_img_private_t)); _data->access_mode = str_to_access_mode_freebsd(psz_access_mode); _data->gen.init = false; _data->gen.fd = -1; _data->gen.toc_init = false; _data->gen.b_cdtext_error = false; if (NULL == psz_orig_source_name) { psz_source_name=cdio_get_default_device_freebsd(); if (NULL == psz_source_name) { cdio_generic_free (_data); return NULL; } _data->device = psz_source_name; set_arg_freebsd(_data, "source", psz_source_name); } else { if (cdio_is_device_generic(psz_orig_source_name)) { set_arg_freebsd(_data, "source", psz_orig_source_name); _data->device = strdup(psz_orig_source_name); } else { /* The below would be okay if all device drivers worked this way. */ #if 0 cdio_info ("source %s is a not a device", psz_orig_source_name); #endif cdio_generic_free (_data); return NULL; } } ret = cdio_new ((void *)_data, &_funcs); if (ret == NULL) { cdio_generic_free (_data); return NULL; } open_access_mode = 0; if (_AM_MMC_RDWR == _data->access_mode) { open_access_mode |= O_RDWR; } else if (_AM_MMC_RDWR_EXCL == _data->access_mode) { open_access_mode |= O_RDWR; } else { open_access_mode |= O_RDONLY; } /* fprintf(stderr, "libcdio_DEBUG: am = %d (MMC_RDWR_EXCL = %d), open = %d (O_RDWR = %d)\n", _data->access_mode, _AM_MMC_RDWR_EXCL, open_access_mode, O_RDWR); */ if (cdio_generic_init(_data, open_access_mode)) { if (_AM_MMC_RDWR_EXCL == _data->access_mode) { int os_errno, pass_dev_no = -1, flock_fd = -1, lock_result; char msg[4096]; lock_result = freebsd_dev_lock(_data->gen.fd, _data->gen.source_name, &os_errno, &pass_dev_no, &flock_fd, msg, 0); if (lock_result <= 0) { cdio_warn ("%s", msg); goto err_exit; } /* One should rather keep this fd open until _data->gen.fd gets closed. It eventually locks a device sibling of _data->gen.source_name. */ if (flock_fd > 0) close(flock_fd); } if ( _data->access_mode == _AM_IOCTL ) { return ret; } else { if (init_freebsd_cam(_data)) return ret; } } err_exit: free(ret); cdio_generic_free(_data); return NULL; #else return NULL; #endif /* HAVE_FREEBSD_CDROM */ }
/* Disk and track information for a Nero file are located at the end of the file. This routine extracts that information. FIXME: right now psz_nrg_name is not used. It will be in the future. */ static bool parse_nrg (_img_private_t *p_env, const char *psz_nrg_name, const cdio_log_level_t log_level) { off_t footer_start; off_t size; char *footer_buf = NULL; if (!p_env) return false; size = cdio_stream_stat (p_env->gen.data_source); if (-1 == size) return false; { _footer_t buf; cdio_assert (sizeof (buf) == 12); cdio_stream_seek (p_env->gen.data_source, size - sizeof (buf), SEEK_SET); cdio_stream_read (p_env->gen.data_source, (void *) &buf, sizeof (buf), 1); if (buf.v50.ID == UINT32_TO_BE (NERO_ID)) { cdio_debug ("detected Nero version 5.0 (32-bit offsets) NRG magic"); footer_start = uint32_to_be (buf.v50.footer_ofs); } else if (buf.v55.ID == UINT32_TO_BE (NER5_ID)) { cdio_debug ("detected Nero version 5.5.x (64-bit offsets) NRG magic"); footer_start = uint64_from_be (buf.v55.footer_ofs); } else { cdio_log (log_level, "Image not recognized as either version 5.0 or " "version 5.5.x-6.x type NRG"); return false; } cdio_debug (".NRG footer start = %ld, length = %ld", (long) footer_start, (long) (size - footer_start)); cdio_assert ((size - footer_start) <= 4096); footer_buf = calloc(1, (size_t)(size - footer_start)); cdio_stream_seek (p_env->gen.data_source, footer_start, SEEK_SET); cdio_stream_read (p_env->gen.data_source, footer_buf, (size_t)(size - footer_start), 1); } { int pos = 0; while (pos < size - footer_start) { _chunk_t *chunk = (void *) (footer_buf + pos); uint32_t opcode = UINT32_FROM_BE (chunk->id); bool break_out = false; switch (opcode) { case CUES_ID: /* "CUES" Seems to have sector size 2336 and 150 sector pregap seems to be included at beginning of image. */ case CUEX_ID: /* "CUEX" */ { unsigned entries = UINT32_FROM_BE (chunk->len); _cuex_array_t *_entries = (void *) chunk->data; cdio_assert (p_env->mapping == NULL); cdio_assert ( sizeof (_cuex_array_t) == 8 ); cdio_assert ( UINT32_FROM_BE (chunk->len) % sizeof(_cuex_array_t) == 0 ); entries /= sizeof (_cuex_array_t); if (CUES_ID == opcode) { lsn_t lsn = UINT32_FROM_BE (_entries[0].lsn); unsigned int idx; unsigned int i = 0; cdio_debug ("CUES type image detected" ); /* CUES LSN has 150 pregap include at beginning? -/ cdio_assert (lsn == 0?); */ p_env->is_cues = true; /* HACK alert. */ p_env->gen.i_tracks = 0; p_env->gen.i_first_track = 1; for (idx = 1; idx < entries-1; idx += 2, i++) { lsn_t sec_count; int cdte_format = _entries[idx].addr_ctrl / 16; int cdte_ctrl = _entries[idx].type >> 4; if ( COPY_PERMITTED & cdte_ctrl ) { if (p_env) p_env->tocent[i].flags |= COPY_PERMITTED; } else { if (p_env) p_env->tocent[i].flags &= ~COPY_PERMITTED; } if ( PRE_EMPHASIS & cdte_ctrl ) { if (p_env) p_env->tocent[i].flags |= PRE_EMPHASIS; } else { if (p_env) p_env->tocent[i].flags &= ~PRE_EMPHASIS; } if ( FOUR_CHANNEL_AUDIO & cdte_ctrl ) { if (p_env) p_env->tocent[i].flags |= FOUR_CHANNEL_AUDIO; } else { if (p_env) p_env->tocent[i].flags &= ~FOUR_CHANNEL_AUDIO; } cdio_assert (_entries[idx].track == _entries[idx + 1].track); /* lsn and sec_count*2 aren't correct, but it comes closer on the single example I have: svcdgs.nrg We are picking up the wrong fields and/or not interpreting them correctly. */ switch (cdte_format) { case 0: lsn = UINT32_FROM_BE (_entries[idx].lsn); break; case 1: { #if 0 msf_t msf = (msf_t) _entries[idx].lsn; lsn = cdio_msf_to_lsn(&msf); #else lsn = CDIO_INVALID_LSN; #endif cdio_log (log_level, "untested (i.e. probably wrong) CUE MSF code"); break; } default: lsn = CDIO_INVALID_LSN; cdio_log(log_level, "unknown cdte_format %d", cdte_format); } sec_count = UINT32_FROM_BE (_entries[idx + 1].lsn); _register_mapping (p_env, lsn, sec_count*2, (lsn+CDIO_PREGAP_SECTORS) * M2RAW_SECTOR_SIZE, M2RAW_SECTOR_SIZE, TRACK_FORMAT_XA, true); } } else { lsn_t lsn = UINT32_FROM_BE (_entries[0].lsn); unsigned int idx; unsigned int i = 0; cdio_debug ("CUEX type image detected"); /* LSN must start at -150 (LBA 0)? */ cdio_assert (lsn == -150); for (idx = 2; idx < entries; idx += 2, i++) { lsn_t sec_count; int cdte_format = _entries[idx].addr_ctrl >> 4; int cdte_ctrl = _entries[idx].type >> 4; if ( COPY_PERMITTED & cdte_ctrl ) { if (p_env) p_env->tocent[i].flags |= COPY_PERMITTED; } else { if (p_env) p_env->tocent[i].flags &= ~COPY_PERMITTED; } if ( PRE_EMPHASIS & cdte_ctrl ) { if (p_env) p_env->tocent[i].flags |= PRE_EMPHASIS; } else { if (p_env) p_env->tocent[i].flags &= ~PRE_EMPHASIS; } if ( FOUR_CHANNEL_AUDIO & cdte_ctrl ) { if (p_env) p_env->tocent[i].flags |= FOUR_CHANNEL_AUDIO; } else { if (p_env) p_env->tocent[i].flags &= ~FOUR_CHANNEL_AUDIO; } /* extractnrg.pl has cdte_format for LBA's 0, and for MSF 1. ??? FIXME: Should decode as appropriate for cdte_format. */ cdio_assert ( cdte_format == 0 || cdte_format == 1 ); cdio_assert (_entries[idx].track != _entries[idx + 1].track); lsn = UINT32_FROM_BE (_entries[idx].lsn); sec_count = UINT32_FROM_BE (_entries[idx + 1].lsn); _register_mapping (p_env, lsn, sec_count - lsn, (lsn + CDIO_PREGAP_SECTORS)*M2RAW_SECTOR_SIZE, M2RAW_SECTOR_SIZE, TRACK_FORMAT_XA, true); } } break; } case DAOX_ID: /* "DAOX" */ case DAOI_ID: /* "DAOI" */ { _daox_t *_xentries = NULL; _daoi_t *_ientries = NULL; _dao_array_common_t *_dao_array_common = NULL; _dao_common_t *_dao_common = (void *) chunk->data; int disc_mode = _dao_common->unknown[1]; track_format_t track_format; int i; /* We include an extra 0 byte so these can be used as C strings.*/ p_env->psz_mcn = calloc(1, CDIO_MCN_SIZE+1); memcpy(p_env->psz_mcn, &(_dao_common->psz_mcn), CDIO_MCN_SIZE); p_env->psz_mcn[CDIO_MCN_SIZE] = '\0'; if (DAOX_ID == opcode) { _xentries = (void *) chunk->data; p_env->dtyp = _xentries->track_info[0].common.unknown[2]; } else { _ientries = (void *) chunk->data; p_env->dtyp = _ientries->track_info[0].common.unknown[2]; } p_env->is_dao = true; cdio_debug ("DAO%c tag detected, track format %d, mode %x\n", opcode==DAOX_ID ? 'X': 'I', p_env->dtyp, disc_mode); switch (p_env->dtyp) { case 0: /* Mode 1 */ track_format = TRACK_FORMAT_DATA; p_env->disc_mode = CDIO_DISC_MODE_CD_DATA; break; case 2: /* Mode 2 form 1 */ disc_mode = 0; track_format = TRACK_FORMAT_XA; p_env->disc_mode = CDIO_DISC_MODE_CD_XA; break; case 3: /* Mode 2 */ track_format = TRACK_FORMAT_XA; p_env->disc_mode = CDIO_DISC_MODE_CD_XA; /* ?? */ break; case 0x6: /* Mode2 form mix */ track_format = TRACK_FORMAT_XA; p_env->disc_mode = CDIO_DISC_MODE_CD_MIXED; break; case 0x20: /* ??? Mode2 form 2, Mode2 raw?? */ track_format = TRACK_FORMAT_XA; p_env->disc_mode = CDIO_DISC_MODE_CD_XA; /* ??. */ break; case 0x7: track_format = TRACK_FORMAT_AUDIO; p_env->disc_mode = CDIO_DISC_MODE_CD_DA; break; default: cdio_log (log_level, "Unknown track format %x\n", p_env->dtyp); track_format = TRACK_FORMAT_AUDIO; } if (0 == disc_mode) { for (i=0; i<p_env->gen.i_tracks; i++) { p_env->tocent[i].track_format= track_format; p_env->tocent[i].datastart = 0; p_env->tocent[i].track_green = false; if (TRACK_FORMAT_AUDIO == track_format) { p_env->tocent[i].blocksize = CDIO_CD_FRAMESIZE_RAW; p_env->tocent[i].datasize = CDIO_CD_FRAMESIZE_RAW; p_env->tocent[i].endsize = 0; } else { p_env->tocent[i].datasize = CDIO_CD_FRAMESIZE; p_env->tocent[i].datastart = 0; } } } else if (2 == disc_mode) { for (i=0; i<p_env->gen.i_tracks; i++) { p_env->tocent[i].track_green = true; p_env->tocent[i].track_format= track_format; p_env->tocent[i].datasize = CDIO_CD_FRAMESIZE; if (TRACK_FORMAT_XA == track_format) { p_env->tocent[i].datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE; p_env->tocent[i].endsize = CDIO_CD_SYNC_SIZE + CDIO_CD_ECC_SIZE; } else { p_env->tocent[i].datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE; p_env->tocent[i].endsize = CDIO_CD_EDC_SIZE + CDIO_CD_M1F1_ZERO_SIZE + CDIO_CD_ECC_SIZE; } } } else if (0x20 == disc_mode) { cdio_debug ("Mixed mode CD?\n"); } else { /* Mixed mode CD */ cdio_log (log_level, "Don't know if mode 1, mode 2 or mixed: %x\n", disc_mode); } for (i=0; i<p_env->gen.i_tracks; i++) { if (DAOX_ID == opcode) { _dao_array_common = &_xentries->track_info[i].common; } else { _dao_array_common = &_ientries->track_info[i].common; } p_env->tocent[i].isrc = calloc(1, CDIO_ISRC_SIZE+1); memcpy(p_env->tocent[i].isrc, _dao_array_common->psz_isrc, CDIO_ISRC_SIZE); p_env->tocent[i].isrc[CDIO_ISRC_SIZE] = '\0'; if (p_env->tocent[i].isrc[0]) { cdio_info("nrg isrc has value \"%s\"", p_env->tocent[i].isrc); } if (!p_env->tocent[i].datasize) { continue; } if (DAOX_ID == opcode) { p_env->tocent[i].pregap = (uint64_from_be (_xentries->track_info[i].index0)) / (p_env->tocent[i].datasize); } else { p_env->tocent[i].pregap = (uint32_from_be (_ientries->track_info[i].index0)) / (p_env->tocent[i].datasize); } } break; } case NERO_ID: case NER5_ID: cdio_error ("unexpected nrg magic ID NER%c detected", opcode==NERO_ID ? 'O': '5'); free(footer_buf); return false; case END1_ID: /* "END!" */ cdio_debug ("nrg end tag detected"); break_out = true; break; case ETNF_ID: /* "ETNF" */ { unsigned entries = UINT32_FROM_BE (chunk->len); _etnf_array_t *_entries = (void *) chunk->data; cdio_assert (p_env->mapping == NULL); cdio_assert ( sizeof (_etnf_array_t) == 20 ); cdio_assert ( UINT32_FROM_BE(chunk->len) % sizeof(_etnf_array_t) == 0 ); entries /= sizeof (_etnf_array_t); cdio_debug ("SAO type image (ETNF) detected"); { int idx; for (idx = 0; idx < entries; idx++) { uint32_t _len = UINT32_FROM_BE (_entries[idx].length); uint32_t _start = UINT32_FROM_BE (_entries[idx].start_lsn); uint32_t _start2 = UINT32_FROM_BE (_entries[idx].start); uint32_t track_mode= uint32_from_be (_entries[idx].type); bool track_green = true; track_format_t track_format = TRACK_FORMAT_XA; uint16_t blocksize; switch (track_mode) { case 0: /* Mode 1 */ track_format = TRACK_FORMAT_DATA; track_green = false; /* ?? */ blocksize = CDIO_CD_FRAMESIZE; p_env->disc_mode = CDIO_DISC_MODE_CD_DATA; cdio_debug ("Format DATA, blocksize %u", CDIO_CD_FRAMESIZE); break; case 2: /* Mode 2 form 1 */ track_format = TRACK_FORMAT_XA; track_green = false; /* ?? */ blocksize = CDIO_CD_FRAMESIZE; p_env->disc_mode = CDIO_DISC_MODE_CD_XA; cdio_debug ("Format XA, blocksize %u", CDIO_CD_FRAMESIZE); break; case 3: /* Mode 2 */ track_format = TRACK_FORMAT_XA; track_green = true; blocksize = M2RAW_SECTOR_SIZE; p_env->disc_mode = CDIO_DISC_MODE_CD_XA; /* ?? */ cdio_debug ("Format XA, blocksize %u", M2RAW_SECTOR_SIZE); break; case 06: /* Mode2 form mix */ track_format = TRACK_FORMAT_XA; track_green = true; blocksize = M2RAW_SECTOR_SIZE; p_env->disc_mode = CDIO_DISC_MODE_CD_MIXED; cdio_debug ("Format MIXED CD, blocksize %u", M2RAW_SECTOR_SIZE); break; case 0x20: /* ??? Mode2 form 2, Mode2 raw?? */ track_format = TRACK_FORMAT_XA; track_green = true; blocksize = M2RAW_SECTOR_SIZE; p_env->disc_mode = CDIO_DISC_MODE_CD_XA; /* ??. */ cdio_debug ("Format MIXED CD, blocksize %u", M2RAW_SECTOR_SIZE); break; case 7: track_format = TRACK_FORMAT_AUDIO; track_green = false; blocksize = CDIO_CD_FRAMESIZE_RAW; p_env->disc_mode = CDIO_DISC_MODE_CD_DA; cdio_debug ("Format CD_DA, blocksize %u", CDIO_CD_FRAMESIZE_RAW); break; default: cdio_log (log_level, "Don't know how to handle track mode (%lu)?", (long unsigned int) track_mode); free(footer_buf); return false; } cdio_assert (_len % blocksize == 0); _len /= blocksize; cdio_assert (_start * blocksize == _start2); _start += idx * CDIO_PREGAP_SECTORS; _register_mapping (p_env, _start, _len, _start2, blocksize, track_format, track_green); } } break; } case ETN2_ID: { /* "ETN2", same as above, but with 64bit stuff instead */ unsigned entries = uint32_from_be (chunk->len); _etn2_array_t *_entries = (void *) chunk->data; cdio_assert (p_env->mapping == NULL); cdio_assert (sizeof (_etn2_array_t) == 32); cdio_assert (uint32_from_be (chunk->len) % sizeof (_etn2_array_t) == 0); entries /= sizeof (_etn2_array_t); cdio_debug ("SAO type image (ETN2) detected"); { int idx; for (idx = 0; idx < entries; idx++) { uint32_t _len = uint64_from_be (_entries[idx].length); uint32_t _start = uint32_from_be (_entries[idx].start_lsn); uint32_t _start2 = uint64_from_be (_entries[idx].start); uint32_t track_mode= uint32_from_be (_entries[idx].type); bool track_green = true; track_format_t track_format = TRACK_FORMAT_XA; uint16_t blocksize; switch (track_mode) { case 0: track_format = TRACK_FORMAT_DATA; track_green = false; /* ?? */ blocksize = CDIO_CD_FRAMESIZE; break; case 2: track_format = TRACK_FORMAT_XA; track_green = false; /* ?? */ blocksize = CDIO_CD_FRAMESIZE; break; case 3: track_format = TRACK_FORMAT_XA; track_green = true; blocksize = M2RAW_SECTOR_SIZE; break; case 7: track_format = TRACK_FORMAT_AUDIO; track_green = false; blocksize = CDIO_CD_FRAMESIZE_RAW; break; default: cdio_log (log_level, "Don't know how to handle track mode (%lu)?", (long unsigned int) track_mode); free(footer_buf); return false; } if (_len % blocksize != 0) { cdio_log (log_level, "length is not a multiple of blocksize " "len %lu, size %d, rem %lu", (long unsigned int) _len, blocksize, (long unsigned int) _len % blocksize); if (0 == _len % CDIO_CD_FRAMESIZE) { cdio_log(log_level, "Adjusting blocksize to %d", CDIO_CD_FRAMESIZE); blocksize = CDIO_CD_FRAMESIZE; } else if (0 == _len % M2RAW_SECTOR_SIZE) { cdio_log(log_level, "Adjusting blocksize to %d", M2RAW_SECTOR_SIZE); blocksize = M2RAW_SECTOR_SIZE; } else if (0 == _len % CDIO_CD_FRAMESIZE_RAW) { cdio_log(log_level, "Adjusting blocksize to %d", CDIO_CD_FRAMESIZE_RAW); blocksize = CDIO_CD_FRAMESIZE_RAW; } } _len /= blocksize; if (_start * blocksize != _start2) { cdio_log (log_level, "%lu * %d != %lu", (long unsigned int) _start, blocksize, (long unsigned int) _start2); if (_start * CDIO_CD_FRAMESIZE == _start2) { cdio_log(log_level, "Adjusting blocksize to %d", CDIO_CD_FRAMESIZE); blocksize = CDIO_CD_FRAMESIZE; } else if (_start * M2RAW_SECTOR_SIZE == _start2) { cdio_log(log_level, "Adjusting blocksize to %d", M2RAW_SECTOR_SIZE); blocksize = M2RAW_SECTOR_SIZE; } else if (_start * CDIO_CD_FRAMESIZE_RAW == _start2) { cdio_log(log_level, "Adjusting blocksize to %d", CDIO_CD_FRAMESIZE_RAW); blocksize = CDIO_CD_FRAMESIZE_RAW; } } _start += idx * CDIO_PREGAP_SECTORS; _register_mapping (p_env, _start, _len, _start2, blocksize, track_format, track_green); } } break; } case SINF_ID: { /* "SINF" */ uint32_t _sessions; cdio_assert (UINT32_FROM_BE (chunk->len) == 4); memcpy(&_sessions, chunk->data, 4); cdio_debug ("SINF: %lu sessions", (long unsigned int) UINT32_FROM_BE (_sessions)); } break; case MTYP_ID: { /* "MTYP" */ uint32_t mtyp_be; uint32_t mtyp; cdio_assert (UINT32_FROM_BE (chunk->len) == 4); memcpy(&mtyp_be, chunk->data, 4); mtyp = UINT32_FROM_BE (mtyp_be); cdio_debug ("MTYP: %lu", (long unsigned int) mtyp); if (mtyp != MTYP_AUDIO_CD) { cdio_log (log_level, "Unknown MTYP value: %u", (unsigned int) mtyp); } p_env->mtyp = mtyp; } break; case CDTX_ID: { /* "CD TEXT" */ uint8_t *wdata = (uint8_t *) chunk->data; int len = UINT32_FROM_BE (chunk->len); cdio_assert (len % CDTEXT_LEN_PACK == 0); p_env->gen.cdtext = cdtext_init (); if(0 !=cdtext_data_init (p_env->gen.cdtext, wdata, len)) { cdtext_destroy(p_env->gen.cdtext); free(p_env->gen.cdtext); p_env->gen.cdtext = NULL; } break; } default: cdio_log (log_level, "unknown tag %8.8x seen", (unsigned int) UINT32_FROM_BE (chunk->id)); break; } if (break_out) break; pos += 8; pos += UINT32_FROM_BE (chunk->len); }
static void cued_parse_qsc(qsc_buffer_t *qsc, rip_context_t *rip) { int flags; qsc_index_t index; lsn_t *currLsn; char *isrc; if (qsc_check_crc(qsc)) { ++rip->crcFailure; return; } ++rip->crcSuccess; switch (qsc_get_mode(qsc)) { case QSC_MODE_INDEX: if (!qsc_get_index(qsc, &index)) { // set this for ISRC case rip->trackHint = index.track; currLsn = &rip->ripData[index.track].indices[index.index]; if (*currLsn == CDIO_INVALID_LSN || index.absoluteLsn < *currLsn) { *currLsn = index.absoluteLsn; // do not do this for every record; hence, inside the if statement flags = 0; SETF(RIP_F_DATA_VALID, flags); if (qsc_has_pre_emphasis(qsc)) { SETF(RIP_F_DATA_PRE_EMPHASIS, flags); } if (qsc_has_copy_permitted(qsc)) { SETF(RIP_F_DATA_COPY_PERMITTED, flags); } if (qsc_has_four_channels(qsc)) { SETF(RIP_F_DATA_FOUR_CHANNELS, flags); } rip->ripData[index.track].flags = flags; } } else { cdio_warn("invalid index found in q sub-channel"); } break; case QSC_MODE_MCN: if (!rip->mcn[0]) { if (qsc_get_mcn(qsc, rip->mcn)) { cdio_warn("invalid mcn found in q sub-channel"); rip->mcn[0] = 0; } } break; case QSC_MODE_ISRC: isrc = rip->ripData[rip->trackHint].isrc; if (!isrc[0]) { if (qsc_get_isrc(qsc, isrc)) { cdio_warn("invalid isrc found in q sub-channel"); isrc[0] = 0; } else if (!rip->year) { rip->year = qsc_get_isrc_year(isrc); cdio_info("set rip year to %d\n", rip->year); } } break; default: break; } }
/*! Initialization routine. This is the only thing that doesn't get called via a function pointer. In fact *we* are the ones to set that up. */ CdIo_t * cdio_open_os2 (const char *psz_orig_source) { #ifdef HAVE_OS2_CDROM CdIo_t *ret; _img_private_t *_data; char *psz_source; cdio_funcs_t _funcs; memset( &_funcs, 0, sizeof(_funcs) ); _funcs.audio_get_volume = audio_get_volume_os2; _funcs.audio_pause = audio_pause_os2; _funcs.audio_play_msf = audio_play_msf_os2; #if 0 _funcs.audio_play_track_index = audio_play_track_index_os2; #endif _funcs.audio_read_subchannel = audio_read_subchannel_os2; _funcs.audio_resume = audio_resume_os2; _funcs.audio_set_volume = audio_set_volume_os2; _funcs.audio_stop = audio_stop_os2; _funcs.eject_media = eject_media_os2; _funcs.free = free_os2; _funcs.get_arg = get_arg_os2; #if 0 _funcs.get_blocksize = get_blocksize_os2; #endif _funcs.get_cdtext = get_cdtext_generic; _funcs.get_cdtext_raw = read_cdtext_generic; _funcs.get_default_device = cdio_get_default_device_os2; _funcs.get_devices = cdio_get_devices_os2; _funcs.get_disc_last_lsn = get_disc_last_lsn_os2; _funcs.get_discmode = get_discmode_os2; _funcs.get_drive_cap = get_drive_cap_mmc; _funcs.get_first_track_num = get_first_track_num_generic; _funcs.get_hwinfo = NULL; #if 0 _funcs.get_last_session = get_last_session_os2; #endif _funcs.get_media_changed = get_media_changed_mmc; _funcs.get_mcn = _cdio_get_mcn; _funcs.get_num_tracks = get_num_tracks_generic; _funcs.get_track_channels = get_track_channels_generic; _funcs.get_track_copy_permit = get_track_copy_permit_generic; _funcs.get_track_format = _cdio_get_track_format; _funcs.get_track_green = _cdio_get_track_green; _funcs.get_track_lba = NULL; /* This could be done if need be. */ #if 0 _funcs.get_track_pregap_lba = get_track_pregap_lba_os2; #endif _funcs.get_track_isrc = _cdio_get_track_isrc; _funcs.get_track_msf = _cdio_get_track_msf; _funcs.get_track_preemphasis = get_track_preemphasis_generic; _funcs.lseek = cdio_generic_lseek; _funcs.read = cdio_generic_read; _funcs.read_audio_sectors = read_audio_sectors_os2; _funcs.read_data_sectors = read_data_sectors_mmc; _funcs.read_mode1_sector = read_mode1_sector_os2; _funcs.read_mode1_sectors = read_mode1_sectors_os2; _funcs.read_mode2_sector = read_mode2_sector_os2; _funcs.read_mode2_sectors = read_mode2_sectors_os2; _funcs.read_toc = read_toc_os2; _funcs.run_mmc_cmd = run_mmc_cmd_os2; _funcs.set_arg = set_arg_os2; _funcs.set_blocksize = set_blocksize_mmc; _funcs.set_speed = set_drive_speed_mmc; _data = calloc(1, sizeof (_img_private_t)); _data->access_mode = _AM_OS2; _data->gen.b_cdtext_error = false; _data->gen.init = false; _data->gen.fd = -1; if (NULL == psz_orig_source) { psz_source=cdio_get_default_device_os2(); if (NULL == psz_source) return NULL; set_arg_os2(_data, "source", psz_source); free(psz_source); } else { if (cdio_is_device_os2(psz_orig_source)) set_arg_os2(_data, "source", psz_orig_source); else { /* The below would be okay if all device drivers worked this way. */ #if 0 cdio_info ("source %s is a not a device", psz_orig_source); #endif free(_data); return NULL; } } ret = cdio_new ((void *)_data, &_funcs); if (ret == NULL) return NULL; ret->driver_id = DRIVER_OS2; if (init_os2(_data)) return ret; else { free_os2 (_data); free(ret); return NULL; } #else return NULL; #endif /* HAVE_OS2_CDROM */ }