static int UDFFileEntry( uint8_t *data, uint8_t *FileType, struct Partition *partition, struct AD *ad ) { uint16_t flags; uint32_t L_EA, L_AD; unsigned int p; UDFICB( &data[ 16 ], FileType, &flags ); /* Init ad for an empty file (i.e. there isn't a AD, L_AD == 0 ) */ ad->Length = GETN4( 60 ); /* Really 8 bytes a 56 */ ad->Flags = 0; ad->Location = 0; /* what should we put here? */ ad->Partition = partition->Number; /* use number of current partition */ L_EA = GETN4( 168 ); L_AD = GETN4( 172 ); if (176 + L_EA + L_AD > DVD_VIDEO_LB_LEN) return 0; p = 176 + L_EA; while( p < 176 + L_EA + L_AD ) { switch( flags & 0x0007 ) { case 0: UDFShortAD( &data[ p ], ad, partition ); p += 8; break; case 1: UDFLongAD( &data[ p ], ad ); p += 16; break; case 2: UDFExtAD( &data[ p ], ad ); p += 20; break; case 3: switch( L_AD ) { case 8: UDFShortAD( &data[ p ], ad, partition ); break; case 16: UDFLongAD( &data[ p ], ad ); break; case 20: UDFExtAD( &data[ p ], ad ); break; } p += L_AD; break; default: p += L_AD; break; } } return 0; }
static int UDFAD( quint8 *ptr, quint32 len, struct FileAD *fad) { struct AD *ad; if (fad->num_AD >= UDF_MAX_AD_CHAINS) return len; ad = &fad->AD_chain[fad->num_AD]; ad->Partition = fad->Partition; ad->Flags = 0; fad->num_AD++; switch( fad->Flags & 0x0007 ) { case 0: UDFShortAD( ptr, ad ); return 8; case 1: UDFLongAD( ptr, ad ); return 16; case 2: UDFExtAD( ptr, ad ); return 20; case 3: switch( len ) { case 8: UDFShortAD( ptr, ad ); break; case 16: UDFLongAD( ptr, ad ); break; case 20: UDFExtAD( ptr, ad ); break; } break; default: break; } return len; }
static int UDFFileIdentifier( uint8_t *data, uint8_t *FileCharacteristics, char *FileName, struct AD *FileICB ) { uint8_t L_FI; uint16_t L_IU; *FileCharacteristics = GETN1(18); L_FI = GETN1(19); UDFLongAD(&data[20], FileICB); L_IU = GETN2(36); if (L_FI) Unicodedecode(&data[38 + L_IU], L_FI, FileName); else FileName[0] = '\0'; return 4 * ((38 + L_FI + L_IU + 3) / 4); }
static int UDFExtFileEntry(uint8_t *data, struct Partition *partition, struct AD *ad) { int nRet = -1; uint8_t FileType; uint16_t TagID; uint16_t flags; uint32_t L_EA, L_AD; unsigned int p; UDFDescriptor( data, &TagID ); if (TagID != 266) { //printf("Not ExtFileEntry!!!\n"); return nRet; } UDFICB( &data[ 16 ], &FileType, &flags ); ad->Length = GETN4( 60 ); /* Really 8 bytes a 56 */ ad->Flags = 0; ad->Location = 0; /* what should we put here? */ ad->Partition = partition->Number; /* use number of current partition */ L_EA = GETN4( 208 ); L_AD = GETN4( 212 ); if (216 + L_EA + L_AD > DVD_VIDEO_LB_LEN) return nRet; p = 216 + L_EA; while( p < 216 + L_EA + L_AD ) { switch( flags & 0x0007 ) { case 0: UDFShortAD( &data[ p ], ad, partition ); p += 8; break; case 1: UDFLongAD( &data[ p ], ad ); p += 16; break; default: p += L_AD; break; } } return nRet; }
uint32_t UDFFindFile( dvd_reader_t *device, char *filename, uint32_t *filesize ) { uint8_t LogBlock_base[ DVD_VIDEO_LB_LEN + 2048 ]; uint8_t *LogBlock = (uint8_t *)(((uintptr_t)LogBlock_base & ~((uintptr_t)2047)) + 2048); uint32_t lbnum; uint16_t TagID; struct Partition partition; struct AD RootICB, File, ICB; char tokenline[ MAX_UDF_FILE_NAME_LEN ]; char *token; uint8_t filetype; *filesize = 0; tokenline[0] = '\0'; strncat(tokenline, filename, MAX_UDF_FILE_NAME_LEN - 1); memset(&ICB, 0, sizeof(ICB)); if(!(GetUDFCache(device, PartitionCache, 0, &partition) && GetUDFCache(device, RootICBCache, 0, &RootICB))) { /* Find partition, 0 is the standard location for DVD Video.*/ if( !UDFFindPartition( device, 0, &partition ) ) return 0; SetUDFCache(device, PartitionCache, 0, &partition); /* Find root dir ICB */ lbnum = partition.Start; do { if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) TagID = 0; else UDFDescriptor( LogBlock, &TagID ); /* File Set Descriptor */ if( TagID == 256 ) /* File Set Descriptor */ UDFLongAD( &LogBlock[ 400 ], &RootICB ); } while( ( lbnum < partition.Start + partition.Length ) && ( TagID != 8 ) && ( TagID != 256 ) ); /* Sanity checks. */ if( TagID != 256 ) return 0; if( RootICB.Partition != 0 ) return 0; SetUDFCache(device, RootICBCache, 0, &RootICB); } /* Find root dir */ if( !UDFMapICB( device, RootICB, &filetype, &partition, &File ) ) return 0; if( filetype != 4 ) return 0; /* Root dir should be dir */ { int cache_file_info = 0; /* Tokenize filepath */ token = strtok(tokenline, "/"); while( token != NULL ) { if( !UDFScanDir( device, File, token, &partition, &ICB, cache_file_info)) return 0; if( !UDFMapICB( device, ICB, &filetype, &partition, &File ) ) return 0; if(!strcmp(token, "VIDEO_TS")) cache_file_info = 1; token = strtok( NULL, "/" ); } } /* Sanity check. */ if( File.Partition != 0 ) return 0; *filesize = File.Length; /* Hack to not return partition.Start for empty files. */ if( !File.Location ) return 0; else return partition.Start + File.Location; }
static int UDFExtFileEntry( uint8_t *data, uint8_t *FileType, struct Partition *partition, struct AD *ad ) { uint16_t flags; uint32_t L_EA, L_AD; unsigned int p; struct AD temp_ad; int is_init = 0; memset((void *)&temp_ad, 0, sizeof(struct AD)); UDFICB( &data[ 16 ], FileType, &flags ); /* Init ad for an empty file (i.e. there isn't a AD, L_AD == 0 ) */ //ad->Length = GETN4( 60 ); /* Really 8 bytes a 56 */ ad->Length = 0; ad->Flags = 0; ad->Location = 0; /* what should we put here? */ ad->Partition = partition->Number; /* use number of current partition */ L_EA = GETN4( 208 ); L_AD = GETN4( 212 ); if (216 + L_EA + L_AD > DVD_VIDEO_LB_LEN) return 0; p = 216 + L_EA; while( p < 216 + L_EA + L_AD ) { switch( flags & 0x0007 ) { case 0: UDFShortAD( &data[ p ], &temp_ad, partition ); p += 8; break; case 1: UDFLongAD( &data[ p ], &temp_ad ); p += 16; break; case 2: UDFExtAD( &data[ p ], &temp_ad ); p += 20; break; case 3: switch( L_AD ) { case 8: UDFShortAD( &data[ p ], &temp_ad, partition ); break; case 16: UDFLongAD( &data[ p ], &temp_ad ); break; case 20: UDFExtAD( &data[ p ], &temp_ad ); break; } p += L_AD; break; default: p += L_AD; break; } if (is_init == 0) { memcpy((void *)ad, (void *)&temp_ad, sizeof(struct AD)); is_init = 1; } else { // only update file size ad->Length += temp_ad.Length; } } return 0; }
/** * Reads the volume descriptor and checks the parameters. Returns 0 on OK, 1 * on error. */ static int UDFLogVolume( uint8_t *data, struct Volume *vol) { uint32_t MT_L, N_PM, volume; uint32_t ii, type, length, pos; struct PartitionMaps *maps; volume = GETN4(16); Unicodedecode(&data[84], 128, vol->VolumeDesc); vol->BlockSize = GETN4(212); /* should be 2048 */ memset((void *)&vol->FSD, 0, sizeof(struct AD)); UDFLongAD(&data[248], &vol->FSD); //printf("File Set Descriptor: block: %d, part: %d\n", vol->FSD.Location, vol->FSD.Partition); MT_L = GETN4(264); /* should be 6 */ N_PM = GETN4(268); /* should be 1 */ vol->MapNum = N_PM; if ((N_PM >= 1) && (vol->Maps == NULL)) { vol->Maps = (struct PartitionMaps *)calloc(1, sizeof(struct PartitionMaps) * N_PM); } UDFExtentAD( &data[432], &vol->Length, &vol->Location); //printf("location: %d, length: %d\n", vol->Location, vol->Length); pos = 440; for (ii = 0; ii < N_PM; ii++) { maps = &vol->Maps[ii]; type = GETN1(pos); length = GETN1(pos+1); if (type == 1) { maps->MapType = UDF_TYPE1_MAP15; maps->VolSequenNum = GETN2(pos+2); maps->PartitionNum = GETN2(pos+4); } else if (type == 2) { struct EntityIdentifier ident; uint32_t version; UDFEntIdentifier(&data[pos+4], &ident); version = ((uint16_t)ident.indetifierSuffix[1] << 8) | (uint16_t)(ident.indetifierSuffix[0]); //printf("identifier: '%s', version: %04x\n", ident.identifier, version); if (strncmp(ident.identifier, UDF_ID_VIRTUAL, strlen(UDF_ID_VIRTUAL)) == 0) { if (version < 0x0200) maps->MapType = UDF_VIRTUAL_MAP15; else maps->MapType = UDF_VIRTUAL_MAP20; } else if (strncmp(ident.identifier, UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE)) == 0) { maps->MapType = UDF_SPARABLE_MAP15; } else if (strncmp(ident.identifier, UDF_ID_METADATA, strlen(UDF_ID_METADATA)) == 0) { maps->MapType = UDF_METADATA_MAP25; } maps->VolSequenNum = GETN2(pos+36); maps->PartitionNum = GETN2(pos+38); maps->mdata.meta_file_loc = GETN4(pos+40); maps->mdata.mirror_file_loc = GETN4(pos+44); maps->mdata.bitmap_file_loc = GETN4(pos+48); maps->mdata.alloc_unit_size = GETN4(pos+52); maps->mdata.alig_unit_size = GETN2(pos+56); maps->mdata.flags = data[pos+58]; //printf("meta_loc: %u, mirr_loc: %u, bit_loc: %u, alloc_unit: %u, alig_unit: %hu, flags: %hhu\n", maps->mdata.meta_file_loc, maps->mdata.mirror_file_loc, maps->mdata.bitmap_file_loc, maps->mdata.alloc_unit_size, maps->mdata.alig_unit_size, maps->mdata.flags); } //printf("Volume Sequence Number: %hu, Partition Number: %hu\n", maps->VolSequenNum, maps->PartitionNum); pos += length; } //printf("volume: %d, MT_L: %d, N_PM: %d\n", volume, MT_L, N_PM); if (vol->BlockSize != DVD_VIDEO_LB_LEN) return 1; return 0; }
uint32_t BDUDFDirFile( UDF_DIR *device, const char *filename) { uint8_t LogBlock_base[ DVD_VIDEO_LB_LEN + 2048 ]; uint8_t *LogBlock = (uint8_t *)(((uintptr_t)LogBlock_base & ~((uintptr_t)2047)) + 2048); uint32_t lbnum; uint16_t TagID; struct Partition partition; struct AD RootICB, File, ICB; char tokenline[ MAX_UDF_FILE_NAME_LEN ]; char *token; uint8_t filetype; tokenline[0] = '\0'; strncat(tokenline, filename, MAX_UDF_FILE_NAME_LEN - 1); memset(&ICB, 0, sizeof(struct AD)); memset(&File, 0, sizeof(struct AD)); memset(&RootICB, 0, sizeof(struct AD)); memset(&partition, 0, sizeof(struct Partition)); if(!(GetBDUDFCache(device->udf_data, PartitionCache, 0, &partition) && GetBDUDFCache(device->udf_data, RootICBCache, 0, &RootICB))) { /* Find partition, 0 is the standard location for DVD Video.*/ if( !UDFFindPartition( device->udf_data, 0, &partition ) ) { UDFFreePartition(&partition); return 0; } /* Find root dir ICB */ //lbnum = partition.Start; lbnum = UDFGetBlock(&partition, partition.vol.FSD.Partition, partition.vol.FSD.Location); do { if( DVDReadLBUDF( device->udf_data, lbnum++, 1, LogBlock, 0 ) <= 0 ) TagID = 0; else UDFDescriptor( LogBlock, &TagID ); /* File Set Descriptor */ if( TagID == 256 ) /* File Set Descriptor */ { UDFLongAD( &LogBlock[ 400 ], &RootICB ); partition.Number = RootICB.Partition; } } while( ( lbnum < partition.Start + partition.Length ) && ( TagID != 8 ) && ( TagID != 256 ) ); SetUDFCache(device->udf_data, PartitionCache, 0, &partition); /* Sanity checks. */ if( TagID != 256 ) return 0; //if( RootICB.Partition != 0 ) // return 0; SetUDFCache(device->udf_data, RootICBCache, 0, &RootICB); } /* Find root dir */ if( !UDFMapICB( device->udf_data, RootICB, &filetype, &partition, &File ) ) return 0; if( filetype != 4 ) return 0; /* Root dir should be dir */ { /* Tokenize filepath */ token = strtok(tokenline, "/"); while( token != NULL ) { if( !UDFScanDir( device->udf_data, File, token, &partition, &ICB, 0) ) return 0; //printf("icb: part: %u, block: %u\n", ICB.Partition, ICB.Location); if( !UDFMapICB( device->udf_data, ICB, &filetype, &partition, &File ) ) return 0; //printf("file: part: %u, block: %u\n", File.Partition, File.Location); token = strtok( NULL, "/" ); } if( UDFCacheDir( device, File, &partition, &ICB) ) { return 1; } } return 0; }
uint32_t UDFFindFile( dvd_reader_t *device, char *filename, uint32_t *filesize ) { uint8_t *LogBlock; uint32_t lbnum; uint16_t TagID; struct Partition partition; struct AD RootICB, File, ICB; char tokenline[ MAX_UDF_FILE_NAME_LEN ]; char *token; uint8_t filetype; if(filesize) { *filesize = 0; } tokenline[0] = '\0'; strcat( tokenline, filename ); if(!(GetUDFCache(device, PartitionCache, 0, &partition) && GetUDFCache(device, RootICBCache, 0, &RootICB))) { /* Find partition, 0 is the standard location for DVD Video.*/ if( !UDFFindPartition( device, 0, &partition ) ) { return 0; } SetUDFCache(device, PartitionCache, 0, &partition); LogBlock = dvdalign_lbmalloc(device, 1); if(!LogBlock) { return 0; } /* Find root dir ICB */ lbnum = partition.Start; do { if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) { TagID = 0; } else { UDFDescriptor( LogBlock, &TagID ); } /* File Set Descriptor */ if( TagID == 256 ) { // File Set Descriptor UDFLongAD( &LogBlock[ 400 ], &RootICB ); } } while( ( lbnum < partition.Start + partition.Length ) && ( TagID != 8 ) && ( TagID != 256 ) ); dvdalign_lbfree(device, LogBlock); /* Sanity checks. */ if( TagID != 256 ) { return 0; } if( RootICB.Partition != 0 ) { return 0; } SetUDFCache(device, RootICBCache, 0, &RootICB); } /* Find root dir */ if( !UDFMapICB( device, RootICB, &filetype, &partition, &File ) ) { return 0; } if( filetype != 4 ) { return 0; /* Root dir should be dir */ } { int cache_file_info = 0; /* Tokenize filepath */ token = strtok(tokenline, "/"); while( token != NULL ) { if( !UDFScanDir( device, File, token, &partition, &ICB, cache_file_info)) { return 0; } if( !UDFMapICB( device, ICB, &filetype, &partition, &File ) ) { return 0; } if(!strcmp(token, "VIDEO_TS")) { cache_file_info = 1; } token = strtok( NULL, "/" ); } } /* Sanity check. */ if( File.Partition != 0 ) { return 0; } if(filesize) { *filesize = File.Length; } /* Hack to not return partition.Start for empty files. */ if( !File.Location ) { return 0; } else { return partition.Start + File.Location; } }