/* @(#)udf.c 1.14 04/04/15 Copyright 2001 J. Schilling */
#ifndef lint
static char sccsid[] =
"@(#)udf.c 1.14 04/04/15 Copyright 2001 J. Schilling";
#endif
/*
* udf.c - UDF support for mkisofs
*
* Written by Ben Rudiak-Gould (2001).
*
* Copyright 2001 J. Schilling.
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; see the file COPYING. If not, write to the Free Software
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* Some remaining issues:
*
* - Do not forget to edit joliet.c and remove the VIDEO_TS lines after
* we did implement a decent own file name handling for UDF.
*
* - UDF supports UNIX-style file permissions and uid/gid, but currently
* this code just sets them to default values and ignores their Rock
* Ridge counterparts. This would be easy to fix.
*
* - There's no support for symlinks, Mac type/creator, or Mac resource
* forks. Hard links and followed symlinks may work, but if so, it's
* only by accident.
*
* - The file system mirrors the Joliet file system, so files excluded
* from Joliet will also be excluded from UDF, the -jcharset option
* also applies to UDF, file names too long for Joliet will also be
* truncated on UDF, and characters not allowed by Joliet will also
* be translated on UDF. (Fortunately, Joliet is pretty lenient.)
*
* - convert_to_unicode is always called with in_nls, not hfs_nls. This
* may lead to incorrect name conversion sometimes when using a Mac
* filesystem. See joliet.c for an example of what's supposed to be
* done.
*
* - DVD-Video discs are supposed to have Copyright Management Information
* in both the ISO and UDF filesystems. This is not implemented in ISO,
* and the code to do it in UDF is currently #ifdef'd out. I'm not sure
* whether discs without this information are actually DVD-Video
* compliant. The Copyright Management Information is described in ECMA
* Technical Report TR/71.
*
* - Most of the space before sector 256 on the disc (~480K) is wasted,
* because UDF Bridge requires a pointer block at sector 256. ISO 9660
* structures could be moved below sector 256 if they're small enough, but
* this would be ugly to implement since it breaks the output_fragment
* abstraction.
*
* - Each file must have a File Entry, and each File Entry seems to
* require its own 2K sector. As a result, there is an overhead of more
* than 2K *per file* when using UDF. I couldn't see any way to avoid
* this.
*
* - Read performance would probably be improved by placing the File Entry
* for each file just before the file itself, instead of at the beginning
* of the disc. But this would not work for DVD-Video files, which have
* to be stored contiguously. So there would have to be an override
* mechanism to handle this case. I don't know if it's worth the trouble.
*/
#ifdef UDF
#include "config.h"
#include "mkisofs.h"
#include <timedefs.h>
#include <schily.h>
#include "udf.h"
#include "udf_fs.h"
extern int use_sparcboot;
extern struct directory *root;
extern time_t begun;
static unsigned lba_main_seq;
static unsigned lba_main_seq_copy;
static unsigned lba_integ_seq;
static unsigned lba_udf_partition_start;
static unsigned lba_last_file_entry;
static unsigned lba_end_anchor_vol_desc;
static unsigned num_udf_files;
static unsigned num_udf_directories;
static unsigned volume_set_id[2];
#define UDF_MAIN_SEQ_LENGTH (16)
#define UDF_INTEG_SEQ_LENGTH (2)
/* only works for granularity a power of 2! */
#define PAD(val, granularity) (((val)+(granularity)-1)&~((granularity)-1))
#define read_733(field) ((0[field]&255)+(1[field]&255)*256+(2[field]&255)*65536+(3[field]&255)*16777216)
/**************** SIZE ****************/
static int set_file_ident_desc __PR((unsigned char *, unsigned, char *, int, unsigned, unsigned));
static unsigned
#ifdef PROTOTYPES
directory_size(struct directory *dpnt)
#else
directory_size(dpnt)
struct directory *dpnt;
#endif
{
unsigned size_in_bytes;
struct directory_entry *de;
Uchar dummy_buf[SECTOR_SIZE];
/* parent directory */
size_in_bytes = set_file_ident_desc(dummy_buf, 0, 0, 0, 0, 0);
/* directory contents */
for (de = dpnt->jcontents; de; de = de->jnext) {
if (!(de->de_flags & INHIBIT_JOLIET_ENTRY)) {
char *name = USE_MAC_NAME(de) ? de->hfs_ent->name : de->name;
/* skip . and .. */
if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0)))
continue;
size_in_bytes += set_file_ident_desc(dummy_buf, 0, name, 0, 0, 0);
}
}
return (size_in_bytes);
}
static void
#ifdef PROTOTYPES
assign_udf_directory_addresses(struct directory *dpnt)
#else
assign_udf_directory_addresses(dpnt)
struct directory *dpnt;
#endif
{
if (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY)) {
dpnt->self->udf_file_entry_sector = last_extent;
last_extent += 1 + ISO_BLOCKS(directory_size(dpnt));
++num_udf_directories;
}
if (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir) {
for (dpnt = dpnt->subdir; dpnt; dpnt = dpnt->next) {
assign_udf_directory_addresses(dpnt);
}
}
}
static void
#ifdef PROTOTYPES
assign_udf_file_entry_addresses(struct directory *dpnt)
#else
assign_udf_file_entry_addresses(dpnt)
struct directory *dpnt;
#endif
{
if (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY)) {
struct directory_entry *de;
for (de = dpnt->jcontents; de; de = de->jnext) {
if (!(de->de_flags & RELOCATED_DIRECTORY) &&
!(de->isorec.flags[0] & ISO_DIRECTORY)) {
de->udf_file_entry_sector = last_extent++;
++num_udf_files;
}
}
}
if (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir) {
for (dpnt = dpnt->subdir; dpnt; dpnt = dpnt->next) {
assign_udf_file_entry_addresses(dpnt);
}
}
}
/****************************/
static int
#ifdef PROTOTYPES
udf_vol_recognition_area_size(int starting_extent)
#else
udf_vol_recognition_area_size(starting_extent)
int starting_extent;
#endif
{
last_extent = starting_extent+3;
return (0);
}
static int
#ifdef PROTOTYPES
udf_main_seq_size(int starting_extent)
#else
udf_main_seq_size(starting_extent)
int starting_extent;
#endif
{
lba_main_seq = starting_extent;
last_extent = starting_extent + UDF_MAIN_SEQ_LENGTH;
return (0);
}
static int
#ifdef PROTOTYPES
udf_main_seq_copy_size(int starting_extent)
#else
udf_main_seq_copy_size(starting_extent)
int starting_extent;
#endif
{
lba_main_seq_copy = starting_extent;
last_extent = starting_extent + UDF_MAIN_SEQ_LENGTH;
return (0);
}
static int
#ifdef PROTOTYPES
udf_integ_seq_size(int starting_extent)
#else
udf_integ_seq_size(starting_extent)
int starting_extent;
#endif
{
lba_integ_seq = starting_extent;
last_extent = starting_extent + UDF_INTEG_SEQ_LENGTH;
return (0);
}
static int
#ifdef PROTOTYPES
udf_end_anchor_vol_desc_size(int starting_extent)
#else
udf_end_anchor_vol_desc_size(starting_extent)
int starting_extent;
#endif
{
lba_end_anchor_vol_desc = starting_extent;
last_extent = starting_extent+1;
return (0);
}
static int
#ifdef PROTOTYPES
udf_file_set_desc_size(int starting_extent)
#else
udf_file_set_desc_size(starting_extent)
int starting_extent;
#endif
{
lba_udf_partition_start = starting_extent;
last_extent = starting_extent+2;
return (0);
}
static int
#ifdef PROTOTYPES
udf_dirtree_size(int starting_extent)
#else
udf_dirtree_size(starting_extent)
int starting_extent;
#endif
{
num_udf_directories = 0;
assign_udf_directory_addresses(root);
return (0);
}
static int
#ifdef PROTOTYPES
udf_file_entries_size(int starting_extent)
#else
udf_file_entries_size(starting_extent)
int starting_extent;
#endif
{
num_udf_files = 0;
assign_udf_file_entry_addresses(root);
lba_last_file_entry = last_extent-1;
return (0);
}
static int
#ifdef PROTOTYPES
udf_pad_to_sector_32_size(int starting_extent)
#else
udf_pad_to_sector_32_size(starting_extent)
int starting_extent;
#endif
{
if (last_extent < session_start+32)
last_extent = session_start+32;
return (0);
}
static int
#ifdef PROTOTYPES
udf_pad_to_sector_256_size(int starting_extent)
#else
udf_pad_to_sector_256_size(starting_extent)
int starting_extent;
#endif
{
if (last_extent < session_start+256)
last_extent = session_start+256;
return (0);
}
static int
#ifdef PROTOTYPES
udf_padend_avdp_size(int starting_extent)
#else
udf_padend_avdp_size(starting_extent)
int starting_extent;
#endif
{
lba_end_anchor_vol_desc = starting_extent;
/* add at least 16 and at most 31 sectors, ending at a mult. of 16 */
last_extent = (starting_extent+31) & ~15;
if (!use_sparcboot)
last_extent = starting_extent + 150;
return (0);
}
extern int oneblock_size __PR((int));
/**************** WRITE ****************/
static unsigned
#ifdef PROTOTYPES
crc_ccitt(unsigned char *buf, unsigned len)
#else
crc_ccitt(buf, len)
unsigned char *buf;
unsigned len;
#endif
{
const unsigned poly = 0x11021;
static unsigned short lookup[256];
unsigned int r;
unsigned int i;
if (lookup[1] == 0) {
unsigned int j, k;
for (j = 0; j < 256; ++j) {
unsigned int temp = j << 8;
for (k = 0; k < 8; ++k) {
unsigned int hibit = temp & 32768;
temp <<= 1;
if (hibit)
temp ^= poly;
}
lookup[j] = temp;
}
}
r = 0;
for (i = 0; i < len; ++i) {
r = (r << 8) ^ lookup[((r >> 8) ^ buf[i]) & 255];
}
return (r & 65535);
}
#define set8(dst, src) do { *(dst) = (src); } while (0)
static void
#ifdef PROTOTYPES
set16(udf_Uint16 *dst, unsigned int src)
#else
set16(dst, src)
udf_Uint16 *dst;
unsigned int src;
#endif
{
dst->l = (char)(src);
dst->h = (char)(src>>8);
}
static void
#ifdef PROTOTYPES
set32(udf_Uint32 *dst, unsigned src)
#else
set32(dst, src)
udf_Uint32 *dst;
unsigned src;
#endif
{
dst->l = (char)(src);
dst->ml = (char)(src>>8);
dst->mh = (char)(src>>16);
dst->h = (char)(src>>24);
}
static void
#ifdef PROTOTYPES
set64(udf_Uint64 *dst, unsigned src)
#else
set64(dst, src)
udf_Uint64 *dst;
unsigned src;
#endif
{
set32(&dst->l, src);
/*
* src>>32 actually does the wrong thing on x86 with at least
* one compiler, because of x86's shift count masking. Since
* we never pass more than 32 sig. bits to the function anyway,
* and all the structures we fill in are zeroed beforehand,
* just skip setting the high word.
*/
/*set32(&dst->h, src>>32);*/
}
static int
#ifdef PROTOTYPES
set_ostaunicode(unsigned char *dst, int dst_size, char *src)
#else
set_ostaunicode(dst, dst_size, src)
unsigned char *dst;
int dst_size;
char *src;
#endif
{
unsigned char buf[1024];
int i;
int expanded_length;
expanded_length = joliet_strlen(src);
if (expanded_length > 1024)
expanded_length = 1024;
if (expanded_length > (dst_size-1)*2)
expanded_length = (dst_size-1)*2;
convert_to_unicode(buf, expanded_length, src, in_nls);
dst[0] = 8; /* use 8-bit representation by default */
for (i = 0; i < (expanded_length>>1); ++i) {
dst[i + 1] = buf[i*2+1];
if (buf[i*2] != 0) {
/*
* There's a Unicode character with value >=256.
* Use 16-bit representation instead.
*/
int length_to_copy = (dst_size-1) & ~1;
if (length_to_copy > expanded_length)
length_to_copy = expanded_length;
dst[0] = 16;
memcpy(dst+1, buf, length_to_copy);
return (length_to_copy + 1);
}
}
return ((expanded_length>>1) + 1);
}
static void
#ifdef PROTOTYPES
set_extent(udf_extent_ad *ext, unsigned lba, unsigned length_bytes)
#else
set_extent(ext, lba, length_bytes)
udf_extent_ad *ext;
unsigned lba;
unsigned length_bytes;
#endif
{
set32(&ext->extent_length, length_bytes);
set32(&ext->extent_location, lba);
}
static void
#ifdef PROTOTYPES
set_dstring(udf_dstring *dst, char *src, int n)
#else
set_dstring(dst, src, n)
udf_dstring *dst;
char *src;
int n;
#endif
{
dst[n-1] = set_ostaunicode((Uchar *)dst, n-1, src);
}
static void
#ifdef PROTOTYPES
set_charspec(udf_charspec *dst)
#else
set_charspec(dst)
udf_charspec *dst;
#endif
{
/*set8(&dst->character_set_type, 0);*/
memcpy(dst->character_set_info, "OSTA Compressed Unicode", 23);
}
static void
#ifdef PROTOTYPES
set_impl_ident(udf_EntityID *ent)
#else
set_impl_ident(ent)
udf_EntityID *ent;
#endif
{
strcpy((char *)ent->ident, "*mkisofs");
}
static void
#ifdef PROTOTYPES
set_tag(udf_tag *t, unsigned tid, unsigned lba, int crc_length)
#else
set_tag(t, tid, lba, crc_length)
udf_tag *t;
unsigned tid;
unsigned lba;
int crc_length;
#endif
{
unsigned char checksum;
int i;
set16(&t->tag_ident, tid);
set16(&t->desc_version, 2);
set16(&t->desc_crc, crc_ccitt((unsigned char *)t+16, crc_length-16));
set16(&t->desc_crc_length, crc_length-16);
set32(&t->tag_location, lba);
set8(&t->tag_checksum, 0);
checksum = 0;
for (i = 0; i < 16; ++i)
checksum += ((unsigned char *)t)[i];
set8(&t->tag_checksum, checksum);
}
static void
#ifdef PROTOTYPES
set_timestamp_from_iso_date(udf_timestamp *ts, const char *iso_date_raw)
#else
set_timestamp_from_iso_date(ts, iso_date_raw)
udf_timestamp *ts;
const char *iso_date_raw;
#endif
{
struct {
unsigned char years_since_1900;
unsigned char month, day;
unsigned char hour, minute, second;
signed char offset_from_gmt;
} *iso_date = (void *)iso_date_raw;
set16(&ts->type_and_time_zone,
4096 + ((iso_date->offset_from_gmt * 15) & 4095));
set16(&ts->year, 1900 + iso_date->years_since_1900);
set8(&ts->month, iso_date->month);
set8(&ts->day, iso_date->day);
set8(&ts->hour, iso_date->hour);
set8(&ts->minute, iso_date->minute);
set8(&ts->second, iso_date->second);
/*set8(&ts->centiseconds, 0);*/
/*set8(&ts->hundreds_of_microseconds, 0);*/
/*set8(&ts->microseconds, 0);*/
}
static void
#ifdef PROTOTYPES
set_timestamp_from_time_t(udf_timestamp *ts, time_t t)
#else
set_timestamp_from_time_t(ts, t)
udf_timestamp *ts;
time_t t;
#endif
{
char iso_date[7];
iso9660_date(iso_date, t);
set_timestamp_from_iso_date(ts, iso_date);
}
static void
#ifdef PROTOTYPES
set_anchor_volume_desc_pointer(unsigned char *buf, unsigned lba)
#else
set_anchor_volume_desc_pointer(buf, lba)
unsigned char *buf;
unsigned lba;
#endif
{
udf_anchor_volume_desc_ptr *avdp = (udf_anchor_volume_desc_ptr *)buf;
set_extent(&avdp->main_volume_desc_seq_extent,
lba_main_seq, SECTOR_SIZE*UDF_MAIN_SEQ_LENGTH);
set_extent(&avdp->reserve_volume_desc_seq_extent,
lba_main_seq_copy, SECTOR_SIZE*UDF_MAIN_SEQ_LENGTH);
set_tag(&avdp->desc_tag, UDF_TAGID_ANCHOR_VOLUME_DESC_PTR, lba, 512);
}
static void
#ifdef PROTOTYPES
set_primary_vol_desc(unsigned char *buf, unsigned lba)
#else
set_primary_vol_desc(buf, lba)
unsigned char *buf;
unsigned lba;
#endif
{
char temp[17];
udf_primary_volume_desc *pvd = (udf_primary_volume_desc *)buf;
/*set32(&pvd->volume_desc_seq_number, 0);*/
/*set32(&pvd->primary_volume_desc_number, 0);*/
set_dstring(pvd->volume_ident, volume_id, sizeof (pvd->volume_ident));
set16(&pvd->volume_seq_number, 1);
set16(&pvd->maximum_volume_seq_number, 1);
set16(&pvd->interchange_level, 2);
set16(&pvd->maximum_interchange_level, 2);
set32(&pvd->character_set_list, 1);
set32(&pvd->maximum_character_set_list, 1);
sprintf(temp, "%08X%08X", volume_set_id[0], volume_set_id[1]);
set_dstring(pvd->volume_set_ident, temp,
sizeof (pvd->volume_set_ident));
set_charspec(&pvd->desc_character_set);
set_charspec(&pvd->explanatory_character_set);
/*pvd->volume_abstract;*/
/*pvd->volume_copyright_notice;*/
/*pvd->application_ident;*/
set_timestamp_from_time_t(&pvd->recording_date_and_time, begun);
set_impl_ident(&pvd->impl_ident);
set_tag(&pvd->desc_tag, UDF_TAGID_PRIMARY_VOLUME_DESC, lba, 512);
}
static void
#ifdef PROTOTYPES
set_impl_use_vol_desc(unsigned char *buf, unsigned lba)
#else
set_impl_use_vol_desc(buf, lba)
unsigned char *buf;
unsigned lba;
#endif
{
udf_impl_use_volume_desc *iuvd = (udf_impl_use_volume_desc *)buf;
set32(&iuvd->volume_desc_seq_number, 1);
strcpy((char *)iuvd->impl_ident.ident, "*UDF LV Info");
iuvd->impl_ident.ident_suffix[0] = 2;
iuvd->impl_ident.ident_suffix[1] = 1;
set_charspec(&iuvd->impl_use.lvi_charset);
set_dstring(iuvd->impl_use.logical_volume_ident, volume_id,
sizeof (iuvd->impl_use.logical_volume_ident));
/*set_dstring(iuvd->impl_use.lv_info1, "", sizeof (iuvd->impl_use.lv_info1));*/
/*set_dstring(iuvd->impl_use.lv_info2, "", sizeof (iuvd->impl_use.lv_info2));*/
/*set_dstring(iuvd->impl_use.lv_info3, "", sizeof (iuvd->impl_use.lv_info3));*/
set_impl_ident(&iuvd->impl_use.impl_id);
set_tag(&iuvd->desc_tag, UDF_TAGID_IMPL_USE_VOLUME_DESC, lba, 512);
}
static void
#ifdef PROTOTYPES
set_partition_desc(unsigned char *buf, unsigned lba)
#else
set_partition_desc(buf, lba)
unsigned char *buf;
unsigned lba;
#endif
{
udf_partition_desc *pd = (udf_partition_desc *)buf;
set32(&pd->volume_desc_seq_number, 2);
set16(&pd->partition_flags, UDF_PARTITION_FLAG_ALLOCATED);
/*set16(&pd->partition_number, 0);*/
set8(&pd->partition_contents.flags, UDF_ENTITYID_FLAG_PROTECTED); /*???*/
strcpy((char *)pd->partition_contents.ident, "+NSR02");
set32(&pd->access_type, UDF_ACCESSTYPE_READONLY);
set32(&pd->partition_starting_location, lba_udf_partition_start);
set32(&pd->partition_length,
lba_end_anchor_vol_desc - lba_udf_partition_start);
set_impl_ident(&pd->impl_ident);
set_tag(&pd->desc_tag, UDF_TAGID_PARTITION_DESC, lba, 512);
}
static void
#ifdef PROTOTYPES
set_domain_ident(udf_EntityID *ent)
#else
set_domain_ident(ent)
udf_EntityID *ent;
#endif
{
strcpy((char *)ent->ident, "*OSTA UDF Compliant");
memcpy(ent->ident_suffix, "\002\001\003", 3);
}
static void
#ifdef PROTOTYPES
set_logical_vol_desc(unsigned char *buf, unsigned lba)
#else
set_logical_vol_desc(buf, lba)
unsigned char *buf;
unsigned lba;
#endif
{
udf_logical_volume_desc *lvd = (udf_logical_volume_desc *)buf;
set32(&lvd->volume_desc_seq_number, 3);
set_charspec(&lvd->desc_character_set);
set_dstring(lvd->logical_volume_ident, volume_id,
sizeof (lvd->logical_volume_ident));
set32(&lvd->logical_block_size, SECTOR_SIZE);
set_domain_ident(&lvd->domain_ident);
set32(&lvd->logical_volume_contents_use.extent_length, 2*SECTOR_SIZE);
/*set32(&lvd->logical_volume_contents_use.extent_location.logical_block_number, 0);*/
/*set16(&lvd->logical_volume_contents_use.extent_location.partition_reference_number, 0);*/
set32(&lvd->map_table_length, 6);
set32(&lvd->number_of_partition_maps, 1);
set_impl_ident(&lvd->impl_ident);
set_extent(&lvd->integrity_seq_extent, lba_integ_seq,
SECTOR_SIZE*UDF_INTEG_SEQ_LENGTH);
set8(&lvd->partition_map[0].partition_map_type,
UDF_PARTITION_MAP_TYPE_1);
set8(&lvd->partition_map[0].partition_map_length, 6);
set16(&lvd->partition_map[0].volume_seq_number, 1);
/*set16(&lvd->partition_map[0].partition_number, 0);*/
set_tag(&lvd->desc_tag, UDF_TAGID_LOGICAL_VOLUME_DESC, lba, 446);
}
static void
#ifdef PROTOTYPES
set_unallocated_space_desc(unsigned char *buf, unsigned lba)
#else
set_unallocated_space_desc(buf, lba)
unsigned char *buf;
unsigned lba;
#endif
{
udf_unallocated_space_desc *usd = (udf_unallocated_space_desc *)buf;
set32(&usd->volume_desc_seq_number, 4);
/*set32(&usd->number_of_allocation_descs, 0);*/
set_tag(&usd->desc_tag, UDF_TAGID_UNALLOCATED_SPACE_DESC, lba, 24);
}
static void
#ifdef PROTOTYPES
set_terminating_desc(unsigned char *buf, unsigned lba)
#else
set_terminating_desc(buf, lba)
unsigned char *buf;
unsigned lba;
#endif
{
udf_terminating_desc *td = (udf_terminating_desc *)buf;
set_tag(&td->desc_tag, UDF_TAGID_TERMINATING_DESC, lba, 512);
}
static void
#ifdef PROTOTYPES
set_logical_vol_integrity_desc(unsigned char *buf, unsigned lba)
#else
set_logical_vol_integrity_desc(buf, lba)
unsigned char *buf;
unsigned lba;
#endif
{
udf_logical_volume_integrity_desc *lvid =
(udf_logical_volume_integrity_desc *)buf;
set_timestamp_from_time_t(&lvid->recording_date, begun);
set32(&lvid->integrity_type, UDF_INTEGRITY_TYPE_CLOSE);
/*lvid->next_integrity_extent;*/
set64(&lvid->logical_volume_contents_use.unique_id,
lba_last_file_entry+1);
set32(&lvid->number_of_partitions, 1);
set32(&lvid->length_of_impl_use, 46);
/*set32(&lvid->free_space_table, 0);*/
set32(&lvid->size_table,
lba_end_anchor_vol_desc - lba_udf_partition_start);
set_impl_ident(&lvid->impl_use.impl_id);
set32(&lvid->impl_use.number_of_files, num_udf_files);
set32(&lvid->impl_use.number_of_directories, num_udf_directories);
set16(&lvid->impl_use.minimum_udf_read_revision, 0x102);
set16(&lvid->impl_use.minimum_udf_write_revision, 0x102);
set16(&lvid->impl_use.maximum_udf_write_revision, 0x102);
set_tag(&lvid->desc_tag, UDF_TAGID_LOGICAL_VOLUME_INTEGRITY_DESC,
lba, 88+46);
}
static void
#ifdef PROTOTYPES
set_file_set_desc(unsigned char *buf, unsigned rba)
#else
set_file_set_desc(buf, rba)
unsigned char *buf;
unsigned rba;
#endif
{
udf_file_set_desc *fsd = (udf_file_set_desc *)buf;
set_timestamp_from_time_t(&fsd->recording_date_and_time, begun);
set16(&fsd->interchange_level, 3);
set16(&fsd->maximum_interchange_level, 3);
set32(&fsd->character_set_list, 1);
set32(&fsd->maximum_character_set_list, 1);
/*set32(&fsd->file_set_number, 0);*/
/*set32(&fsd->file_set_desc_number, 0);*/
set_charspec(&fsd->logical_volume_ident_character_set);
set_dstring(fsd->logical_volume_ident, volume_id,
sizeof (fsd->logical_volume_ident));
set_charspec(&fsd->file_set_character_set);
set_dstring(fsd->file_set_ident, volume_id,
sizeof (fsd->file_set_ident));
/*fsd->copyright_file_ident;*/
/*fsd->abstract_file_ident;*/
set32(&fsd->root_directory_icb.extent_length, SECTOR_SIZE);
set32(&fsd->root_directory_icb.extent_location.logical_block_number,
root->self->udf_file_entry_sector - lba_udf_partition_start);
set_domain_ident(&fsd->domain_ident);
/*fsd->next_extent;*/
set_tag(&fsd->desc_tag, UDF_TAGID_FILE_SET_DESC, rba, 512);
}
static int
#ifdef PROTOTYPES
set_file_ident_desc(unsigned char *buf, unsigned rba, char *name, int is_directory, unsigned file_entry_rba, unsigned unique_id)
#else
set_file_ident_desc(buf, rba, name, is_directory, file_entry_rba, unique_id)
unsigned char *buf;
unsigned rba;
char *name;
int is_directory;
unsigned file_entry_rba;
unsigned unique_id;
#endif
{
udf_file_ident_desc *fid = (udf_file_ident_desc *)buf;
int length_of_file_ident, length, padded_length;
set16(&fid->file_version_number, 1);
set8(&fid->file_characteristics,
(is_directory ? UDF_FILE_CHARACTERISTIC_DIRECTORY : 0)
+ (name == 0) * UDF_FILE_CHARACTERISTIC_PARENT);
set32(&fid->icb.extent_length, SECTOR_SIZE);
set32(&fid->icb.extent_location.logical_block_number, file_entry_rba);
set16(&fid->icb.extent_location.partition_reference_number, 0);
set32(&fid->icb.impl_use.unique_id, unique_id);
set16(&fid->length_of_impl_use, 0);
if (name) {
length_of_file_ident =
set_ostaunicode((Uchar *)fid->file_ident, 512, name);
} else {
length_of_file_ident = 0;
}
set8(&fid->length_of_file_ident, length_of_file_ident);
length = 38 + length_of_file_ident;
padded_length = PAD(length, 4);
while (length < padded_length) {
buf[length++] = 0;
}
set_tag(&fid->desc_tag, UDF_TAGID_FILE_IDENT_DESC, rba, length);
return (length);
}
static void
#ifdef PROTOTYPES
set_file_entry(unsigned char *buf,
unsigned rba,
unsigned file_rba,
unsigned length,
const char *iso_date,
int is_directory,
unsigned link_count,
unsigned unique_id)
#else
set_file_entry(buf, rba, file_rba, length, iso_date, is_directory, link_count, unique_id)
unsigned char *buf;
unsigned rba;
unsigned file_rba;
unsigned length;
const char *iso_date;
int is_directory;
unsigned link_count;
unsigned unique_id;
#endif
{
udf_short_ad *allocation_desc;
unsigned chunk;
udf_file_entry *fe = (udf_file_entry *)buf;
/*set32(&fe->icb_tag.prior_recorded_number_of_direct_entries, 0);*/
set16(&fe->icb_tag.strategy_type, 4);
/*set16(&fe->icb_tag.strategy_parameter, 0);*/
set16(&fe->icb_tag.maximum_number_of_entries, 1);
set8(&fe->icb_tag.file_type, is_directory
? UDF_ICBTAG_FILETYPE_DIRECTORY : UDF_ICBTAG_FILETYPE_BYTESEQ);
/*fe->icb_tag.parent_icb_location;*/
set16(&fe->icb_tag.flags, UDF_ICBTAG_FLAG_NONRELOCATABLE
| UDF_ICBTAG_FLAG_ARCHIVE | UDF_ICBTAG_FLAG_CONTIGUOUS);
if (rationalize_uid)
set32(&fe->uid, uid_to_use);
else
set32(&fe->uid, -1);
if (rationalize_gid)
set32(&fe->gid, gid_to_use);
else
set32(&fe->gid, -1);
if (is_directory) {
set32(&fe->permissions,
UDF_FILEENTRY_PERMISSION_OR | UDF_FILEENTRY_PERMISSION_OX |
UDF_FILEENTRY_PERMISSION_GR | UDF_FILEENTRY_PERMISSION_GX |
UDF_FILEENTRY_PERMISSION_UR | UDF_FILEENTRY_PERMISSION_UX);
} else {
set32(&fe->permissions, UDF_FILEENTRY_PERMISSION_OR
| UDF_FILEENTRY_PERMISSION_GR | UDF_FILEENTRY_PERMISSION_UR);
}
set16(&fe->file_link_count, link_count);
/*fe->record_format;*/
/*fe->record_display_attributes;*/
/*fe->record_length;*/
set64(&fe->info_length, length);
set64(&fe->logical_blocks_recorded, ISO_BLOCKS(length));
if (iso_date) {
set_timestamp_from_iso_date(&fe->access_time, iso_date);
fe->modification_time = fe->access_time;
fe->attribute_time = fe->access_time;
}
set32(&fe->checkpoint, 1);
/*fe->ext_attribute_icb;*/
set_impl_ident(&fe->impl_ident);
set64(&fe->unique_id, unique_id);
/*
* Extended attributes that may (?) be required for DVD-Video
* compliance
*/
#if 0
set32(&fe->length_of_ext_attributes, 24+52+56);
set32(&fe->ext_attribute_header.impl_attributes_location, 24);
set32(&fe->ext_attribute_header.application_attributes_location,
24+52+56);
set_tag(&fe->ext_attribute_header.desc_tag,
UDF_TAGID_EXT_ATTRIBUTE_HEADER_DESC, rba, 24 /*???*/);
set32(&fe->ext_attribute_free_ea_space.attribute_type, SECTOR_SIZE);
set8(&fe->ext_attribute_free_ea_space.attribute_subtype, 1);
set32(&fe->ext_attribute_free_ea_space.attribute_length, 52);
set32(&fe->ext_attribute_free_ea_space.impl_use_length, 4);
strcpy((char *)fe->ext_attribute_free_ea_space.impl_ident.ident,
"*UDF FreeAppEASpace");
set32(&fe->ext_attribute_dvd_cgms_info.attribute_type, SECTOR_SIZE);
set8(&fe->ext_attribute_dvd_cgms_info.attribute_subtype, 1);
set32(&fe->ext_attribute_dvd_cgms_info.attribute_length, 56);
set32(&fe->ext_attribute_dvd_cgms_info.impl_use_length, 8);
strcpy((char *)fe->ext_attribute_free_ea_space.impl_ident.ident,
"*UDF DVD CGMS Info");
fe->ext_attribute_free_ea_space.impl_ident.ident_suffix[0] = 2;
fe->ext_attribute_free_ea_space.impl_ident.ident_suffix[1] = 1;
#else
/*set32(&fe->length_of_ext_attributes, 0);*/
#endif
allocation_desc = &fe->allocation_desc;
/*
* Only a file size less than 1GB can be expressed by a single
* AllocationDescriptor. When the size of a file is larger than 1GB,
* 2 or more AllocationDescriptors should be used. We don't know
* whether a singl 8-byte AllocationDescriptor should be written or no
* one should be written if the size of a file is 0 byte. - FIXME.
*
* XXX We get called with buf[2048]. This allows a max. file size of
* XXX 234 GB. With more we would cause a buffer overflow.
* XXX We need to check whether UDF would allow files > 234 GB.
*/
for (; length > 0; length -= chunk) {
chunk = (length > 0x3ffff800) ? 0x3ffff800 : length;
set32(&allocation_desc->extent_length, chunk);
set32(&allocation_desc->extent_position, file_rba);
file_rba += chunk >> 11;
allocation_desc++;
}
set32(&fe->length_of_allocation_descs,
(unsigned char *) allocation_desc -
(unsigned char *) &fe->allocation_desc);
set_tag(&fe->desc_tag, UDF_TAGID_FILE_ENTRY, rba,
(unsigned char *) allocation_desc - buf);
}
static unsigned
#ifdef PROTOTYPES
directory_link_count(struct directory *dpnt)
#else
directory_link_count(dpnt)
struct directory *dpnt;
#endif
{
/*
* The link count is equal to 1 (for the parent) plus the
* number of subdirectories.
*/
unsigned link_count = 1;
struct directory_entry *de;
/* count relocated subdirectories */
for (de = dpnt->jcontents; de; de = de->jnext) {
if ((de->de_flags &
(INHIBIT_JOLIET_ENTRY | RELOCATED_DIRECTORY)) ==
RELOCATED_DIRECTORY) {
link_count++;
}
}
/* count ordinary subdirectories */
for (dpnt = dpnt->subdir; dpnt; dpnt = dpnt->next) {
if (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY)) {
link_count++;
}
}
return (link_count);
}
static void
#ifdef PROTOTYPES
write_one_udf_directory(struct directory *dpnt, FILE *outfile)
#else
write_one_udf_directory(dpnt, outfile)
struct directory *dpnt;
FILE *outfile;
#endif
{
unsigned size_in_bytes, padded_size_in_bytes;
struct directory_entry *de;
unsigned ident_size;
unsigned base_sector;
struct directory *parent;
Uchar buf[SECTOR_SIZE];
memset(buf, 0, SECTOR_SIZE);
set_file_entry(
buf,
last_extent_written - lba_udf_partition_start,
last_extent_written+1 - lba_udf_partition_start,
directory_size(dpnt),
dpnt->self->isorec.date,
1, /* is_directory */
directory_link_count(dpnt),
(dpnt == root) ? 0 : dpnt->self->udf_file_entry_sector);
xfwrite(buf, SECTOR_SIZE, 1, outfile, 0, FALSE);
last_extent_written++;
base_sector = last_extent_written - lba_udf_partition_start;
/* parent directory */
parent = dpnt->parent;
if (parent == reloc_dir) {
parent = dpnt->self->parent_rec->filedir;
}
ident_size = set_file_ident_desc(
buf,
base_sector,
0,
1,
parent->self->udf_file_entry_sector - lba_udf_partition_start,
(parent == root) ? 0 : parent->self->udf_file_entry_sector);
xfwrite(buf, ident_size, 1, outfile, 0, FALSE);
size_in_bytes = ident_size;
/* directory contents */
for (de = dpnt->jcontents; de; de = de->jnext) {
char *name;
struct directory_entry *de1;
if (de->de_flags & INHIBIT_JOLIET_ENTRY)
continue;
name = USE_MAC_NAME(de) ? de->hfs_ent->name : de->name;
/* skip . and .. */
if (name[0] == '.' && (name[1] == 0 ||
(name[1] == '.' && name[2] == 0)))
continue;
/* look in RR_MOVED for relocated directories */
de1 = de;
if (de->de_flags & RELOCATED_DIRECTORY) {
for (de1 = reloc_dir->contents; de1; de1 = de1->next) {
if (de1->parent_rec == de) {
break;
}
}
if (!de1) {
#ifdef USE_LIBSCHILY
comerrno(EX_BAD,
"Unable to locate relocated directory\n");
#else
fprintf(stderr,
"Unable to locate relocated directory\n");
exit(1);
#endif
}
}
ident_size = set_file_ident_desc(
buf,
base_sector + (size_in_bytes / SECTOR_SIZE),
name,
!!(de1->isorec.flags[0] & ISO_DIRECTORY),
de1->udf_file_entry_sector - lba_udf_partition_start,
de1->udf_file_entry_sector);
xfwrite(buf, ident_size, 1, outfile, 0, FALSE);
size_in_bytes += ident_size;
}
padded_size_in_bytes = PAD(size_in_bytes, SECTOR_SIZE);
if (size_in_bytes < padded_size_in_bytes) {
memset(buf, 0, padded_size_in_bytes - size_in_bytes);
xfwrite(buf, padded_size_in_bytes - size_in_bytes, 1, outfile, 0, FALSE);
}
last_extent_written += padded_size_in_bytes / SECTOR_SIZE;
}
static void
#ifdef PROTOTYPES
write_udf_directories(struct directory *dpnt, FILE *outfile)
#else
write_udf_directories(dpnt, outfile)
struct directory *dpnt;
FILE *outfile;
#endif
{
if (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY)) {
write_one_udf_directory(dpnt, outfile);
}
if (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir) {
for (dpnt = dpnt->subdir; dpnt; dpnt = dpnt->next) {
write_udf_directories(dpnt, outfile);
}
}
}
static void
#ifdef PROTOTYPES
write_udf_file_entries(struct directory *dpnt, FILE *outfile)
#else
write_udf_file_entries(dpnt, outfile)
struct directory *dpnt;
FILE *outfile;
#endif
{
Uchar buf[SECTOR_SIZE];
memset(buf, 0, SECTOR_SIZE);
if (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY)) {
struct directory_entry *de;
for (de = dpnt->jcontents; de; de = de->jnext) {
if (!(de->de_flags & RELOCATED_DIRECTORY) &&
!(de->isorec.flags[0] & ISO_DIRECTORY)) {
memset(buf, 0, 512);
set_file_entry(
buf,
(last_extent_written++) - lba_udf_partition_start,
read_733(de->isorec.extent) - lba_udf_partition_start,
read_733(de->isorec.size),
de->isorec.date,
0, /* is_directory */
1, /* link_count */
de->udf_file_entry_sector);
xfwrite(buf, SECTOR_SIZE, 1, outfile, 0, FALSE);
}
}
}
if (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir) {
for (dpnt = dpnt->subdir; dpnt; dpnt = dpnt->next) {
write_udf_file_entries(dpnt, outfile);
}
}
}
/****************************/
static int
#ifdef PROTOTYPES
udf_vol_recognition_area_write(FILE *out)
#else
udf_vol_recognition_area_write(out)
FILE *out;
#endif
{
static const char *identifiers[3] = { "BEA01", "NSR02", "TEA01" };
int i;
char buf[SECTOR_SIZE];
udf_volume_recognition_desc *vsd = (udf_volume_recognition_desc *)buf;
memset(buf, 0, sizeof (buf));
/*set8(&vsd->structure_type, 0);*/
set8(&vsd->structure_version, 1);
for (i = 0; i < 3; ++i) {
memcpy(vsd->standard_identifier, identifiers[i], 5);
xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
}
last_extent_written += 3;
return (0);
}
static int
#ifdef PROTOTYPES
udf_main_seq_write(FILE *out)
#else
udf_main_seq_write(out)
FILE *out;
#endif
{
Uchar buf[SECTOR_SIZE];
int i;
/*
* volume_set_id needs to be set to a (64-bit) "unique" number.
* This will have to do for now.
*/
volume_set_id[0] = begun;
volume_set_id[1] = (unsigned)clock(); /* XXX Maybe non-portable */
memset(buf, 0, sizeof (buf));
set_primary_vol_desc(buf, last_extent_written++);
xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
memset(buf, 0, sizeof (buf));
set_impl_use_vol_desc(buf, last_extent_written++);
xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
memset(buf, 0, sizeof (buf));
set_partition_desc(buf, last_extent_written++);
xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
memset(buf, 0, sizeof (buf));
set_logical_vol_desc(buf, last_extent_written++);
xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
memset(buf, 0, sizeof (buf));
set_unallocated_space_desc(buf, last_extent_written++);
xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
memset(buf, 0, sizeof (buf));
set_terminating_desc(buf, last_extent_written++);
xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
memset(buf, 0, sizeof (buf));
for (i = 6; i < UDF_MAIN_SEQ_LENGTH; ++i) {
xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
last_extent_written++;
}
return (0);
}
static int
#ifdef PROTOTYPES
udf_integ_seq_write(FILE *out)
#else
udf_integ_seq_write(out)
FILE *out;
#endif
{
Uchar buf[SECTOR_SIZE*UDF_INTEG_SEQ_LENGTH];
memset(buf, 0, sizeof (buf));
set_logical_vol_integrity_desc(buf+0*SECTOR_SIZE,
last_extent_written++);
set_terminating_desc(buf+1*SECTOR_SIZE, last_extent_written++);
xfwrite(buf, SECTOR_SIZE, UDF_INTEG_SEQ_LENGTH, out, 0, FALSE);
return (0);
}
static int
#ifdef PROTOTYPES
udf_anchor_vol_desc_write(FILE *out)
#else
udf_anchor_vol_desc_write(out)
FILE *out;
#endif
{
Uchar buf[SECTOR_SIZE];
memset(buf, 0, sizeof (buf));
set_anchor_volume_desc_pointer(buf, last_extent_written++);
xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
return (0);
}
static int
#ifdef PROTOTYPES
udf_file_set_desc_write(FILE *out)
#else
udf_file_set_desc_write(out)
FILE *out;
#endif
{
Uchar buf[SECTOR_SIZE*2];
memset(buf, 0, sizeof (buf));
set_file_set_desc(buf+0*SECTOR_SIZE,
(last_extent_written++) - lba_udf_partition_start);
set_terminating_desc(buf+1*SECTOR_SIZE,
(last_extent_written++) - lba_udf_partition_start);
xfwrite(buf, SECTOR_SIZE, 2, out, 0, FALSE);
return (0);
}
static int
#ifdef PROTOTYPES
udf_dirtree_write(FILE *out)
#else
udf_dirtree_write(out)
FILE *out;
#endif
{
write_udf_directories(root, out);
return (0);
}
static int
#ifdef PROTOTYPES
udf_file_entries_write(FILE *out)
#else
udf_file_entries_write(out)
FILE *out;
#endif
{
write_udf_file_entries(root, out);
return (0);
}
static int
#ifdef PROTOTYPES
pad_to(unsigned last_extent_to_write, FILE *out)
#else
pad_to(last_extent_to_write, out)
unsigned last_extent_to_write;
FILE *out;
#endif
{
char buf[SECTOR_SIZE];
memset(buf, 0, sizeof (buf));
while (last_extent_written < last_extent_to_write) {
xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
++last_extent_written;
}
return (0);
}
static int
#ifdef PROTOTYPES
udf_pad_to_sector_32_write(FILE *out)
#else
udf_pad_to_sector_32_write(out)
FILE *out;
#endif
{
return (pad_to(session_start+32, out));
}
static int
#ifdef PROTOTYPES
udf_pad_to_sector_256_write(FILE *out)
#else
udf_pad_to_sector_256_write(out)
FILE *out;
#endif
{
return (pad_to(session_start+256, out));
}
static int
#ifdef PROTOTYPES
udf_padend_avdp_write(FILE *out)
#else
udf_padend_avdp_write(out)
FILE *out;
#endif
{
Uchar buf[SECTOR_SIZE];
unsigned last_extent_to_write = (last_extent_written+31) & ~15;
if (!use_sparcboot)
last_extent_to_write = last_extent_written + 150;
memset(buf, 0, sizeof (buf));
while (last_extent_written < last_extent_to_write) {
set_anchor_volume_desc_pointer(buf, last_extent_written++);
xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
}
return (0);
}
struct output_fragment udf_vol_recognition_area_frag = { NULL, udf_vol_recognition_area_size, NULL, udf_vol_recognition_area_write, "UDF volume recognition area" };
struct output_fragment udf_main_seq_frag = { NULL, udf_main_seq_size, NULL, udf_main_seq_write, "UDF main seq" };
struct output_fragment udf_main_seq_copy_frag = { NULL, udf_main_seq_copy_size, NULL, udf_main_seq_write, "UDF second seq" };
struct output_fragment udf_integ_seq_frag = { NULL, udf_integ_seq_size, NULL, udf_integ_seq_write, "UDF integ seq" };
struct output_fragment udf_anchor_vol_desc_frag = { NULL, oneblock_size, NULL, udf_anchor_vol_desc_write, "UDF Anchor volume" };
struct output_fragment udf_file_set_desc_frag = { NULL, udf_file_set_desc_size, NULL, udf_file_set_desc_write, "UDF file set" };
struct output_fragment udf_dirtree_frag = { NULL, udf_dirtree_size, NULL, udf_dirtree_write, "UDF directory tree" };
struct output_fragment udf_file_entries_frag = { NULL, udf_file_entries_size, NULL, udf_file_entries_write, "UDF file entries" };
struct output_fragment udf_end_anchor_vol_desc_frag = { NULL, udf_end_anchor_vol_desc_size, NULL, udf_anchor_vol_desc_write, "UDF Anchor end volume" };
struct output_fragment udf_pad_to_sector_32_frag = { NULL, udf_pad_to_sector_32_size, NULL, udf_pad_to_sector_32_write, "UDF pad to sector 32" };
struct output_fragment udf_pad_to_sector_256_frag = { NULL, udf_pad_to_sector_256_size, NULL, udf_pad_to_sector_256_write, "UDF pad to sector 256" };
struct output_fragment udf_padend_avdp_frag = { NULL, udf_padend_avdp_size, NULL, udf_padend_avdp_write, "UDF Pad end" };
/*
* This function assigns weights as follows:
*
* /VIDEO_TS/VIDEO_TS.IFO 11199
* /VIDEO_TS/VIDEO_TS.VOB 11198
* /VIDEO_TS/VIDEO_TS.BUP 11188
* /VIDEO_TS/VTS_01_0.IFO 11187
* /VIDEO_TS/VTS_01_0.VOB 11186
* : :
* /VIDEO_TS/VTS_01_9.VOB 11177
* /VIDEO_TS/VTS_01_0.BUP 11176
* : :
* /VIDEO_TS/VTS_99_0.BUP 10000
*
* This ensures that DVD-Video files are laid out properly on the disc.
* The same thing is done for AUDIO_TS files, except in the 20000 range
* instead of the 10000 range.
*
* Question: what about JACKET_P files?
*
* Answer: At least as far as I know :)
* JACKET_P files are still images (single frame mpeg video .i.e mp2
* format). The DVD Jacket pictures will be displayed on the TV screen
* when the player is in a stop/resume mode.
* The location is not dependent on IFO information and the only must
* as far as I know is that they are in upper case (both dir and files).
* This sparce information makes me conclude that they don't need any
* weight. This obviously needs to be tested.
*/
int
#ifdef PROTOTYPES
assign_dvd_weights(char *name, struct directory *this_dir, int val)
#else
assign_dvd_weights(name, this_dir, val)
char *name;
struct directory *this_dir;
int val;
#endif
{
int ts_number;
int segment;
int audio;
if (name[0] != 'A' && name[0] != 'V')
return (val);
if (memcmp(name, "VIDEO_TS", 8) == 0) {
ts_number = 0;
audio = 0;
} else if (memcmp(name, "VTS_", 4) == 0) {
ts_number = 1;
audio = 0;
} else if (memcmp(name, "AUDIO_TS", 8) == 0) {
ts_number = 0;
audio = 1;
} else if (memcmp(name, "ATS_", 4) == 0) {
ts_number = 1;
audio = 1;
} else {
return (val);
}
if (this_dir->parent != root ||
strcmp(this_dir->de_name, "VIDEO_TS") != 0)
return (val);
if (ts_number == 0) {
segment = 0;
} else {
if (name[4] >= '0' && name[4] <= '9' &&
name[5] >= '0' && name[5] <= '9' &&
name[6] == '_' &&
name[7] >= '0' && name[7] <= '9') {
ts_number = name[4] * 10 + name[5] - ('0' * 11);
segment = name[7] - '0';
} else {
return (val);
}
}
if (strcmp(name+8, audio ? ".AOB" : ".VOB") == 0) {
return (audio * 10000 - ts_number * 12 - segment + 11198);
} else if (strcmp(name+8, ".IFO") == 0) {
return (audio * 10000 - ts_number * 12 + 11199);
} else if (strcmp(name+8, ".BUP") == 0) {
return (audio * 10000 - ts_number * 12 + 11188);
} else {
return (val);
}
}
#endif /* UDF */
syntax highlighted by Code2HTML, v. 0.9.1