/*! Like fread(3) and in fact is about the same. DESCRIPTION: The function fread reads nmemb elements of data, each size bytes long, from the stream pointed to by stream, storing them at the location given by ptr. RETURN VALUE: return the number of items successfully read or written (i.e., not the number of characters). If an error occurs, or the end-of-file is reached, the return value is a short item count (or zero). We do not distinguish between end-of-file and error, and callers must use feof(3) and ferror(3) to determine which occurred. */ static long _stdio_read(void *user_data, void *buf, long int count) { _UserData *const ud = user_data; long read; read = fread(buf, 1, count, ud->fd); if (read != count) { /* fixme -- ferror/feof */ if (feof (ud->fd)) { cdio_debug ("fread (): EOF encountered"); clearerr (ud->fd); } else if (ferror (ud->fd)) { cdio_error ("fread (): %s", strerror (errno)); clearerr (ud->fd); } else cdio_debug ("fread (): short read and no EOF?!?"); } return read; }
/*! Add/allocate a drive to the end of drives. Use cdio_free_device_list() to free this device_list. */ void cdio_add_device_list(char **device_list[], const char *drive, unsigned int *num_drives) { if (NULL != drive) { unsigned int j; char real_device_1[PATH_MAX]; char real_device_2[PATH_MAX]; cdio_realpath(drive, real_device_1); /* Check if drive is already in list. */ for (j=0; j<*num_drives; j++) { cdio_realpath((*device_list)[j], real_device_2); if (strcmp(real_device_1, real_device_2) == 0) break; } if (j==*num_drives) { /* Drive not in list. Add it. */ (*num_drives)++; *device_list = realloc(*device_list, (*num_drives) * sizeof(char *)); cdio_debug("Adding drive %s to list of devices", drive); (*device_list)[*num_drives-1] = strdup(drive); } } else { (*num_drives)++; if (*device_list) { *device_list = realloc(*device_list, (*num_drives) * sizeof(char *)); } else { *device_list = malloc((*num_drives) * sizeof(char *)); } cdio_debug("Adding NULL to end of drive list of size %d", (*num_drives)-1); (*device_list)[*num_drives-1] = NULL; } }
/*! Reads a single mode1 sector from cd device into data starting from lsn. Returns 0 if no error. */ static int read_mode1_sector_win32 (void *p_user_data, void *p_buf, lsn_t lsn, bool b_form2) { _img_private_t *p_env = p_user_data; if (p_env->gen.ioctls_debugged == 75) cdio_debug ("only displaying every 75th ioctl from now on"); if (p_env->gen.ioctls_debugged == 30 * 75) cdio_debug ("only displaying every 30*75th ioctl from now on"); if (p_env->gen.ioctls_debugged < 75 || (p_env->gen.ioctls_debugged < (30 * 75) && p_env->gen.ioctls_debugged % 75 == 0) || p_env->gen.ioctls_debugged % (30 * 75) == 0) cdio_debug ("reading %lu", (unsigned long int) lsn); p_env->gen.ioctls_debugged++; if ( p_env->hASPI ) { return read_mode1_sector_aspi( p_env, p_buf, lsn, b_form2 ); } else { return read_mode1_sector_win32ioctl( p_env, p_buf, lsn, b_form2 ); } }
/*! Reads a single mode2 sector from cd device into data starting from lsn. Returns 0 if no error. */ static int read_mode2_sector_win32 (void *p_user_data, void *data, lsn_t lsn, bool b_form2) { char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; _img_private_t *p_env = p_user_data; if (p_env->gen.ioctls_debugged == 75) cdio_debug ("only displaying every 75th ioctl from now on"); if (p_env->gen.ioctls_debugged == 30 * 75) cdio_debug ("only displaying every 30*75th ioctl from now on"); if (p_env->gen.ioctls_debugged < 75 || (p_env->gen.ioctls_debugged < (30 * 75) && p_env->gen.ioctls_debugged % 75 == 0) || p_env->gen.ioctls_debugged % (30 * 75) == 0) cdio_debug ("reading %lu", (unsigned long int) lsn); p_env->gen.ioctls_debugged++; if ( p_env->hASPI ) { int ret; ret = read_mode2_sector_aspi(p_user_data, buf, lsn, 1); if( ret != 0 ) return ret; if (b_form2) memcpy (data, buf, M2RAW_SECTOR_SIZE); else memcpy (((char *)data), buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE); return 0; } else { return read_mode2_sector_win32ioctl( p_env, data, lsn, b_form2 ); } }
/* Read a particular block into the global array to be used for further analysis later. */ static int _cdio_read_block(const CdIo *cdio, int superblock, uint32_t offset, uint8_t bufnum, track_t track_num) { unsigned int track_sec_count = cdio_get_track_sec_count(cdio, track_num); memset(buffer[bufnum], 0, CDIO_CD_FRAMESIZE); if ( track_sec_count < superblock) { cdio_debug("reading block %u skipped track %d has only %u sectors\n", superblock, track_num, track_sec_count); return -1; } cdio_debug("about to read sector %lu\n", (long unsigned int) offset+superblock); if (cdio_get_track_green(cdio, track_num)) { if (0 > cdio_read_mode2_sector(cdio, buffer[bufnum], offset+superblock, false)) return -1; } else { if (0 > cdio_read_mode1_sector(cdio, buffer[bufnum], offset+superblock, false)) return -1; } return 0; }
const char * is_cdrom_win32ioctl(const char c_drive_letter) { #ifdef _XBOX char sz_win32_drive_full[] = "\\\\.\\X:"; sz_win32_drive_full[4] = c_drive_letter; return strdup(sz_win32_drive_full); #else UINT uDriveType; char sz_win32_drive[4]; sz_win32_drive[0]= c_drive_letter; sz_win32_drive[1]=':'; sz_win32_drive[2]='\\'; sz_win32_drive[3]='\0'; uDriveType = GetDriveType(sz_win32_drive); switch(uDriveType) { case DRIVE_CDROM: { char sz_win32_drive_full[] = "\\\\.\\X:"; sz_win32_drive_full[4] = c_drive_letter; return strdup(sz_win32_drive_full); } default: cdio_debug("Drive %c is not a CD-ROM", c_drive_letter); return NULL; } #endif }
/* Read a particular block into the global array to be used for further analysis later. */ static driver_return_code_t _cdio_read_block(const CdIo_t *p_cdio, int superblock, uint32_t offset, uint8_t bufnum, track_t i_track) { unsigned int track_sec_count = cdio_get_track_sec_count(p_cdio, i_track); memset(buffer[bufnum], 0, CDIO_CD_FRAMESIZE); if ( track_sec_count < superblock) { cdio_debug("reading block %u skipped track %d has only %u sectors\n", superblock, i_track, track_sec_count); return DRIVER_OP_ERROR; } cdio_debug("about to read sector %lu\n", (long unsigned int) offset+superblock); return cdio_read_data_sectors (p_cdio, buffer[bufnum], offset+superblock, ISO_BLOCKSIZE, 1); }
void cdio_stream_close(CdioDataSource_t *p_obj) { if (!p_obj) return; if (p_obj->is_open) { cdio_debug ("closed source..."); p_obj->op.close(p_obj->user_data); p_obj->is_open = 0; p_obj->position = 0; } }
/*! Reads a single mode2 sector from cd device into data starting from lsn. Returns 0 if no error. */ static int read_mode2_sector_win32 (void *p_user_data, void *data, lsn_t lsn, bool b_form2) { char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; _img_private_t *p_env = p_user_data; if (p_env->gen.ioctls_debugged == 75) cdio_debug ("only displaying every 75th ioctl from now on"); if (p_env->gen.ioctls_debugged == 30 * 75) cdio_debug ("only displaying every 30*75th ioctl from now on"); if (p_env->gen.ioctls_debugged < 75 || (p_env->gen.ioctls_debugged < (30 * 75) && p_env->gen.ioctls_debugged % 75 == 0) || p_env->gen.ioctls_debugged % (30 * 75) == 0) cdio_debug ("reading %lu", (unsigned long int) lsn); p_env->gen.ioctls_debugged++; return read_mode2_sector_win32ioctl( p_env, data, lsn, b_form2 ); }
static void _idr2statbuf (const iso9660_dir_t *idr, iso9660_stat_t *stat, bool is_mode2) { iso9660_xa_t *xa_data = NULL; uint8_t dir_len= iso9660_get_dir_len(idr); memset ((void *) stat, 0, sizeof (iso9660_stat_t)); if (!dir_len) return; stat->type = (idr->file_flags & ISO_DIRECTORY) ? _STAT_DIR : _STAT_FILE; stat->lsn = from_733 (idr->extent); stat->size = from_733 (idr->size); stat->secsize = _cdio_len2blocks (stat->size, ISO_BLOCKSIZE); iso9660_get_dtime(&(idr->recording_time), true, &(stat->tm)); cdio_assert (dir_len >= sizeof (iso9660_dir_t)); if (is_mode2) { int su_length = iso9660_get_dir_len(idr) - sizeof (iso9660_dir_t); su_length -= idr->filename_len; if (su_length % 2) su_length--; if (su_length < 0 || su_length < sizeof (iso9660_xa_t)) return; xa_data = (void *) (((char *) idr) + (iso9660_get_dir_len(idr) - su_length)); if (xa_data->signature[0] != 'X' || xa_data->signature[1] != 'A') { cdio_warn ("XA signature not found in ISO9660's system use area;" " ignoring XA attributes for this file entry."); cdio_debug ("%d %d %d, '%c%c' (%d, %d)", iso9660_get_dir_len(idr), idr->filename_len, su_length, xa_data->signature[0], xa_data->signature[1], xa_data->signature[0], xa_data->signature[1]); return; } stat->xa = *xa_data; } }
/* Open if not already open. Return false if we hit an error. Errno should be set for that error. */ static bool _cdio_stream_open_if_necessary(CdioDataSource_t *p_obj) { if (!p_obj) return false; if (!p_obj->is_open) { if (p_obj->op.open(p_obj->user_data)) { cdio_warn ("could not open input stream..."); return false; } else { cdio_debug ("opened source..."); p_obj->is_open = 1; p_obj->position = 0; } } return true; }
static int parse_rock_ridge_stat_internal(iso9660_dir_t *p_iso9660_dir, iso9660_stat_t *p_stat, int regard_xa) { int len; unsigned char * chr; int symlink_len = 0; CONTINUE_DECLS; if (nope == p_stat->rr.b3_rock) return 0; SETUP_ROCK_RIDGE(p_iso9660_dir, chr, len); if (regard_xa) { chr+=14; len-=14; if (len<0) len=0; } /* repeat:*/ { int sig; iso_extension_record_t * rr; 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 = from_721(*chr); chr += rr->len; len -= rr->len; switch(sig){ case SIG('S','P'): CHECK_SP(goto out); break; case SIG('C','E'): 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('P','X'): 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); break; case SIG('P','N'): /* Device major,minor number */ { int32_t high, low; high = from_733(rr->u.PN.dev_high); low = from_733(rr->u.PN.dev_low); /* * The Rock Ridge standard specifies that if sizeof(dev_t) <= 4, * then the high field is unused, and the device number is completely * stored in the low field. Some writers may ignore this subtlety, * and as a result we test to see if the entire device number is * stored in the low field, and use that. */ if((low & ~0xff) && high == 0) { p_stat->rr.i_rdev = CDIO_MKDEV(low >> 8, low & 0xff); } else { p_stat->rr.i_rdev = CDIO_MKDEV(high, low); } } break; 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; } 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++] = '/'; 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'): cdio_warn("Attempt to read p_stat for relocated directory"); goto out; #ifdef FINISHED case SIG('C','L'): { iso9660_stat_t * reloc; ISOFS_I(p_stat)->i_first_extent = from_733(rr->u.CL.location); reloc = isofs_iget(p_stat->rr.i_sb, p_stat->rr.i_first_extent, 0); if (!reloc) goto out; p_stat->rr.st_mode = reloc->st_mode; p_stat->rr.st_nlinks = reloc->st_nlinks; p_stat->rr.st_uid = reloc->st_uid; p_stat->rr.st_gid = reloc->st_gid; p_stat->rr.i_rdev = reloc->i_rdev; p_stat->rr.i_symlink = reloc->i_symlink; p_stat->rr.i_blocks = reloc->i_blocks; p_stat->rr.i_atime = reloc->i_atime; p_stat->rr.i_ctime = reloc->i_ctime; p_stat->rr.i_mtime = reloc->i_mtime; iput(reloc); } break; #endif default: break; } }
/*! 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; }
/*! 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_am_win32 (const char *psz_orig_source, const char *psz_access_mode) { #ifdef HAVE_WIN32_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_win32; _funcs.audio_pause = audio_pause_win32; _funcs.audio_play_msf = audio_play_msf_win32; #if 0 _funcs.audio_play_track_index = audio_play_track_index_win32; #endif _funcs.audio_read_subchannel = audio_read_subchannel_win32; _funcs.audio_resume = audio_resume_win32; _funcs.audio_set_volume = audio_set_volume_win32; _funcs.audio_stop = audio_stop_win32; _funcs.eject_media = eject_media_win32; _funcs.free = free_win32; _funcs.get_arg = get_arg_win32; _funcs.get_cdtext = get_cdtext_generic; _funcs.get_cdtext_raw = read_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_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. */ _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 = read_audio_sectors; _funcs.read_data_sectors = read_data_sectors_win32; _funcs.read_mode1_sector = read_mode1_sector_win32; _funcs.read_mode1_sectors = read_mode1_sectors_win32; _funcs.read_mode2_sector = read_mode2_sector_win32; _funcs.read_mode2_sectors = read_mode2_sectors_win32; _funcs.read_toc = read_toc_win32; _funcs.run_mmc_cmd = run_mmc_cmd_win32; _funcs.set_arg = set_arg_win32; _funcs.set_blocksize = set_blocksize_mmc; _funcs.set_speed = set_drive_speed_mmc; _data = calloc(1, 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 as an info message if all device drivers worked this way. */ cdio_debug ("source %s is a not a device", psz_orig_source); free(_data); return NULL; } } ret = cdio_new ((void *)_data, &_funcs); if (ret == NULL) return NULL; if (init_win32(_data)) return ret; else { free_win32 (_data); return NULL; } #else return NULL; #endif /* HAVE_WIN32_CDROM */ }
/*! Initialize internal structures for CD device. */ bool init_win32ioctl (_img_private_t *env) { #ifdef WIN32 OSVERSIONINFO ov; #endif #ifdef _XBOX ANSI_STRING filename; OBJECT_ATTRIBUTES attributes; IO_STATUS_BLOCK status; HANDLE hDevice; NTSTATUS error; #else unsigned int len=strlen(env->gen.source_name); char psz_win32_drive[7]; DWORD dw_access_flags; #endif cdio_debug("using winNT/2K/XP ioctl layer"); #ifdef WIN32 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; #endif if (cdio_is_device_win32(env->gen.source_name)) { #ifdef _XBOX // Use XBOX cdrom, no matter what drive letter is given. RtlInitAnsiString(&filename,"\\Device\\Cdrom0"); InitializeObjectAttributes(&attributes, &filename, OBJ_CASE_INSENSITIVE, NULL); error = NtCreateFile( &hDevice, GENERIC_READ |SYNCHRONIZE | FILE_READ_ATTRIBUTES, &attributes, &status, NULL, 0, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ); if (!NT_SUCCESS(error)) { return false; } env->h_device_handle = hDevice; #else sprintf( psz_win32_drive, "\\\\.\\%c:", env->gen.source_name[len-2] ); env->h_device_handle = CreateFile( psz_win32_drive, dw_access_flags, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if( env->h_device_handle == INVALID_HANDLE_VALUE ) { /* No good. try toggle write. */ dw_access_flags ^= GENERIC_WRITE; env->h_device_handle = CreateFile( psz_win32_drive, dw_access_flags, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (env->h_device_handle == NULL) return false; } #endif env->b_ioctl_init = true; return true; } return false; }
/*! Read and cache the CD's Track Table of Contents and track info. via a SCSI MMC READ_TOC (FULTOC). Return true if successful or false if an error. */ static bool read_fulltoc_win32mmc (_img_private_t *p_env) { mmc_cdb_t cdb = {{0, }}; CDROM_TOC_FULL cdrom_toc_full; int i_status, i, j; int i_track_format = 0; int i_seen_flag; /* Operation code */ CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_TOC); cdb.field[1] = 0x00; /* Format */ cdb.field[2] = CDIO_MMC_READTOC_FMT_FULTOC; memset(&cdrom_toc_full, 0, sizeof(cdrom_toc_full)); /* Setup to read header, to get length of data */ CDIO_MMC_SET_READ_LENGTH16(cdb.field, sizeof(cdrom_toc_full)); i_status = run_mmc_cmd_win32ioctl (p_env, 1000*60*3, mmc_get_cmd_len(cdb.field[0]), &cdb, SCSI_MMC_DATA_READ, sizeof(cdrom_toc_full), &cdrom_toc_full); if ( 0 != i_status ) { cdio_debug ("SCSI MMC READ_TOC failed\n"); return false; } i_seen_flag=0; for( i = 0 ; i <= CDIO_CD_MAX_TRACKS+3; i++ ) { if ( 0xA0 == cdrom_toc_full.TrackData[i].POINT ) { /* First track number */ p_env->gen.i_first_track = cdrom_toc_full.TrackData[i].PMIN; i_track_format = cdrom_toc_full.TrackData[i].PSEC; i_seen_flag|=0x01; } if ( 0xA1 == cdrom_toc_full.TrackData[i].POINT ) { /* Last track number */ p_env->gen.i_tracks = cdrom_toc_full.TrackData[i].PMIN - p_env->gen.i_first_track + 1; i_seen_flag|=0x02; } j = cdrom_toc_full.TrackData[i].POINT; if ( 0xA2 == j ) { /* Start position of the lead out */ p_env->tocent[ p_env->gen.i_tracks ].start_lsn = cdio_lba_to_lsn( cdio_msf3_to_lba( cdrom_toc_full.TrackData[i].PMIN, cdrom_toc_full.TrackData[i].PSEC, cdrom_toc_full.TrackData[i].PFRAME ) ); p_env->tocent[ p_env->gen.i_tracks ].Control = cdrom_toc_full.TrackData[i].Control; p_env->tocent[ p_env->gen.i_tracks ].Format = i_track_format; i_seen_flag|=0x04; } if (cdrom_toc_full.TrackData[i].POINT > 0 && cdrom_toc_full.TrackData[i].POINT <= p_env->gen.i_tracks) { p_env->tocent[j-1].start_lsn = cdio_lba_to_lsn( cdio_msf3_to_lba( cdrom_toc_full.TrackData[i].PMIN, cdrom_toc_full.TrackData[i].PSEC, cdrom_toc_full.TrackData[i].PFRAME ) ); p_env->tocent[j-1].Control = cdrom_toc_full.TrackData[i].Control; p_env->tocent[j-1].Format = i_track_format; set_track_flags(&(p_env->gen.track_flags[j]), p_env->tocent[j-1].Control); cdio_debug("p_sectors: %i, %lu", i, (unsigned long int) (p_env->tocent[i].start_lsn)); if (cdrom_toc_full.TrackData[i].POINT == p_env->gen.i_tracks) i_seen_flag|=0x08; } if ( 0x0F == i_seen_flag ) break; } if ( 0x0F == i_seen_flag ) { p_env->gen.toc_init = true; return true; } return false; }
static iso9660_stat_t * _iso9660_dir_to_statbuf (iso9660_dir_t *p_iso9660_dir, bool_3way_t b_xa, uint8_t i_joliet_level) { uint8_t dir_len= iso9660_get_dir_len(p_iso9660_dir); iso711_t i_fname; unsigned int stat_len; iso9660_stat_t *p_stat; if (!dir_len) return NULL; i_fname = from_711(p_iso9660_dir->filename_len); /* .. string in statbuf is one longer than in p_iso9660_dir's listing '\1' */ stat_len = sizeof(iso9660_stat_t)+i_fname+2; p_stat = calloc(1, stat_len); if (!p_stat) { cdio_warn("Couldn't calloc(1, %d)", stat_len); return NULL; } p_stat->type = (p_iso9660_dir->file_flags & ISO_DIRECTORY) ? _STAT_DIR : _STAT_FILE; p_stat->lsn = from_733 (p_iso9660_dir->extent); p_stat->size = from_733 (p_iso9660_dir->size); p_stat->secsize = _cdio_len2blocks (p_stat->size, ISO_BLOCKSIZE); p_stat->rr.b3_rock = dunno; /*FIXME should do based on mask */ p_stat->b_xa = false; { char rr_fname[256] = ""; int i_rr_fname = #ifdef HAVE_ROCK get_rock_ridge_filename(p_iso9660_dir, rr_fname, p_stat); #else 0; #endif if (i_rr_fname > 0) { if (i_rr_fname > i_fname) { /* realloc gives valgrind errors */ iso9660_stat_t *p_stat_new = calloc(1, sizeof(iso9660_stat_t)+i_rr_fname+2); if (!p_stat_new) { cdio_warn("Couldn't calloc(1, %d)", sizeof(iso9660_stat_t)+i_rr_fname+2); return NULL; } memcpy(p_stat_new, p_stat, stat_len); free(p_stat); p_stat = p_stat_new; } strncpy(p_stat->filename, rr_fname, i_rr_fname+1); } else { if ('\0' == p_iso9660_dir->filename[0] && 1 == i_fname) strncpy (p_stat->filename, ".", sizeof(".")); else if ('\1' == p_iso9660_dir->filename[0] && 1 == i_fname) strncpy (p_stat->filename, "..", sizeof("..")); #ifdef HAVE_JOLIET else if (i_joliet_level) { int i_inlen = i_fname; cdio_utf8_t *p_psz_out = NULL; if (cdio_charset_to_utf8(p_iso9660_dir->filename, i_inlen, &p_psz_out, "UCS-2BE")) { strncpy(p_stat->filename, p_psz_out, i_fname); free(p_psz_out); } else { return NULL; } } #endif /*HAVE_JOLIET*/ else { strncpy (p_stat->filename, p_iso9660_dir->filename, i_fname); } } } iso9660_get_dtime(&(p_iso9660_dir->recording_time), true, &(p_stat->tm)); if (dir_len < sizeof (iso9660_dir_t)) { free(p_stat->rr.psz_symlink); free(p_stat); return NULL; } { int su_length = iso9660_get_dir_len(p_iso9660_dir) - sizeof (iso9660_dir_t); su_length -= i_fname; if (su_length % 2) su_length--; if (su_length < 0 || su_length < sizeof (iso9660_xa_t)) return p_stat; if (nope == b_xa) { return p_stat; } else { iso9660_xa_t *xa_data = (void *) (((char *) p_iso9660_dir) + (iso9660_get_dir_len(p_iso9660_dir) - su_length)); cdio_log_level_t loglevel = (yep == b_xa) ? CDIO_LOG_WARN : CDIO_LOG_INFO; if (xa_data->signature[0] != 'X' || xa_data->signature[1] != 'A') { cdio_log (loglevel, "XA signature not found in ISO9660's system use area;" " ignoring XA attributes for this file entry."); cdio_debug ("%d %d %d, '%c%c' (%d, %d)", iso9660_get_dir_len(p_iso9660_dir), i_fname, su_length, xa_data->signature[0], xa_data->signature[1], xa_data->signature[0], xa_data->signature[1]); return p_stat; } p_stat->b_xa = true; p_stat->xa = *xa_data; } } return p_stat; }
/*! Read and cache the CD's Track Table of Contents and track info. Return true if successful or false if an error. */ bool read_toc_win32ioctl (_img_private_t *p_env) { CDROM_TOC cdrom_toc; DWORD dw_bytes_returned; unsigned int i, j; bool b_fulltoc_first; /* Do we do fulltoc or DeviceIoControl first? */ if ( ! p_env ) return false; /* The MMC5 spec says: For media other than CD, information may be fabricated in order ^^^ ^^ to emulate a CD structure for the specific media. There is no requirement though that it *has* to and some DVD drives like one by Thompson for XBOX don't support a IOCTL_CDROM_READ_TOC for DVD's. So if we have a DVD we should not prefer getting the TOC via MMC. But on the other hand in GNU/Linux it is reported that using the TOC via MMC gives better information such as for CD DATA Form 2 (used in SVCDs). So if we *don't* have a DVD I think we want to try MMC first. Is this complicated enough? I could be wrong... */ b_fulltoc_first = (CDIO_DISC_MODE_NO_INFO == dvd_discmode_win32ioctl(p_env)); if ( b_fulltoc_first && read_fulltoc_win32mmc(p_env) ) return true; /* SCSI-MMC READ_TOC (FULTOC) read failed or we don't want to try it initiaily. Try reading TOC via DeviceIoControl... */ if( DeviceIoControl( p_env->h_device_handle, IOCTL_CDROM_READ_TOC, NULL, 0, &cdrom_toc, sizeof(CDROM_TOC), &dw_bytes_returned, NULL ) == 0 ) { char *psz_msg = NULL; long int i_err = GetLastError(); cdio_log_level_t loglevel = b_fulltoc_first ? CDIO_LOG_WARN : CDIO_LOG_DEBUG; FORMAT_ERROR(i_err, psz_msg); if (psz_msg) { cdio_log(loglevel, "could not read TOC (%ld): %s", i_err, psz_msg); LocalFree(psz_msg); } else cdio_log(loglevel, "could not read TOC (%ld)", i_err); if ( !b_fulltoc_first && read_fulltoc_win32mmc(p_env) ) return true; return false; } p_env->gen.i_first_track = cdrom_toc.FirstTrack; p_env->gen.i_tracks = cdrom_toc.LastTrack - cdrom_toc.FirstTrack + 1; j = p_env->gen.i_first_track; for( i = 0 ; i <= p_env->gen.i_tracks ; i++, j++ ) { p_env->tocent[ i ].start_lsn = cdio_lba_to_lsn( cdio_msf3_to_lba( cdrom_toc.TrackData[i].Address[1], cdrom_toc.TrackData[i].Address[2], cdrom_toc.TrackData[i].Address[3] ) ); p_env->tocent[i].Control = cdrom_toc.TrackData[i].Control; p_env->tocent[i].Format = cdrom_toc.TrackData[i].Adr; p_env->gen.track_flags[j].preemphasis = p_env->tocent[i].Control & 0x1 ? CDIO_TRACK_FLAG_TRUE : CDIO_TRACK_FLAG_FALSE; p_env->gen.track_flags[j].copy_permit = p_env->tocent[i].Control & 0x2 ? CDIO_TRACK_FLAG_TRUE : CDIO_TRACK_FLAG_FALSE; p_env->gen.track_flags[j].channels = p_env->tocent[i].Control & 0x8 ? 4 : 2; cdio_debug("p_sectors: %i, %lu", i, (unsigned long int) (p_env->tocent[i].start_lsn)); } p_env->gen.toc_init = true; return true; }
static iso9660_stat_t * _iso9660_dir_to_statbuf (iso9660_dir_t *p_iso9660_dir, bool b_mode2, uint8_t i_joliet_level) { iso9660_xa_t *xa_data = NULL; uint8_t dir_len= iso9660_get_dir_len(p_iso9660_dir); unsigned int filename_len; unsigned int stat_len; iso9660_stat_t *stat; if (!dir_len) return NULL; filename_len = from_711(p_iso9660_dir->filename_len); /* .. string in statbuf is one longer than in p_iso9660_dir's listing '\1' */ stat_len = sizeof(iso9660_stat_t)+filename_len+2; stat = _cdio_malloc(stat_len); stat->type = (p_iso9660_dir->file_flags & ISO_DIRECTORY) ? _STAT_DIR : _STAT_FILE; stat->lsn = from_733 (p_iso9660_dir->extent); stat->size = from_733 (p_iso9660_dir->size); stat->secsize = _cdio_len2blocks (stat->size, ISO_BLOCKSIZE); if ('\0' == p_iso9660_dir->filename[0] && 1 == filename_len) strcpy (stat->filename, "."); else if ('\1' == p_iso9660_dir->filename[0] && 1 == filename_len) strcpy (stat->filename, ".."); else { #ifdef HAVE_JOLIET if (i_joliet_level) { int i_inlen = filename_len; int i_outlen = (i_inlen / 2); char *p_psz_out = NULL; ucs2be_to_locale(p_iso9660_dir->filename, i_inlen, &p_psz_out, i_outlen); strncpy(stat->filename, p_psz_out, filename_len); free(p_psz_out); } else #endif /*HAVE_JOLIET*/ strncpy (stat->filename, p_iso9660_dir->filename, filename_len); } iso9660_get_dtime(&(p_iso9660_dir->recording_time), true, &(stat->tm)); cdio_assert (dir_len >= sizeof (iso9660_dir_t)); if (b_mode2) { int su_length = iso9660_get_dir_len(p_iso9660_dir) - sizeof (iso9660_dir_t); su_length -= filename_len; if (su_length % 2) su_length--; if (su_length < 0 || su_length < sizeof (iso9660_xa_t)) return stat; xa_data = (void *) (((char *) p_iso9660_dir) + (iso9660_get_dir_len(p_iso9660_dir) - su_length)); if (xa_data->signature[0] != 'X' || xa_data->signature[1] != 'A') { cdio_warn ("XA signature not found in ISO9660's system use area;" " ignoring XA attributes for this file entry."); cdio_debug ("%d %d %d, '%c%c' (%d, %d)", iso9660_get_dir_len(p_iso9660_dir), filename_len, su_length, xa_data->signature[0], xa_data->signature[1], xa_data->signature[0], xa_data->signature[1]); return stat; } stat->xa = *xa_data; } return stat; }
/*! 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_cdrdao (const char *psz_cue_name) { CdIo_t *ret; _img_private_t *p_data; cdio_funcs_t _funcs; memset( &_funcs, 0, sizeof(_funcs) ); _funcs.eject_media = _eject_media_image; _funcs.free = _free_image; _funcs.get_arg = _get_arg_image; _funcs.get_cdtext = _get_cdtext_image; _funcs.get_cdtext_raw = NULL; _funcs.get_devices = cdio_get_devices_cdrdao; _funcs.get_default_device = cdio_get_default_device_cdrdao; _funcs.get_disc_last_lsn = get_disc_last_lsn_cdrdao; _funcs.get_discmode = _get_discmode_image; _funcs.get_drive_cap = _get_drive_cap_image; _funcs.get_first_track_num = _get_first_track_num_image; _funcs.get_hwinfo = get_hwinfo_cdrdao; _funcs.get_media_changed = get_media_changed_image; _funcs.get_mcn = _get_mcn_image; _funcs.get_num_tracks = _get_num_tracks_image; _funcs.get_track_channels = get_track_channels_image; _funcs.get_track_copy_permit = get_track_copy_permit_image; _funcs.get_track_format = _get_track_format_cdrdao; _funcs.get_track_green = _get_track_green_cdrdao; _funcs.get_track_lba = _get_lba_track_cdrdao; _funcs.get_track_msf = _get_track_msf_image; _funcs.get_track_preemphasis = get_track_preemphasis_image; _funcs.get_track_pregap_lba = get_track_pregap_lba_image; _funcs.get_track_isrc = get_track_isrc_image; _funcs.lseek = _lseek_cdrdao; _funcs.read = _read_cdrdao; _funcs.read_audio_sectors = _read_audio_sectors_cdrdao; _funcs.read_data_sectors = read_data_sectors_image; _funcs.read_mode1_sector = _read_mode1_sector_cdrdao; _funcs.read_mode1_sectors = _read_mode1_sectors_cdrdao; _funcs.read_mode2_sector = _read_mode2_sector_cdrdao; _funcs.read_mode2_sectors = _read_mode2_sectors_cdrdao; _funcs.run_mmc_cmd = NULL; _funcs.set_arg = _set_arg_image; _funcs.set_speed = cdio_generic_unimplemented_set_speed; _funcs.set_blocksize = cdio_generic_unimplemented_set_blocksize; if (NULL == psz_cue_name) return NULL; p_data = calloc(1, sizeof (_img_private_t)); p_data->gen.init = false; p_data->psz_cue_name = NULL; p_data->gen.data_source = NULL; p_data->gen.source_name = NULL; ret = cdio_new ((void *)p_data, &_funcs); if (ret == NULL) { free(p_data); return NULL; } ret->driver_id = DRIVER_CDRDAO; if (!cdio_is_tocfile(psz_cue_name)) { cdio_debug ("source name %s is not recognized as a TOC file", psz_cue_name); free(p_data); free(ret); return NULL; } _set_arg_image (p_data, "cue", psz_cue_name); _set_arg_image (p_data, "source", psz_cue_name); _set_arg_image (p_data, "access-mode", "cdrdao"); if (_init_cdrdao(p_data)) { return ret; } else { _free_image(p_data); free(ret); return NULL; } }
/* 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); }
/* 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); }