📄 info.c
字号:
/*! Return true is there is playback control. */boolvcdinfo_has_pbc (const vcdinfo_obj_t *obj) { return (obj && obj->info.psd_size!=0);} /*! Return true if VCD has "extended attributes" (XA). Extended attributes add meta-data attributes to a entries of file describing the file. See also cdio_get_xa_attr_str() which returns a string similar to a string you might get on a Unix filesystem listing ("ls").*/boolvcdinfo_has_xa(const vcdinfo_obj_t *obj) { return obj->has_xa;}/*! Add one to the MSF.*/voidvcdinfo_inc_msf (uint8_t *min, uint8_t *sec, int8_t *frame){ (*frame)++; if (*frame>=CDIO_CD_FRAMES_PER_SEC) { *frame = 0; (*sec)++; if (*sec>=CDIO_CD_SECS_PER_MIN) { *sec = 0; (*min)++; } }}/*! Convert minutes, seconds and frame (MSF components) into a logical block address (or LBA). See also cdio_msf_to_lba which uses msf_t as its single parameter.*/lba_tvcdinfo_msf2lba (uint8_t min, uint8_t sec, int8_t frame){ return CDIO_CD_FRAMES_PER_SEC*(CDIO_CD_SECS_PER_MIN*min + sec) + frame;}/*! Convert minutes, seconds and frame (MSF components) into a logical block address (or LBA). See also cdio_msf_to_lba which uses msf_t as its single parameter.*/void vcdinfo_lba2msf (lba_t lba, uint8_t *min, uint8_t *sec, uint8_t *frame) { *min = lba / (60*75); lba %= (60*75); *sec = lba / 75; *frame = lba % 75; }/*! Convert minutes, seconds and frame (MSF components) into a logical sector number (or LSN). */lsn_tvcdinfo_msf2lsn (uint8_t min, uint8_t sec, int8_t frame){ lba_t lba=75*(60*min + sec) + frame; if (lba < CDIO_PREGAP_SECTORS) { vcd_error ("lba (%u) less than pregap sector (%u)", (unsigned int) lba, CDIO_PREGAP_SECTORS); return lba; } return lba - CDIO_PREGAP_SECTORS;}const char *vcdinfo_ofs2str (const vcdinfo_obj_t *obj, unsigned int offset, bool ext){ vcdinfo_offset_t *ofs; char *buf; switch (offset) { case PSD_OFS_DISABLED: return "disabled"; case PSD_OFS_MULTI_DEF: return "multi-default"; case PSD_OFS_MULTI_DEF_NO_NUM: return "multi_def_no_num"; default: ; } buf = _getbuf (); ofs = _vcdinfo_get_offset_t(obj, offset, ext); if (ofs != NULL) { if (ofs->lid) snprintf (buf, BUF_SIZE, "LID[%d] @0x%4.4x", ofs->lid, ofs->offset); else snprintf (buf, BUF_SIZE, "PSD[?] @0x%4.4x", ofs->offset); } else { snprintf (buf, BUF_SIZE, "? @0x%4.4x", offset); } return buf;}boolvcdinfo_read_psd (vcdinfo_obj_t *obj){ unsigned psd_size = vcdinfo_get_psd_size (obj); if (psd_size) { if (psd_size > 256*1024) { vcd_error ("weird psd size (%u) -- aborting", psd_size); return false; } obj->lot = _vcd_malloc (ISO_BLOCKSIZE * LOT_VCD_SIZE); obj->psd = _vcd_malloc (ISO_BLOCKSIZE * _vcd_len2blocks (psd_size, ISO_BLOCKSIZE)); if (cdio_read_mode2_sectors (obj->img, (void *) obj->lot, LOT_VCD_SECTOR, false, LOT_VCD_SIZE)) return false; if (cdio_read_mode2_sectors (obj->img, (void *) obj->psd, PSD_VCD_SECTOR, false, _vcd_len2blocks (psd_size, ISO_BLOCKSIZE))) return false; } else { return false; } return true;}/*! Return the entry number for the given track. */unsigned int vcdinfo_track_get_entry(const vcdinfo_obj_t *obj, track_t i_track) { /* FIXME: Add structure to directly map track to first entry number. Until then... */ lsn_t lsn= vcdinfo_get_track_lsn(obj, i_track); return vcdinfo_lsn_get_entry(obj, lsn);} /*! Calls recursive routine to populate obj->offset_list or obj->offset_x_list by going through LOT. Returns false if there was some error.*/boolvcdinfo_visit_lot (vcdinfo_obj_t *obj, bool extended){ struct _vcdinf_pbc_ctx pbc_ctx; bool ret; pbc_ctx.psd_size = vcdinfo_get_psd_size (obj); pbc_ctx.psd_x_size = obj->psd_x_size; pbc_ctx.offset_mult = 8; pbc_ctx.maximum_lid = vcdinfo_get_num_LIDs(obj); pbc_ctx.offset_x_list = NULL; pbc_ctx.offset_list = NULL; pbc_ctx.psd = obj->psd; pbc_ctx.psd_x = obj->psd_x; pbc_ctx.lot = obj->lot; pbc_ctx.lot_x = obj->lot_x; pbc_ctx.extended = extended; ret = vcdinf_visit_lot(&pbc_ctx); if (NULL != obj->offset_x_list) _cdio_list_free(obj->offset_x_list, true); obj->offset_x_list = pbc_ctx.offset_x_list; if (NULL != obj->offset_list) _cdio_list_free(obj->offset_list, true); obj->offset_list = pbc_ctx.offset_list; return ret;}/*! Change trailing blanks in str to nulls. Str has a maximum size of n characters.*/const char *vcdinfo_strip_trail (const char str[], size_t n){ static char buf[1025]; int j; vcd_assert (n < 1024); strncpy (buf, str, n); buf[n] = '\0'; for (j = strlen (buf) - 1; j >= 0; j--) { if (buf[j] != ' ') break; buf[j] = '\0'; } return buf;}/*! Return true if offset is "rejected". That is shouldn't be displayed in a list of entries.*/boolvcdinfo_is_rejected(uint16_t offset){ return (offset & VCDINFO_REJECTED_MASK) != 0;}/*! Nulls/zeros vcdinfo_obj_t structures; The caller should have ensured that obj != NULL. routines using obj are called.*/static void_vcdinfo_zero(vcdinfo_obj_t *obj){ memset(obj, 0, sizeof(vcdinfo_obj_t)); obj->vcd_type = VCD_TYPE_INVALID; obj->img = NULL; obj->lot = NULL; obj->source_name = NULL; obj->seg_sizes = NULL;}/*! Initialize the vcdinfo structure "obj". Should be done before other routines using obj are called.*/bool vcdinfo_init(vcdinfo_obj_t *obj){ if (NULL == obj) return false; _vcdinfo_zero(obj); return cdio_init();}/*! Set up vcdinfo structure "obj" for reading from a particular medium. This should be done before after initialization but before any routines that need to retrieve data. source_name is the device or file to use for inspection, and source_type indicates what driver to use or class of drivers in the case of DRIVER_DEVICE. access_mode gives the CD access method for reading should the driver allow for more than one kind of access method (e.g. MMC versus ioctl on GNU/Linux) If source_name is NULL we'll fill in the appropriate default device name for the given source_type. However if in addtion source_type is DRIVER_UNKNOWN, then we'll scan for a drive containing a VCD. VCDINFO_OPEN_VCD is returned if everything went okay; VCDINFO_OPEN_ERROR if there was an error and VCDINFO_OPEN_OTHER if the medium is something other than a VCD. */vcdinfo_open_return_tvcdinfo_open(vcdinfo_obj_t **obj_p, char *source_name[], driver_id_t source_type, const char access_mode[]){ CdIo *img; vcdinfo_obj_t *obj = _vcd_malloc(sizeof(vcdinfo_obj_t)); iso9660_stat_t *statbuf; /* If we don't specify a driver_id or a source_name, scan the system for a CD that contains a VCD. */ if (NULL == *source_name && source_type == DRIVER_UNKNOWN) { char **cd_drives=NULL; cd_drives = cdio_get_devices_with_cap_ret(NULL, (CDIO_FS_ANAL_SVCD|CDIO_FS_ANAL_CVD|CDIO_FS_ANAL_VIDEOCD |CDIO_FS_UNKNOWN), true, &source_type); if ( NULL == cd_drives || NULL == cd_drives[0] ) { return VCDINFO_OPEN_ERROR; } *source_name = strdup(cd_drives[0]); cdio_free_device_list(cd_drives); } img = cdio_open(*source_name, source_type); if (NULL == img) { return VCDINFO_OPEN_ERROR; } *obj_p = obj; if (access_mode != NULL) cdio_set_arg (img, "access-mode", access_mode); if (NULL == *source_name) { *source_name = cdio_get_default_device(img); if (NULL == *source_name) return VCDINFO_OPEN_ERROR; } memset (obj, 0, sizeof (vcdinfo_obj_t)); obj->img = img; /* Note we do this after the above wipeout! */ if (!iso9660_fs_read_pvd(obj->img, &(obj->pvd))) { return VCDINFO_OPEN_ERROR; } /* Determine if VCD has XA attributes. */ { iso9660_pvd_t const *pvd = &obj->pvd; obj->has_xa = !strncmp ((char *) pvd + ISO_XA_MARKER_OFFSET, ISO_XA_MARKER_STRING, strlen (ISO_XA_MARKER_STRING)); } if (!read_info(obj->img, &(obj->info), &(obj->vcd_type)) || vcdinfo_get_format_version (obj) == VCD_TYPE_INVALID || !read_entries(obj->img, &(obj->entries))) { free (obj); /* match 0.7.23's behaviour */ return VCDINFO_OPEN_OTHER; } { size_t len = strlen(*source_name)+1; obj->source_name = (char *) malloc(len * sizeof(char)); strncpy(obj->source_name, *source_name, len); } if (obj->vcd_type == VCD_TYPE_SVCD || obj->vcd_type == VCD_TYPE_HQVCD) { statbuf = iso9660_fs_stat (obj->img, "MPEGAV"); if (NULL != statbuf) { vcd_warn ("non compliant /MPEGAV folder detected!"); free(statbuf); } statbuf = iso9660_fs_stat (obj->img, "SVCD/TRACKS.SVD;1"); if (NULL != statbuf) { lsn_t lsn = statbuf->lsn; if (statbuf->size != ISO_BLOCKSIZE) vcd_warn ("TRACKS.SVD filesize != %d!", ISO_BLOCKSIZE); obj->tracks_buf = _vcd_malloc (ISO_BLOCKSIZE); free(statbuf); if (cdio_read_mode2_sector (obj->img, obj->tracks_buf, lsn, false)) return VCDINFO_OPEN_ERROR; } } _init_segments (obj); switch (obj->vcd_type) { case VCD_TYPE_VCD2: { /* FIXME: Can reduce CD reads by using iso9660_fs_readdir(img, "EXT", true) and then scanning for the files listed below. */ statbuf = iso9660_fs_stat (img, "EXT/PSD_X.VCD;1"); if (NULL != statbuf) { lsn_t lsn = statbuf->lsn; uint32_t secsize = statbuf->secsize; obj->psd_x = _vcd_malloc (ISO_BLOCKSIZE * secsize); obj->psd_x_size = statbuf->size; vcd_debug ("found /EXT/PSD_X.VCD at sector %lu", (long unsigned int) lsn); free(statbuf); if (cdio_read_mode2_sectors (img, obj->psd_x, lsn, false, secsize)) return VCDINFO_OPEN_ERROR; } statbuf = iso9660_fs_stat (img, "EXT/LOT_X.VCD;1"); if (NULL != statbuf) { lsn_t lsn = statbuf->lsn; uint32_t secsize = statbuf->secsize; obj->lot_x = _vcd_malloc (ISO_BLOCKSIZE * secsize); vcd_debug ("found /EXT/LOT_X.VCD at sector %lu", (unsigned long int) lsn); if (statbuf->size != LOT_VCD_SIZE * ISO_BLOCKSIZE) vcd_warn ("LOT_X.VCD size != 65535"); free(statbuf); if (cdio_read_mode2_sectors (img, obj->lot_x, lsn, false, secsize)) return VCDINFO_OPEN_ERROR; } break; } case VCD_TYPE_SVCD: case VCD_TYPE_HQVCD: { /* FIXME: Can reduce CD reads by using iso9660_fs_readdir(img, "SVCD", true) and then scanning for the files listed below. */ statbuf = iso9660_fs_stat (img, "MPEGAV"); if (NULL != statbuf) { vcd_warn ("non compliant /MPEGAV folder detected!"); free(statbuf); } statbuf = iso9660_fs_stat (img, "SVCD/TRACKS.SVD;1"); if (NULL == statbuf) vcd_warn ("mandatory /SVCD/TRACKS.SVD not found!"); else { vcd_debug ("found TRACKS.SVD signature at sector %lu", (unsigned long int) statbuf->lsn); free(statbuf); } statbuf = iso9660_fs_stat (img, "SVCD/SEARCH.DAT;1"); if (NULL == statbuf) vcd_warn ("mandatory /SVCD/SEARCH.DAT not found!"); else { lsn_t lsn = statbuf->lsn; uint32_t secsize = statbuf->secsize; uint32_t stat_size = statbuf->size; uint32_t size; vcd_debug ("found SEARCH.DAT at sector %lu", (unsigned long int) lsn); obj->search_buf = _vcd_malloc (ISO_BLOCKSIZE * secsize); if (cdio_read_mode2_sectors (img, obj->search_buf, lsn, false, secsize)) return VCDINFO_OPEN_ERROR; size = (3 * uint16_from_be (((SearchDat *)obj->search_buf)->scan_points)) + sizeof (SearchDat); free(statbuf); if (size > stat_size) { vcd_warn ("number of scanpoints leads to bigger size than " "file size of SEARCH.DAT! -- rereading"); free (obj->search_buf); obj->search_buf = _vcd_malloc (ISO_BLOCKSIZE * _vcd_len2blocks(size, ISO_BLOCKSIZE)); if (cdio_read_mode2_sectors (img, obj->search_buf, lsn, false, secsize)) return VCDINFO_OPEN_ERROR; } } break; } default: ; } statbuf = iso9660_fs_stat (img, "EXT/SCANDATA.DAT;1"); if (statbuf != NULL) { lsn_t lsn = statbuf->lsn; uint32_t secsize = statbuf->secsize; vcd_debug ("found /EXT/SCANDATA.DAT at sector %u", (unsigned int) lsn); obj->scandata_buf = _vcd_malloc (ISO_BLOCKSIZE * secsize); free(statbuf); if (cdio_read_mode2_sectors (img, obj->scandata_buf, lsn, false, secsize)) return VCDINFO_OPEN_ERROR; } return VCDINFO_OPEN_VCD; }/*! Dispose of any resources associated with vcdinfo structure "obj". Call this when "obj" it isn't needed anymore. True is returned is everything went okay, and false if not.*/bool vcdinfo_close(vcdinfo_obj_t *obj){ if (obj != NULL) { if (obj->offset_list != NULL) _cdio_list_free(obj->offset_list, true); if (obj->offset_x_list != NULL) _cdio_list_free(obj->offset_x_list, true); free(obj->seg_sizes); free(obj->lot); free(obj->lot_x); if (obj->psd_x) free(obj->psd_x); if (obj->psd) free(obj->psd); if (obj->scandata_buf) free(obj->scandata_buf); free(obj->tracks_buf); free(obj->search_buf); free(obj->source_name); if (obj->img != NULL) cdio_destroy (obj->img); _vcdinfo_zero(obj); } free(obj); return(true);}/* * Local variables: * c-file-style: "gnu" * tab-width: 8 * indent-tabs-mode: nil * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -