📄 dvd_reader.c
字号:
fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename ); } return -1; } tot_size = fileinfo.st_size; nr_parts = 1; parts_size[0] = fileinfo.st_size; if( !menu ) { int cur; for( cur = 2; cur < 10; cur++ ) { sprintf( filename, "VTS_%02d_%d.VOB", title, cur ); if( !findDVDFile( dvd, filename, full_path ) ) { break; } if( stat( full_path, &fileinfo ) < 0 ) { if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename ); } break; } parts_size[nr_parts] = fileinfo.st_size; tot_size += parts_size[nr_parts]; nr_parts++; } } statbuf->size = tot_size; statbuf->nr_parts = nr_parts; for(n = 0; n < nr_parts; n++) { statbuf->parts_size[n] = parts_size[n]; } return 0;}int DVDFileStat(dvd_reader_t *dvd, int titlenum, dvd_read_domain_t domain, dvd_stat_t *statbuf){ char filename[ MAX_UDF_FILE_NAME_LEN ]; char full_path[ PATH_MAX + 1 ]; struct stat fileinfo; uint32_t size; /* Check arguments. */ if( dvd == NULL || titlenum < 0 ) { errno = EINVAL; return -1; } switch( domain ) { case DVD_READ_INFO_FILE: if( titlenum == 0 ) { sprintf( filename, "/VIDEO_TS/VIDEO_TS.IFO" ); } else { sprintf( filename, "/VIDEO_TS/VTS_%02i_0.IFO", titlenum ); } break; case DVD_READ_INFO_BACKUP_FILE: if( titlenum == 0 ) { sprintf( filename, "/VIDEO_TS/VIDEO_TS.BUP" ); } else { sprintf( filename, "/VIDEO_TS/VTS_%02i_0.BUP", titlenum ); } break; case DVD_READ_MENU_VOBS: if( dvd->isImageFile ) { return DVDFileStatVOBUDF( dvd, titlenum, 1, statbuf ); } else { return DVDFileStatVOBPath( dvd, titlenum, 1, statbuf ); } break; case DVD_READ_TITLE_VOBS: if( titlenum == 0 ) { return -1; } if( dvd->isImageFile ) { return DVDFileStatVOBUDF( dvd, titlenum, 0, statbuf ); } else { return DVDFileStatVOBPath( dvd, titlenum, 0, statbuf ); } break; default: if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: Invalid domain for file stat.\n" ); } errno = EINVAL; return -1; } if( dvd->isImageFile ) { if( UDFFindFile( dvd, filename, &size ) ) { statbuf->size = size; statbuf->nr_parts = 1; statbuf->parts_size[0] = size; return 0; } } else { if( findDVDFile( dvd, filename, full_path ) ) { if( stat( full_path, &fileinfo ) < 0 ) { if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename ); } } else { statbuf->size = fileinfo.st_size; statbuf->nr_parts = 1; statbuf->parts_size[0] = statbuf->size; return 0; } } } return -1;}/** * Internal, but used from dvd_udf.c * * @param device A read handle. * @param lb_number Logical block number to start read from. * @param block_count Number of logical blocks to read. * @param data Pointer to buffer where read data should be stored. * This buffer must be large enough to hold lb_number*2048 bytes. * The pointer must be aligned to the logical block size when * reading from a raw/O_DIRECT device. * @param encrypted 0 if no decryption shall be performed, * 1 if decryption shall be performed * @param return Returns number of blocks read on success, negative on error */int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number, size_t block_count, unsigned char *data, int encrypted ){ int ret; if( !device->dev ) { if(device->verbose >= 1) { fprintf( stderr, "libdvdread: Fatal error in block read.\n" ); } return 0; } ret = dvdinput_seek( device->dev, (int) lb_number ); if( ret != (int) lb_number ) { if(device->verbose >= 1) { fprintf( stderr, "libdvdread: UDFReadBlocksRaw: Can't seek to block %u\n", lb_number ); } return 0; } return dvdinput_read( device->dev, (char *) data, (int) block_count, encrypted );}/** * This is using a single input and starting from 'dvd_file->lb_start' offset. * * Reads 'block_count' blocks from 'dvd_file' at block offset 'offset' * into the buffer located at 'data' and if 'encrypted' is set * descramble the data if it's encrypted. Returning either an * negative error or the number of blocks read. * * @param data Pointer to buffer where read data should be placed. * This buffer must be large enough to hold block_count*2048 bytes. * The pointer must be aligned to 2048 bytes when reading from * a raw/O_DIRECT device. * @return Returns the number of blocks read on success or a negative error. */static int DVDReadBlocksUDF( dvd_file_t *dvd_file, uint32_t offset, size_t block_count, unsigned char *data, int encrypted ){ return UDFReadBlocksRaw( dvd_file->dvd, dvd_file->lb_start + offset, block_count, data, encrypted );}/** * This is using possibly several inputs and starting from an offset of '0'. * data must be aligned to logical block size (2048 bytes) of the device * for raw/O_DIRECT devices to work * Reads 'block_count' blocks from 'dvd_file' at block offset 'offset' * into the buffer located at 'data' and if 'encrypted' is set * descramble the data if it's encrypted. Returning either an * negative error or the number of blocks read. * * @param dvd_file A file read handle. * @param offset Block offset from start of file. * @return Returns number of blocks read on success, negative on error. */static int DVDReadBlocksPath( dvd_file_t *dvd_file, unsigned int offset, size_t block_count, unsigned char *data, int encrypted ){ int i; int ret, ret2, off; ret = 0; ret2 = 0; for( i = 0; i < 9; ++i ) { if( !dvd_file->title_sizes[ i ] ) return 0; /* Past end of file */ if( offset < dvd_file->title_sizes[ i ] ) { if( ( offset + block_count ) <= dvd_file->title_sizes[ i ] ) { off = dvdinput_seek( dvd_file->title_devs[ i ], (int)offset ); if( off < 0 || off != (int)offset ) { if(dvd_file->dvd->verbose >= 1) { fprintf( stderr, "libdvdread: DVDReadBlocksPath1: Can't seek to block %d\n", offset ); } return off < 0 ? off : 0; } ret = dvdinput_read( dvd_file->title_devs[ i ], data, (int)block_count, encrypted ); break; } else { size_t part1_size = dvd_file->title_sizes[ i ] - offset; /* FIXME: Really needs to be a while loop. * (This is only true if you try and read >1GB at a time) */ /* Read part 1 */ off = dvdinput_seek( dvd_file->title_devs[ i ], (int)offset ); if( off < 0 || off != (int)offset ) { if(dvd_file->dvd->verbose >= 1) { fprintf( stderr, "libdvdread: DVDReadBlocksPath2: Can't seek to block %d\n", offset ); } return off < 0 ? off : 0; } ret = dvdinput_read( dvd_file->title_devs[ i ], data, (int)part1_size, encrypted ); if( ret < 0 ) return ret; /* FIXME: This is wrong if i is the last file in the set. * also error from this read will not show in ret. */ /* Does the next part exist? If not then return now. */ if( !dvd_file->title_devs[ i + 1 ] ) return ret; /* Read part 2 */ off = dvdinput_seek( dvd_file->title_devs[ i + 1 ], 0 ); if( off < 0 || off != 0 ) { if(dvd_file->dvd->verbose >= 1) { fprintf( stderr, "libdvdread: DVDReadBlocksPath3: Can't seek to block %d\n", 0 ); } return off < 0 ? off : 0; } ret2 = dvdinput_read( dvd_file->title_devs[ i + 1 ], data + ( part1_size * (int64_t)DVD_VIDEO_LB_LEN ), (int)(block_count - part1_size), encrypted ); if( ret2 < 0 ) return ret2; break; } } else { offset -= dvd_file->title_sizes[ i ]; } } return ret + ret2;}/** * This is broken reading more than 2Gb at a time if ssize_t is 32-bit. */ssize_t DVDReadBlocks( dvd_file_t *dvd_file, int offset, size_t block_count, unsigned char *data ){ int ret; /* Check arguments. */ if( dvd_file == NULL || offset < 0 || data == NULL ) return -1; /* Hack, and it will still fail for multiple opens in a threaded app ! */ if( dvd_file->dvd->css_title != dvd_file->css_title ) { dvd_file->dvd->css_title = dvd_file->css_title; if( dvd_file->dvd->isImageFile ) { dvdinput_title( dvd_file->dvd->dev, (int)dvd_file->lb_start ); } /* Here each vobu has it's own dvdcss handle, so no need to update else { dvdinput_title( dvd_file->title_devs[ 0 ], (int)dvd_file->lb_start ); }*/ } if( dvd_file->dvd->isImageFile ) { ret = DVDReadBlocksUDF( dvd_file, (uint32_t)offset, block_count, data, DVDINPUT_READ_DECRYPT ); } else { ret = DVDReadBlocksPath( dvd_file, (unsigned int)offset, block_count, data, DVDINPUT_READ_DECRYPT ); } return (ssize_t)ret;}int DVDFileSeek( dvd_file_t *dvd_file, int offset ){ /* Check arguments. */ if( dvd_file == NULL || offset < 0 ) return -1; if( offset > dvd_file->filesize * DVD_VIDEO_LB_LEN ) { return -1; } dvd_file->seek_pos = (uint32_t) offset; return offset;}#ifndef HAVE_UINTPTR_T#warning "Assuming that (unsigned long) can hold (void *)"typedef unsigned long uintptr_t;#endif#define DVD_ALIGN(ptr) (void *)((((uintptr_t)(ptr)) + (DVD_VIDEO_LB_LEN-1)) \ / DVD_VIDEO_LB_LEN * DVD_VIDEO_LB_LEN)ssize_t DVDReadBytes( dvd_file_t *dvd_file, void *data, size_t byte_size ){ unsigned char *secbuf_start; unsigned char *secbuf; //must be aligned to 2048-bytes for raw/O_DIRECT unsigned int numsec, seek_sector, seek_byte; int ret; /* Check arguments. */ if( dvd_file == NULL || data == NULL ) { errno = EINVAL; return -1; } seek_sector = dvd_file->seek_pos / DVD_VIDEO_LB_LEN; seek_byte = dvd_file->seek_pos % DVD_VIDEO_LB_LEN; numsec = ( ( seek_byte + byte_size ) / DVD_VIDEO_LB_LEN ) + ( ( ( seek_byte + byte_size ) % DVD_VIDEO_LB_LEN ) ? 1 : 0 ); /* must align to 2048 bytes if we are reading from raw/O_DIRECT */ secbuf_start = (unsigned char *) malloc( (numsec+1) * DVD_VIDEO_LB_LEN ); if( !secbuf_start ) { /* errno will be set to ENOMEM by malloc */ return -1; } secbuf = DVD_ALIGN(secbuf_start); if( dvd_file->dvd->isImageFile ) { ret = DVDReadBlocksUDF( dvd_file, (uint32_t) seek_sector, (size_t) numsec, secbuf, DVDINPUT_NOFLAGS ); } else { ret = DVDReadBlocksPath( dvd_file, seek_sector, (size_t) numsec, secbuf, DVDINPUT_NOFLAGS ); } if( ret != (int) numsec ) { free( secbuf_start ); return ret < 0 ? ret : 0; } memcpy( data, &(secbuf[ seek_byte ]), byte_size ); free( secbuf_start ); dvd_file->seek_pos += byte_size; return byte_size;}ssize_t DVDFileSize( dvd_file_t *dvd_file ){ /* Check arguments. */ if( dvd_file == NULL ) return -1; return dvd_file->filesize;}int DVDDiscID( dvd_reader_t *dvd, unsigned char *discid ){ struct md5_ctx ctx; int title; int nr_of_files = 0; int tmp_errno; int nofiles_errno = ENOENT; /* Check arguments. */ if( dvd == NULL || discid == NULL ) { errno = EINVAL; return -1; } /* Go through the first 10 IFO:s, in order, * and md5sum them, i.e VIDEO_TS.IFO and VTS_0?_0.IFO */ md5_init_ctx( &ctx ); for( title = 0; title < 10; title++ ) { dvd_file_t *dvd_file = DVDOpenFile( dvd, title, DVD_READ_INFO_FILE ); if( dvd_file != NULL ) { ssize_t bytes_read; size_t file_size = dvd_file->filesize * DVD_VIDEO_LB_LEN; char *buffer = malloc( file_size ); nr_of_files++; if( buffer == NULL ) { /* errno will be set to ENOMEM by malloc */ return -1; } bytes_read = DVDReadBytes( dvd_file, buffer, file_size ); if( bytes_read != file_size ) { tmp_errno = errno; if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: DVDDiscId read returned %d bytes" ", wanted %d\n", (int)bytes_read, (int)file_size ); } free(buffer); DVDCloseFile( dvd_file ); errno = tmp_errno; return -1; } md5_process_bytes( buffer, file_size, &ctx ); DVDCloseFile( dvd_file ); free( buffer ); } else { if(errno != ENOENT) { nofiles_errno = errno; } } } md5_finish_ctx( &ctx, discid ); if(nr_of_files == 0) { errno = nofiles_errno; return -1; } return 0;}int DVDISOVolumeInfo( dvd_reader_t *dvd, char *volid, unsigned int volid_size, unsigned char *volsetid, unsigned int volsetid_size ){ unsigned char *buffer; /* must be aligned to 2048 for raw/O_DIRECT */ unsigned char *buffer_start; int ret; /* Check arguments. */ if( dvd == NULL ) { errno = EINVAL; return -1; } if( dvd->dev == NULL ) { /* No block access, so no ISO... */ errno = EINVAL; return -1; } buffer_start = malloc( 2 * DVD_VIDEO_LB_LEN ); if( buffer_start == NULL ) { return -1; } buffer = DVD_ALIGN(buffer_start); ret = UDFReadBlocksRaw( dvd, 16, 1, buffer, 0 ); if( ret != 1 ) { if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: DVDISOVolumeInfo, failed to " "read ISO9660 Primary Volume Descriptor!\n" ); } free(buffer_start); return -1; } if( (volid != NULL) && (volid_size > 0) ) { unsigned int n; for(n = 0; n < 32; n++) { if(buffer[40+n] == 0x20) { break; } } if(volid_size > n+1) { volid_size = n+1; } memcpy(volid, &buffer[40], volid_size-1); volid[volid_size-1] = '\0'; } if( (volsetid != NULL) && (volsetid_size > 0) ) { if(volsetid_size > 128) { volsetid_size = 128; } memcpy(volsetid, &buffer[190], volsetid_size); } free(buffer_start); return 0;}int DVDUDFVolumeInfo( dvd_reader_t *dvd, char *volid, unsigned int volid_size, unsigned char *volsetid, unsigned int volsetid_size ){ int ret; /* Check arguments. */ if( dvd == NULL ) return -1; if( dvd->dev == NULL ) { /* No block access, so no UDF VolumeSet Identifier */ return -1; } if( (volid != NULL) && (volid_size > 0) ) { ret = UDFGetVolumeIdentifier(dvd, volid, volid_size); if(!ret) { return -1; } } if( (volsetid != NULL) && (volsetid_size > 0) ) { ret = UDFGetVolumeSetIdentifier(dvd, volsetid, volsetid_size); if(!ret) { return -1; } } return 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -