Blame contrib/libudfread/src/ecma167.c

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