/*
* This file is part of libudfread
* Copyright (C) 2014-2015 VLC authors and VideoLAN
*
* Authors: Petri Hintukainen <phintuka@users.sourceforge.net>
*
* 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
* <http://www.gnu.org/licenses/>.
*/
#ifndef UDFREAD_ECMA167_H_
#define UDFREAD_ECMA167_H_
#include <stdint.h> /* *int_t */
#include <stddef.h> /* size_t */
/*
* Minimal implementation of ECMA-167:
* Volume and File Structure for Write-Once and Rewritable
* Media using Non-Sequential Recording for Information Interchange
*
* Based on 3rd Edition, June 1997
* http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-167.pdf
*
*/
/*
* Part 1: General
*/
/* Numerical Values (ECMA 167, 1/7.1) */
static inline uint32_t _get_u8(const uint8_t *p)
{
return (uint32_t)p[0];
}
static inline uint32_t _get_u16(const uint8_t *p)
{
return _get_u8(p) | (_get_u8(p + 1) << 8);
}
static inline uint32_t _get_u32(const uint8_t *p)
{
return _get_u16(p) | (_get_u16(p + 2) << 16);
}
static inline uint64_t _get_u64(const uint8_t *p)
{
return (uint64_t)_get_u32(p) | ((uint64_t)_get_u32(p + 4) << 32);
}
/* Entity Identifier (ECMA 167, 1/7.4) */
struct entity_id {
uint8_t identifier[23];
uint8_t identifier_suffix[8];
};
void decode_entity_id(const uint8_t *p, struct entity_id *eid);
/*
* Part 3: Volume Structure
*/
/* Extent Descriptor (ECMA 167, 3/7.1) */
struct extent_ad {
uint32_t lba;
uint32_t length; /* in bytes */
};
/* Descriptor Tag (ECMA 167, 3/7.2) */
enum tag_identifier {
/* ECMA 167, 3/7.2.1) */
ECMA_PrimaryVolumeDescriptor = 1,
ECMA_AnchorVolumeDescriptorPointer = 2,
ECMA_VolumeDescriptorPointer = 3,
ECMA_PartitionDescriptor = 5,
ECMA_LogicalVolumeDescriptor = 6,
ECMA_TerminatingDescriptor = 8,
/* ECMA 167, 4/7.2.1 */
ECMA_FileSetDescriptor = 256,
ECMA_FileIdentifierDescriptor = 257,
ECMA_AllocationExtentDescriptor = 258,
ECMA_FileEntry = 261,
ECMA_ExtendedFileEntry = 266,
ECMA_TAG_NONE = -1,
};
enum tag_identifier decode_descriptor_tag(const uint8_t *buf);
/* Primary Volume Descriptor (ECMA 167, 3/10.1) */
struct primary_volume_descriptor {
uint8_t volume_identifier[31];
uint8_t volume_identifier_length;
uint8_t volume_set_identifier[128];
};
void decode_primary_volume(const uint8_t *p, struct primary_volume_descriptor *pvd);
/* Anchor Volume Descriptor (ECMA 167, 3/10.2) */
struct anchor_volume_descriptor {
struct extent_ad mvds; /* Main Volume Descriptor Sequence extent */
struct extent_ad rvds; /* Reserve Volume Descriptor Sequence extent */
};
void decode_avdp(const uint8_t *p, struct anchor_volume_descriptor *avdp);
/* Volume Descriptor Pointer (ECMA 167, 3/10.3) */
struct volume_descriptor_pointer {
struct extent_ad next_extent; /* Next Volume Descriptor Sequence Extent */
};
void decode_vdp(const uint8_t *p, struct volume_descriptor_pointer *vdp);
/* Partition Descriptor (ECMA 167, 3/10.5) */
struct partition_descriptor {
uint16_t number;
uint32_t start_block;
uint32_t num_blocks;
};
void decode_partition(const uint8_t *p, struct partition_descriptor *pd);
/* Logical Volume Descriptor (ECMA 167, 3/10.6) */
struct logical_volume_descriptor {
uint32_t block_size;
struct entity_id domain_id;
uint8_t contents_use[16];
uint32_t num_partition_maps;
uint32_t partition_map_lable_length;
uint8_t partition_map_table[2048];
};
void decode_logical_volume(const uint8_t *p, struct logical_volume_descriptor *lvd);
/*
* Part 4: File Structure
*/
enum {
ECMA_AD_EXTENT_NORMAL = 0, /* allocated and recorded file data */
ECMA_AD_EXTENT_NOT_RECORDED = 1,
ECMA_AD_EXTENT_NOT_ALLOCATED = 2,
ECMA_AD_EXTENT_AD = 3, /* pointer to next extent of allocation descriptors */
};
/* Short/Long/Extended Allocation Descriptor (ECMA 167, 4/14.14.[1,2,3]) */
struct long_ad {
uint32_t lba; /* start block, relative to partition start */
uint32_t length; /* in bytes */
uint16_t partition;
uint8_t extent_type;
};
void decode_long_ad(const uint8_t *p, struct long_ad *ad);
/* File Set Descriptor (ECMA 167 4/14.1) */
struct file_set_descriptor {
struct long_ad root_icb;
};
void decode_file_set_descriptor(const uint8_t *p, struct file_set_descriptor *fsd);
/* File Identifier (ECMA 167 4/14.4) */
enum {
CHAR_FLAG_HIDDEN = 0x01,
CHAR_FLAG_DIR = 0x02,
CHAR_FLAG_DELETED = 0x04,
CHAR_FLAG_PARENT = 0x08,
};
struct file_identifier {
struct long_ad icb;
uint8_t characteristic; /* CHAR_FLAG_* */
uint8_t filename_len;
uint8_t filename[256];
};
size_t decode_file_identifier(const uint8_t *p, size_t size, struct file_identifier *fi);
/* File Entry (ECMA 167, 4/14.9) */
/* Extended File Entry (ECMA 167, 4/14.17) */
enum {
/* ECMA 167, 14.6.6 File Type */
ECMA_FT_UNSPECIFIED = 0,
ECMA_FT_INDIRECT = 3,
ECMA_FT_DIR = 4,
ECMA_FT_BYTESTREAM = 5, /* random-access byte stream - regular file - udf 2.60, 2.3.5.2 */
ECMA_FT_TERMINAL_ENTRY = 11,
ECMA_FT_SYMLINK = 12,
};
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 ad_type; /* from icb_flags; used when parsing allocation extents */
union {
/* "normal" file */
struct {
uint32_t num_ad;
struct long_ad ad[1]; /* Most files have only single extent, files in 3D BDs can have 100+. */
} ads;
/* inline file */
struct {
uint32_t information_length; /* recorded information length, may be different than file length */
uint8_t content[1]; /* content of small files is embedded here */
} data;
} u;
};
struct file_entry *decode_file_entry (const uint8_t *p, size_t size, uint16_t partition);
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_ */