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