libudfread | branch: master | Petri Hintukainen <[email protected]> | Tue Jan 24 22:50:12 2017 +0200| [f6abda4e725d606e91d15b001edca3f9f095e255] | committer: Petri Hintukainen
Handle allocation extents (fixes issues with large 3D BluRay .m2ts/.ssif files) > http://git.videolan.org/gitweb.cgi/libudfread.git/?a=commit;h=f6abda4e725d606e91d15b001edca3f9f095e255 --- src/ecma167.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/ecma167.h | 3 +++ src/udfread.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/src/ecma167.c b/src/ecma167.c index e25fa3d..814e7af 100644 --- a/src/ecma167.c +++ b/src/ecma167.c @@ -302,6 +302,7 @@ static struct file_entry *_decode_file_entry(const uint8_t *p, size_t size, fe->file_type = tag.file_type; fe->length = _get_u64(p + 56); fe->num_ad = num_ad; + fe->icb_flags = tag.flags; if (content_inline) { /* data of small files can be embedded in file entry */ @@ -315,6 +316,50 @@ static struct file_entry *_decode_file_entry(const uint8_t *p, size_t size, return fe; } +int decode_allocation_extent(struct file_entry **p_fe, const uint8_t *p, size_t size, uint16_t partition) +{ + struct file_entry *fe = *p_fe; + uint32_t l_ad, num_ad; + + l_ad = _get_u32(p + 20); + if (size < 24 || size - 24 < l_ad) { + ecma_error("decode_allocation_extent: invalid allocation extent (l_ad)\n"); + return -1; + } + + switch (fe->icb_flags & 7) { + case 0: num_ad = l_ad / 8; break; + case 1: num_ad = l_ad / 16; break; + case 2: num_ad = l_ad / 20; break; + default: + ecma_error("decode_allocation_extent: unsupported icb flags 0x%x\n", fe->icb_flags); + return -1; + } + + if (num_ad < 1) { + ecma_error("decode_allocation_extent: empty allocation extent\n"); + return 0; + } + + fe = (struct file_entry *)realloc(fe, sizeof(struct file_entry) + sizeof(struct long_ad) * (fe->num_ad + num_ad - 1)); + if (!fe) { + return -1; + } + *p_fe = fe; + + /* drop pointer to this extent from the end of ads */ + if (fe->data.ad[fe->num_ad - 1].extent_type != ECMA_AD_EXTENT_AD) { + ecma_error("decode_allocation_extent: missing link ad\n"); + } + fe->num_ad--; + + /* decode new allocation descriptors */ + _decode_file_ads(p + 24, fe->icb_flags, partition, &fe->data.ad[fe->num_ad], num_ad); + fe->num_ad += num_ad; + + return 0; +} + /* File Entry (ECMA 167, 4/14.9) */ struct file_entry *decode_file_entry(const uint8_t *p, size_t size, uint16_t partition) { diff --git a/src/ecma167.h b/src/ecma167.h index 9300255..f507893 100644 --- a/src/ecma167.h +++ b/src/ecma167.h @@ -94,6 +94,7 @@ enum tag_identifier { /* ECMA 167, 4/7.2.1 */ ECMA_FileSetDescriptor = 256, ECMA_FileIdentifierDescriptor = 257, + ECMA_AllocationExtentDescriptor = 258, ECMA_FileEntry = 261, ECMA_ExtendedFileEntry = 266, @@ -211,6 +212,7 @@ struct file_entry { uint64_t length; /* in bytes */ uint8_t file_type; /* ECMA_FT_* */ uint8_t content_inline; /* 1 if file data is embedded in file entry */ + uint8_t icb_flags; /* used when parsing allocation extents */ uint32_t num_ad; union { @@ -223,5 +225,6 @@ struct file_entry *decode_file_entry (const uint8_t *p, size_t size, uint16_t struct file_entry *decode_ext_file_entry(const uint8_t *p, size_t size, uint16_t partition); void free_file_entry (struct file_entry **p_fe); +int decode_allocation_extent(struct file_entry **p_fe, const uint8_t *p, size_t size, uint16_t partition); #endif /* UDFREAD_ECMA167_H_ */ diff --git a/src/udfread.c b/src/udfread.c index a7ce87d..0aadd0d 100644 --- a/src/udfread.c +++ b/src/udfread.c @@ -824,6 +824,39 @@ static struct file_entry *_read_file_entry(udfread *udf, } free(buf); + + /* read possible additional allocation extents */ + if (fe && fe->num_ad > 0) { + while (fe->data.ad[fe->num_ad - 1].extent_type == ECMA_AD_EXTENT_AD) { + + icb = &fe->data.ad[fe->num_ad - 1]; + udf_log("_read_file_entry: reading allocation extent @%u\n", icb->lba); + + buf = _read_metadata(udf, icb, &tag_id); + if (!buf) { + udf_error("_read_file_entry: reading allocation extent @%u failed\n", icb->lba); + break; + } + + if (tag_id != ECMA_AllocationExtentDescriptor) { + free(buf); + udf_error("_read_file_entry: unexpected tag %u (expected ECMA_AllocationExtentDescriptor)\n", tag_id); + break; + } + + if (decode_allocation_extent(&fe, buf, icb->length, icb->partition) < 0) { + free(buf); + udf_error("_read_file_entry: decode_allocation_extent() failed\n"); + break; + } + + /* failure before this point will cause an error when reading the file past extent point. + (extent ad is left in file ad list). */ + + free(buf); + } + } + return fe; } _______________________________________________ libbluray-devel mailing list [email protected] https://mailman.videolan.org/listinfo/libbluray-devel
