[libbluray-devel] Handle allocation extents
Petri Hintukainen
git at videolan.org
Tue Jan 24 22:52:28 CET 2017
libudfread | branch: master | Petri Hintukainen <phintuka at gmail.com> | 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;
}
More information about the libbluray-devel
mailing list