/* * This file is part of libudfread * Copyright (C) 2014-2015 VLC authors and VideoLAN * * Authors: Petri Hintukainen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see * . */ #if HAVE_CONFIG_H #include "config.h" #endif #include "ecma167.h" #include #include #include #include #define ecma_error(...) fprintf(stderr, "ecma: " __VA_ARGS__) /* * Part 1: General */ /* fixed-length dstring, ECMA 1/7.2.12 */ static uint8_t _decode_dstring(const uint8_t *p, size_t field_length, uint8_t *str) { size_t length; if (field_length < 1) { return 0; } field_length--; length = _get_u8(p + field_length); if (length > field_length) { length = field_length; } memcpy(str, p, length); return (uint8_t)length; } /* Extent Descriptor (ECMA 167, 3/7.1) */ static void _decode_extent_ad(const uint8_t *p, struct extent_ad *ad) { ad->length = _get_u32(p + 0); ad->lba = _get_u32(p + 4); } /* Entity Identifier (ECMA 167, 1/7.4) */ void decode_entity_id(const uint8_t *p, struct entity_id *eid) { memcpy(eid->identifier, p + 1, 23); memcpy(eid->identifier_suffix, p + 24, 8); } /* * Part 3: Volume Structure */ /* Descriptor Tag (ECMA 167, 3/7.2) */ enum tag_identifier decode_descriptor_tag(const uint8_t *buf) { uint16_t id; uint8_t checksum = 0; int i; id = _get_u16(buf + 0); /* descriptor tag is 16 bytes */ /* calculate tag checksum */ for (i = 0; i < 4; i++) { checksum = (uint8_t)(checksum + buf[i]); } for (i = 5; i < 16; i++) { checksum = (uint8_t)(checksum + buf[i]); } if (checksum != buf[4]) { return ECMA_TAG_NONE; } return (enum tag_identifier)id; } /* Primary Volume Descriptor (ECMA 167, 3/10.1) */ void decode_primary_volume(const uint8_t *p, struct primary_volume_descriptor *pvd) { pvd->volume_identifier_length = _decode_dstring(p + 24, 32, pvd->volume_identifier); memcpy(pvd->volume_set_identifier, p + 72, 128); } /* Anchor Volume Descriptor Pointer (ECMA 167 3/10.2) */ void decode_avdp(const uint8_t *p, struct anchor_volume_descriptor *avdp) { /* Main volume descriptor sequence extent */ _decode_extent_ad(p + 16, &avdp->mvds); /* Reserve (backup) volume descriptor sequence extent */ _decode_extent_ad(p + 24, &avdp->rvds); } /* Volume Descriptor Pointer (ECMA 167 3/10.3) */ void decode_vdp(const uint8_t *p, struct volume_descriptor_pointer *vdp) { _decode_extent_ad(p + 20, &vdp->next_extent); } /* Partition Descriptor (ECMA 167 3/10.5) */ void decode_partition(const uint8_t *p, struct partition_descriptor *pd) { pd->number = _get_u16(p + 22); pd->start_block = _get_u32(p + 188); pd->num_blocks = _get_u32(p + 192); } /* Logical Volume Descriptor (ECMA 167 3/10.6) */ void decode_logical_volume(const uint8_t *p, struct logical_volume_descriptor *lvd) { size_t map_size; lvd->block_size = _get_u32(p + 212); decode_entity_id(p + 216, &lvd->domain_id); memcpy(lvd->contents_use, p + 248, 16); lvd->partition_map_lable_length = _get_u32(p + 264); lvd->num_partition_maps = _get_u32(p + 268); /* XXX cut long maps */ map_size = lvd->partition_map_lable_length; if (map_size > sizeof(lvd->partition_map_table)) { map_size = sizeof(lvd->partition_map_table); } /* input size is one block (2048 bytes) */ if (map_size > 2048 - 440) { map_size = 2048 - 440; } memcpy(lvd->partition_map_table, p + 440, map_size); } /* * Part 4: File Structure */ /* File Set Descriptor (ECMA 167 4/14.1) */ void decode_file_set_descriptor(const uint8_t *p, struct file_set_descriptor *fsd) { decode_long_ad(p + 400, &fsd->root_icb); } /* File Identifier (ECMA 167 4/14.4) */ size_t decode_file_identifier(const uint8_t *p, size_t size, struct file_identifier *fi) { size_t l_iu; /* length of implementation use field */ if (size < 38) { ecma_error("not enough data\n"); return 0; } fi->characteristic = _get_u8(p + 18); fi->filename_len = _get_u8(p + 19); decode_long_ad(p + 20, &fi->icb); l_iu = _get_u16(p + 36); if (size < 38 + l_iu + fi->filename_len) { ecma_error("not enough data\n"); return 0; } if (fi->filename_len) { memcpy(fi->filename, p + 38 + l_iu, fi->filename_len); } fi->filename[fi->filename_len] = 0; /* ECMA 167, 4/14.4 * padding size 4 * ip((L_FI+L_IU+38+3)/4) - (L_FI+L_IU+38) * => padded to dwords */ return 4 * ((38 + (size_t)fi->filename_len + l_iu + 3) / 4); } /* ICB Tag (ECMA 167 4/14.6) */ struct icb_tag { uint8_t file_type; uint16_t strategy_type; uint16_t flags; }; static void _decode_icb_tag(const uint8_t *p, struct icb_tag *tag) { tag->strategy_type = _get_u16(p + 4); tag->file_type = _get_u8 (p + 11); tag->flags = _get_u16(p + 18); } /* Allocation Descriptors */ #define AD_LENGTH_MASK 0x3fffffff #define AD_TYPE(length) ((length) >> 30) /* Short Allocation Descriptor (ECMA 167, 4/14.14.1) */ static void _decode_short_ad(const uint8_t *buf, uint16_t partition, struct long_ad *ad) { uint32_t u32 = _get_u32(buf + 0); ad->extent_type = AD_TYPE(u32); ad->length = u32 & AD_LENGTH_MASK; ad->lba = _get_u32(buf + 4); ad->partition = partition; } /* Long Allocation Descriptor (ECMA 167, 4/14.14.2) */ void decode_long_ad(const uint8_t *buf, struct long_ad *ad) { uint32_t u32 = _get_u32(buf + 0); ad->extent_type = AD_TYPE(u32); ad->length = u32 & AD_LENGTH_MASK; ad->lba = _get_u32(buf + 4); ad->partition = _get_u16(buf + 8); } /* Exrtended Allocation Descriptor (ECMA 167, 4/14.14.3) */ static void _decode_extended_ad(const uint8_t *buf, struct long_ad *ad) { uint32_t u32 = _get_u32(buf + 0); ad->extent_type = AD_TYPE(u32); ad->length = u32 & AD_LENGTH_MASK; ad->lba = _get_u32(buf + 12); ad->partition = _get_u16(buf + 16); } /* File Entry */ static void _decode_file_ads(const uint8_t *p, int ad_type, uint16_t partition, struct long_ad *ad, unsigned num_ad) { uint32_t i; for (i = 0; i < num_ad; i++) { switch (ad_type) { case 0: _decode_short_ad(p, partition, &ad[i]); p += 8; break; case 1: decode_long_ad(p, &ad[i]); p += 16; break; case 2: _decode_extended_ad(p, &ad[i]); p += 20; break; } } } static struct file_entry *_decode_file_entry(const uint8_t *p, size_t size, uint16_t partition, uint32_t l_ad, uint32_t p_ad) { struct file_entry *fe; struct icb_tag tag; uint32_t num_ad; int content_inline = 0; if (p_ad + l_ad > size) { ecma_error("not enough data in file entry\n"); return NULL; } _decode_icb_tag(p + 16, &tag); if (tag.strategy_type != 4) { /* UDF (2.): only ICB strategy types 4 and 4096 shall be recorded */ ecma_error("unsupported icb strategy type %d\n", tag.strategy_type); return NULL; } switch (tag.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; case 3: num_ad = 0; content_inline = 1; break; default: ecma_error("unsupported icb flags: 0x%x\n", tag.flags); return NULL; } if (num_ad < 1) { fe = (struct file_entry *)calloc(1, sizeof(struct file_entry) + l_ad); } else { fe = (struct file_entry *)calloc(1, sizeof(struct file_entry) + sizeof(struct long_ad) * (num_ad - 1)); } if (!fe) { return NULL; } fe->file_type = tag.file_type; fe->length = _get_u64(p + 56); fe->ad_type = tag.flags & 7; if (content_inline) { /* data of small files can be embedded in file entry */ /* copy embedded file data */ fe->content_inline = 1; fe->u.data.information_length = l_ad; memcpy(fe->u.data.content, p + p_ad, l_ad); } else { fe->u.ads.num_ad = num_ad; _decode_file_ads(p + p_ad, fe->ad_type, partition, &fe->u.ads.ad[0], num_ad); } 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->ad_type) { 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: return -1; } if (num_ad < 1) { ecma_error("decode_allocation_extent: empty allocation extent\n"); return 0; } fe = (struct file_entry *)realloc(*p_fe, sizeof(struct file_entry) + sizeof(struct long_ad) * (fe->u.ads.num_ad + num_ad)); if (!fe) { return -1; } *p_fe = fe; /* decode new allocation descriptors */ _decode_file_ads(p + 24, fe->ad_type, partition, &fe->u.ads.ad[fe->u.ads.num_ad], num_ad); fe->u.ads.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) { uint32_t l_ea, l_ad; l_ea = _get_u32(p + 168); l_ad = _get_u32(p + 172); /* check for integer overflow */ if ((uint64_t)l_ea + (uint64_t)l_ad + (uint64_t)176 >= (uint64_t)1<<32) { ecma_error("invalid file entry\n"); return NULL; } return _decode_file_entry(p, size, partition, l_ad, 176 + l_ea); } /* Extended File Entry (ECMA 167, 4/14.17) */ struct file_entry *decode_ext_file_entry(const uint8_t *p, size_t size, uint16_t partition) { uint32_t l_ea, l_ad; l_ea = _get_u32(p + 208); l_ad = _get_u32(p + 212); /* check for integer overflow */ if ((uint64_t)l_ea + (uint64_t)l_ad + (uint64_t)216 >= (uint64_t)1<<32) { ecma_error("invalid file entry\n"); return NULL; } return _decode_file_entry(p, size, partition, l_ad, 216 + l_ea); } void free_file_entry(struct file_entry **p_fe) { if (p_fe) { free(*p_fe); *p_fe = NULL; } }