Commit f6abda4e authored by Petri Hintukainen's avatar Petri Hintukainen

Handle allocation extents

(fixes issues with large 3D BluRay .m2ts/.ssif files)
parent 83029949
......@@ -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)
{
......
......@@ -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_ */
......@@ -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;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment