[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