[iso] fix UDF UNICODE support

* libcdio's unicode16_decode() was not decoding labels at all,
  but simply stripping the MSB of the UDF USC-16 sequences
* use an actual conversion to UTF-8
* also update the rest of udf_fs.c to latest libcdio version
* closes #285
This commit is contained in:
Pete Batard 2014-02-17 21:41:48 +00:00
parent 167a877e9f
commit 60b68258dc
3 changed files with 180 additions and 146 deletions

View File

@ -113,7 +113,6 @@ FILE* fopen_utf8(const char* filename, const char* mode)
} }
#endif #endif
#ifdef HAVE_JOLIET
#ifdef HAVE_ICONV #ifdef HAVE_ICONV
#include <iconv.h> #include <iconv.h>
struct cdio_charset_coverter_s struct cdio_charset_coverter_s
@ -344,5 +343,3 @@ bool cdio_charset_to_utf8(const char *src, size_t src_len, cdio_utf8_t **dst,
return (*dst != NULL); return (*dst != NULL);
} }
#endif /* HAVE_ICONV */ #endif /* HAVE_ICONV */
#endif /* HAVE_JOLIET */

View File

@ -1,5 +1,5 @@
/* /*
Copyright (C) 2005, 2006, 2008, 2011 Rocky Bernstein <rocky@gnu.org> Copyright (C) 2005-2006, 2008, 2011, 2013 Rocky Bernstein <rocky@gnu.org>
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -59,7 +59,7 @@
#endif #endif
/* These definitions are also to make debugging easy. Note that they /* These definitions are also to make debugging easy. Note that they
have to come *before* #include <cdio/ecma_167.h> which sets have to come *before* #include <cdio/ecma_167.h> which sets
#defines for these. #defines for these.
*/ */
const char VSD_STD_ID_BEA01[] = {'B', 'E', 'A', '0', '1'}; const char VSD_STD_ID_BEA01[] = {'B', 'E', 'A', '0', '1'};
@ -70,6 +70,9 @@ const char VSD_STD_ID_NSR03[] = {'N', 'S', 'R', '0', '3'};
const char VSD_STD_ID_TEA01[] = {'T', 'E', 'A', '0', '1'}; const char VSD_STD_ID_TEA01[] = {'T', 'E', 'A', '0', '1'};
#include <cdio/bytesex.h> #include <cdio/bytesex.h>
#include <cdio/utf8.h>
#include <cdio/util.h>
#include "udf_private.h" #include "udf_private.h"
#include "udf_fs.h" #include "udf_fs.h"
#include "cdio_assert.h" #include "cdio_assert.h"
@ -131,24 +134,28 @@ udf_checktag(const udf_tag_t *p_tag, udf_Uint16_t tag_id)
uint8_t *itag; uint8_t *itag;
uint8_t i; uint8_t i;
uint8_t cksum = 0; uint8_t cksum = 0;
itag = (uint8_t *)p_tag; itag = (uint8_t *)p_tag;
#ifdef WORDS_BIGENDIAN
tag_id = UINT16_SWAP_LE_BE(tag_id);
#endif
if (p_tag->id != tag_id) if (p_tag->id != tag_id)
return -1; return -1;
for (i = 0; i < 15; i++) for (i = 0; i < 15; i++)
cksum = cksum + itag[i]; cksum = cksum + itag[i];
cksum = cksum - itag[4]; cksum = cksum - itag[4];
if (cksum == p_tag->cksum) if (cksum == p_tag->cksum)
return 0; return 0;
return -1; return -1;
} }
bool bool
udf_get_lba(const udf_file_entry_t *p_udf_fe, udf_get_lba(const udf_file_entry_t *p_udf_fe,
/*out*/ uint32_t *start, /*out*/ uint32_t *end) /*out*/ uint32_t *start, /*out*/ uint32_t *end)
{ {
if (! p_udf_fe->i_alloc_descs) if (! p_udf_fe->i_alloc_descs)
@ -158,11 +165,11 @@ udf_get_lba(const udf_file_entry_t *p_udf_fe,
case ICBTAG_FLAG_AD_SHORT: case ICBTAG_FLAG_AD_SHORT:
{ {
/* The allocation descriptor field is filled with short_ad's. */ /* The allocation descriptor field is filled with short_ad's. */
udf_short_ad_t *p_ad = (udf_short_ad_t *) udf_short_ad_t *p_ad = (udf_short_ad_t *)
(p_udf_fe->u.ext_attr + p_udf_fe->i_extended_attr); (p_udf_fe->u.ext_attr + p_udf_fe->i_extended_attr);
*start = uint32_from_le(p_ad->pos); *start = uint32_from_le(p_ad->pos);
*end = *start + *end = *start +
((uint32_from_le(p_ad->len) & UDF_LENGTH_MASK) - 1) / UDF_BLOCKSIZE; ((uint32_from_le(p_ad->len) & UDF_LENGTH_MASK) - 1) / UDF_BLOCKSIZE;
return true; return true;
} }
@ -170,11 +177,11 @@ udf_get_lba(const udf_file_entry_t *p_udf_fe,
case ICBTAG_FLAG_AD_LONG: case ICBTAG_FLAG_AD_LONG:
{ {
/* The allocation descriptor field is filled with long_ad's */ /* The allocation descriptor field is filled with long_ad's */
udf_long_ad_t *p_ad = (udf_long_ad_t *) udf_long_ad_t *p_ad = (udf_long_ad_t *)
(p_udf_fe->u.ext_attr + p_udf_fe->i_extended_attr); (p_udf_fe->u.ext_attr + p_udf_fe->i_extended_attr);
*start = uint32_from_le(p_ad->loc.lba); /* ignore partition number */ *start = uint32_from_le(p_ad->loc.lba); /* ignore partition number */
*end = *start + *end = *start +
((uint32_from_le(p_ad->len) & UDF_LENGTH_MASK) - 1) / UDF_BLOCKSIZE; ((uint32_from_le(p_ad->len) & UDF_LENGTH_MASK) - 1) / UDF_BLOCKSIZE;
return true; return true;
} }
@ -183,9 +190,9 @@ udf_get_lba(const udf_file_entry_t *p_udf_fe,
{ {
udf_ext_ad_t *p_ad = (udf_ext_ad_t *) udf_ext_ad_t *p_ad = (udf_ext_ad_t *)
(p_udf_fe->u.ext_attr + p_udf_fe->i_extended_attr); (p_udf_fe->u.ext_attr + p_udf_fe->i_extended_attr);
*start = uint32_from_le(p_ad->ext_loc.lba); /* ignore partition number */ *start = uint32_from_le(p_ad->ext_loc.lba); /* ignore partition number */
*end = *start + *end = *start +
((uint32_from_le(p_ad->len) & UDF_LENGTH_MASK) - 1) / UDF_BLOCKSIZE; ((uint32_from_le(p_ad->len) & UDF_LENGTH_MASK) - 1) / UDF_BLOCKSIZE;
return true; return true;
} }
@ -203,21 +210,21 @@ udf_get_lba(const udf_file_entry_t *p_udf_fe,
not found p_udf_dirent is useless and thus the caller should not found p_udf_dirent is useless and thus the caller should
not use it afterwards. not use it afterwards.
*/ */
static static
udf_dirent_t * udf_dirent_t *
udf_ff_traverse(udf_dirent_t *p_udf_dirent, char *psz_token) udf_ff_traverse(udf_dirent_t *p_udf_dirent, char *psz_token)
{ {
while ((p_udf_dirent = udf_readdir(p_udf_dirent))) { while ((p_udf_dirent = udf_readdir(p_udf_dirent))) {
if (strcmp(psz_token, p_udf_dirent->psz_name) == 0) { if (strcmp(psz_token, p_udf_dirent->psz_name) == 0) {
char *next_tok = strtok(NULL, udf_PATH_DELIMITERS); char *next_tok = strtok(NULL, udf_PATH_DELIMITERS);
if (!next_tok) if (!next_tok)
return p_udf_dirent; /* found */ return p_udf_dirent; /* found */
else if (p_udf_dirent->b_dir) { else if (p_udf_dirent->b_dir) {
udf_dirent_t * p_udf_dirent2 = udf_opendir(p_udf_dirent); udf_dirent_t * p_udf_dirent2 = udf_opendir(p_udf_dirent);
if (p_udf_dirent2) { if (p_udf_dirent2) {
udf_dirent_t * p_udf_dirent3 = udf_dirent_t * p_udf_dirent3 =
udf_ff_traverse(p_udf_dirent2, next_tok); udf_ff_traverse(p_udf_dirent2, next_tok);
/* if p_udf_dirent3 is null p_udf_dirent2 is free'd. */ /* if p_udf_dirent3 is null p_udf_dirent2 is free'd. */
@ -234,11 +241,11 @@ udf_ff_traverse(udf_dirent_t *p_udf_dirent, char *psz_token)
/* FIXME! */ /* FIXME! */
#define udf_MAX_PATHLEN 2048 #define udf_MAX_PATHLEN 2048
udf_dirent_t * udf_dirent_t *
udf_fopen(udf_dirent_t *p_udf_root, const char *psz_name) udf_fopen(udf_dirent_t *p_udf_root, const char *psz_name)
{ {
udf_dirent_t *p_udf_file = NULL; udf_dirent_t *p_udf_file = NULL;
if (p_udf_root) { if (p_udf_root) {
char tokenline[udf_MAX_PATHLEN]; char tokenline[udf_MAX_PATHLEN];
char *psz_token; char *psz_token;
@ -251,11 +258,11 @@ udf_fopen(udf_dirent_t *p_udf_root, const char *psz_name)
if (psz_token) { if (psz_token) {
/*** FIXME??? udf_dirent can be variable size due to the /*** FIXME??? udf_dirent can be variable size due to the
extended attributes and descriptors. Given that, is this extended attributes and descriptors. Given that, is this
correct? correct?
*/ */
udf_dirent_t *p_udf_dirent = udf_dirent_t *p_udf_dirent =
udf_new_dirent(&p_udf_root->fe, p_udf_root->p_udf, udf_new_dirent(&p_udf_root->fe, p_udf_root->p_udf,
p_udf_root->psz_name, p_udf_root->b_dir, p_udf_root->psz_name, p_udf_root->b_dir,
p_udf_root->b_parent); p_udf_root->b_parent);
p_udf_file = udf_ff_traverse(p_udf_dirent, psz_token); p_udf_file = udf_ff_traverse(p_udf_dirent, psz_token);
if (p_udf_file != p_udf_dirent) if (p_udf_file != p_udf_dirent)
@ -263,67 +270,75 @@ udf_fopen(udf_dirent_t *p_udf_root, const char *psz_name)
} }
else if ( 0 == strncmp("/", psz_name, sizeof("/")) ) { else if ( 0 == strncmp("/", psz_name, sizeof("/")) ) {
return udf_new_dirent(&p_udf_root->fe, p_udf_root->p_udf, return udf_new_dirent(&p_udf_root->fe, p_udf_root->p_udf,
p_udf_root->psz_name, p_udf_root->b_dir, p_udf_root->psz_name, p_udf_root->b_dir,
p_udf_root->b_parent); p_udf_root->b_parent);
} }
} }
return p_udf_file; return p_udf_file;
} }
/* Convert unicode16 to 8-bit char by dripping MSB. /* Convert unicode16 to UTF-8.
Wonder if iconv can be used here The returned string is allocated and must be freed by the caller
*/ */
static int static char*
unicode16_decode( const uint8_t *data, int i_len, char *target ) unicode16_decode(const uint8_t *data, int i_len)
{ {
int p = 1, i = 0; int i;
char* r = NULL;
if( ( data[ 0 ] == 8 ) || ( data[ 0 ] == 16 ) ) do {
if( data[ 0 ] == 16 ) p++; /* Ignore MSB of unicode16 */ switch (data[0])
if( p < i_len ) { {
target[ i++ ] = data[ p++ ]; case 8:
} r = (char*)malloc(i_len);
} while( p < i_len ); if (r == NULL)
return r;
target[ i ] = '\0'; for (i=0; i<i_len-1; i++)
return 0; r[i] = data[i+1];
r[i] = 0;
return r;
case 16:
cdio_charset_to_utf8((char*)&data[1], i_len-1, &r, "UCS-2BE");
return r;
default:
return NULL;
}
} }
static udf_dirent_t * static udf_dirent_t *
udf_new_dirent(udf_file_entry_t *p_udf_fe, udf_t *p_udf, udf_new_dirent(udf_file_entry_t *p_udf_fe, udf_t *p_udf,
const char *psz_name, bool b_dir, bool b_parent) const char *psz_name, bool b_dir, bool b_parent)
{ {
udf_dirent_t *p_udf_dirent = (udf_dirent_t *) udf_dirent_t *p_udf_dirent = (udf_dirent_t *)
calloc(1, sizeof(udf_dirent_t)); calloc(1, sizeof(udf_dirent_t));
if (!p_udf_dirent) return NULL; if (!p_udf_dirent) return NULL;
p_udf_dirent->psz_name = strdup(psz_name); p_udf_dirent->psz_name = strdup(psz_name);
p_udf_dirent->b_dir = b_dir; p_udf_dirent->b_dir = b_dir;
p_udf_dirent->b_parent = b_parent; p_udf_dirent->b_parent = b_parent;
p_udf_dirent->p_udf = p_udf; p_udf_dirent->p_udf = p_udf;
p_udf_dirent->i_part_start = p_udf->i_part_start; p_udf_dirent->i_part_start = p_udf->i_part_start;
p_udf_dirent->dir_left = uint64_from_le(p_udf_fe->info_len); p_udf_dirent->dir_left = uint64_from_le(p_udf_fe->info_len);
memcpy(&(p_udf_dirent->fe), p_udf_fe, memcpy(&(p_udf_dirent->fe), p_udf_fe,
sizeof(udf_file_entry_t)); sizeof(udf_file_entry_t));
udf_get_lba( p_udf_fe, &(p_udf_dirent->i_loc), udf_get_lba( p_udf_fe, &(p_udf_dirent->i_loc),
&(p_udf_dirent->i_loc_end) ); &(p_udf_dirent->i_loc_end) );
return p_udf_dirent; return p_udf_dirent;
} }
/*! /*!
Seek to a position i_start and then read i_blocks. Number of blocks read is Seek to a position i_start and then read i_blocks. Number of blocks read is
returned. One normally expects the return to be equal to i_blocks. returned. One normally expects the return to be equal to i_blocks.
*/ */
driver_return_code_t driver_return_code_t
udf_read_sectors (const udf_t *p_udf, void *ptr, lsn_t i_start, udf_read_sectors (const udf_t *p_udf, void *ptr, lsn_t i_start,
long i_blocks) long i_blocks)
{ {
driver_return_code_t ret; driver_return_code_t ret;
long i_read; long i_read;
off_t i_byte_offset; off_t i_byte_offset;
if (!p_udf) return 0; if (!p_udf) return 0;
/* Without the cast, i_start * UDF_BLOCKSIZE may be evaluated as 32 bit */ /* Without the cast, i_start * UDF_BLOCKSIZE may be evaluated as 32 bit */
i_byte_offset = ((off_t)i_start) * UDF_BLOCKSIZE; i_byte_offset = ((off_t)i_start) * UDF_BLOCKSIZE;
@ -369,7 +384,7 @@ udf_open (const char *psz_path)
encapsulated as a CD-ROM Image (e.g. often .UDF or (sic) .ISO) encapsulated as a CD-ROM Image (e.g. often .UDF or (sic) .ISO)
*/ */
p_udf->stream = cdio_stdio_new( psz_path ); p_udf->stream = cdio_stdio_new( psz_path );
if (!p_udf->stream) if (!p_udf->stream)
goto error; goto error;
p_udf->b_stream = true; p_udf->b_stream = true;
} }
@ -379,36 +394,36 @@ udf_open (const char *psz_path)
*/ */
if (DRIVER_OP_SUCCESS != udf_read_sectors (p_udf, &data, 256, 1) ) if (DRIVER_OP_SUCCESS != udf_read_sectors (p_udf, &data, 256, 1) )
goto error; goto error;
memcpy(&(p_udf->anchor_vol_desc_ptr), &data, sizeof(anchor_vol_desc_ptr_t)); memcpy(&(p_udf->anchor_vol_desc_ptr), &data, sizeof(anchor_vol_desc_ptr_t));
if (udf_checktag((udf_tag_t *)&(p_udf->anchor_vol_desc_ptr), TAGID_ANCHOR)) if (udf_checktag((udf_tag_t *)&(p_udf->anchor_vol_desc_ptr), TAGID_ANCHOR))
goto error; goto error;
/* /*
* Then try to find a reference to a Primary Volume Descriptor. * Then try to find a reference to a Primary Volume Descriptor.
*/ */
{ {
const anchor_vol_desc_ptr_t *p_avdp = &p_udf->anchor_vol_desc_ptr; anchor_vol_desc_ptr_t *p_avdp = &p_udf->anchor_vol_desc_ptr;
const uint32_t mvds_start =
const uint32_t mvds_start =
uint32_from_le(p_avdp->main_vol_desc_seq_ext.loc); uint32_from_le(p_avdp->main_vol_desc_seq_ext.loc);
const uint32_t mvds_end = mvds_start + const uint32_t mvds_end = mvds_start +
(uint32_from_le(p_avdp->main_vol_desc_seq_ext.len) - 1) / UDF_BLOCKSIZE; (uint32_from_le(p_avdp->main_vol_desc_seq_ext.len) - 1) / UDF_BLOCKSIZE;
uint32_t i_lba; uint32_t i_lba;
for (i_lba = mvds_start; i_lba < mvds_end; i_lba++) { for (i_lba = mvds_start; i_lba < mvds_end; i_lba++) {
udf_pvd_t *p_pvd = (udf_pvd_t *) &data; udf_pvd_t *p_pvd = (udf_pvd_t *) &data;
if (DRIVER_OP_SUCCESS != udf_read_sectors (p_udf, p_pvd, i_lba, 1) ) if (DRIVER_OP_SUCCESS != udf_read_sectors (p_udf, p_pvd, i_lba, 1) )
goto error; goto error;
if (!udf_checktag(&p_pvd->tag, TAGID_PRI_VOL)) { if (!udf_checktag(&p_pvd->tag, TAGID_PRI_VOL)) {
p_udf->pvd_lba = i_lba; p_udf->pvd_lba = i_lba;
break; break;
} }
} }
/* /*
@ -427,18 +442,24 @@ udf_open (const char *psz_path)
} }
/** /**
* Gets the Volume Identifier string, in 8bit unicode (latin-1) * Gets the Volume Identifier, as an UTF-8 string
* psz_volid, place to put the string * psz_volid, place to put the string
* i_volid, size of the buffer psz_volid points to * i_volid, size of the buffer psz_volid points to
* returns the size of buffer needed for all data * returns the size of buffer needed for all data
* Note: this call accepts a NULL psz_volid, to retrieve the length required.
*/ */
int int
udf_get_volume_id(udf_t *p_udf, /*out*/ char *psz_volid, unsigned int i_volid) udf_get_volume_id(udf_t *p_udf, /*out*/ char *psz_volid, unsigned int i_volid)
{ {
uint8_t data[UDF_BLOCKSIZE]; uint8_t data[UDF_BLOCKSIZE];
const udf_pvd_t *p_pvd = (udf_pvd_t *) &data; const udf_pvd_t *p_pvd = (udf_pvd_t *) &data;
char* r;
unsigned int volid_len; unsigned int volid_len;
/* clear the output to empty string */
if (psz_volid != NULL)
psz_volid[0] = 0;
/* get primary volume descriptor */ /* get primary volume descriptor */
if ( DRIVER_OP_SUCCESS != udf_read_sectors(p_udf, &data, p_udf->pvd_lba, 1) ) if ( DRIVER_OP_SUCCESS != udf_read_sectors(p_udf, &data, p_udf->pvd_lba, 1) )
return 0; return 0;
@ -448,11 +469,18 @@ udf_get_volume_id(udf_t *p_udf, /*out*/ char *psz_volid, unsigned int i_volid)
/* this field is only UDF_VOLID_SIZE bytes something is wrong */ /* this field is only UDF_VOLID_SIZE bytes something is wrong */
volid_len = UDF_VOLID_SIZE-1; volid_len = UDF_VOLID_SIZE-1;
} }
if(i_volid > volid_len) {
i_volid = volid_len; r = unicode16_decode((uint8_t *) p_pvd->vol_ident, volid_len);
if (r == NULL)
return 0;
volid_len = strlen(r)+1; /* +1 for NUL terminator */
if (psz_volid != NULL) {
strncpy(psz_volid, r, MIN(volid_len, i_volid));
psz_volid[i_volid-1] = 0; /* strncpy does not always terminate the dest */
} }
unicode16_decode((uint8_t *) p_pvd->vol_ident, i_volid, psz_volid); free(r);
return volid_len; return volid_len;
} }
@ -460,12 +488,12 @@ udf_get_volume_id(udf_t *p_udf, /*out*/ char *psz_volid, unsigned int i_volid)
* Gets the Volume Set Identifier, as a 128-byte dstring (not decoded) * Gets the Volume Set Identifier, as a 128-byte dstring (not decoded)
* WARNING This is not a null terminated string * WARNING This is not a null terminated string
* volsetid, place to put the data * volsetid, place to put the data
* i_volsetid, size of the buffer psz_volsetid points to * i_volsetid, size of the buffer psz_volsetid points to
* the buffer should be >=128 bytes to store the whole volumesetidentifier * the buffer should be >=128 bytes to store the whole volumesetidentifier
* returns the size of the available volsetid information (128) * returns the size of the available volsetid information (128)
* or 0 on error * or 0 on error
*/ */
int int
udf_get_volumeset_id(udf_t *p_udf, /*out*/ uint8_t *volsetid, udf_get_volumeset_id(udf_t *p_udf, /*out*/ uint8_t *volsetid,
unsigned int i_volsetid) unsigned int i_volsetid)
{ {
@ -479,34 +507,46 @@ udf_get_volumeset_id(udf_t *p_udf, /*out*/ uint8_t *volsetid,
if (i_volsetid > UDF_VOLSET_ID_SIZE) { if (i_volsetid > UDF_VOLSET_ID_SIZE) {
i_volsetid = UDF_VOLSET_ID_SIZE; i_volsetid = UDF_VOLSET_ID_SIZE;
} }
memcpy(volsetid, p_pvd->volset_id, i_volsetid); memcpy(volsetid, p_pvd->volset_id, i_volsetid);
return UDF_VOLSET_ID_SIZE; return UDF_VOLSET_ID_SIZE;
} }
/** /**
* Gets the Logical Volume Identifier string, in 8bit unicode (latin-1) * Gets the Logical Volume Identifier string, as an UTF-8 string
* psz_logvolid, place to put the string (should be at least 64 bytes) * psz_logvolid, place to put the string (should be at least 64 bytes)
* i_logvolid, size of the buffer psz_logvolid points to * i_logvolid, size of the buffer psz_logvolid points to
* returns the size of buffer needed for all data * returns the size of buffer needed for all data, including NUL terminator
* A call to udf_get_root() should have been issued before this call * A call to udf_get_root() should have been issued before this call
* Note: this call accepts a NULL psz_volid, to retrieve the length required.
*/ */
int int
udf_get_logical_volume_id(udf_t *p_udf, /*out*/ char *psz_logvolid, unsigned int i_logvolid) udf_get_logical_volume_id(udf_t *p_udf, /*out*/ char *psz_logvolid, unsigned int i_logvolid)
{ {
uint8_t data[UDF_BLOCKSIZE]; uint8_t data[UDF_BLOCKSIZE];
logical_vol_desc_t *p_logvol = (logical_vol_desc_t *) &data; logical_vol_desc_t *p_logvol = (logical_vol_desc_t *) &data;
char* r;
int logvolid_len; int logvolid_len;
/* clear the output to empty string */
if (psz_logvolid != NULL)
psz_logvolid[0] = 0;
if (DRIVER_OP_SUCCESS != udf_read_sectors (p_udf, p_logvol, p_udf->lvd_lba, 1) ) if (DRIVER_OP_SUCCESS != udf_read_sectors (p_udf, p_logvol, p_udf->lvd_lba, 1) )
return 0; return 0;
logvolid_len = (p_logvol->logvol_id[127]+1)/2; r = unicode16_decode((uint8_t *) p_logvol->logvol_id, p_logvol->logvol_id[127]);
if (i_logvolid > logvolid_len) if (r == NULL)
i_logvolid = logvolid_len; return 0;
logvolid_len = strlen(r)+1; /* +1 for NUL terminator */
if (psz_logvolid != NULL) {
strncpy(psz_logvolid, r, MIN(logvolid_len, i_logvolid));
psz_logvolid[i_logvolid-1] = 0; /* strncpy does not always terminate the dest */
}
free(r);
unicode16_decode((uint8_t *) p_logvol->logvol_id, 2*i_logvolid, psz_logvolid);
return logvolid_len; return logvolid_len;
} }
@ -522,14 +562,14 @@ udf_dirent_t *
udf_get_root (udf_t *p_udf, bool b_any_partition, partition_num_t i_partition) udf_get_root (udf_t *p_udf, bool b_any_partition, partition_num_t i_partition)
{ {
const anchor_vol_desc_ptr_t *p_avdp = &p_udf->anchor_vol_desc_ptr; const anchor_vol_desc_ptr_t *p_avdp = &p_udf->anchor_vol_desc_ptr;
const uint32_t mvds_start = const uint32_t mvds_start =
uint32_from_le(p_avdp->main_vol_desc_seq_ext.loc); uint32_from_le(p_avdp->main_vol_desc_seq_ext.loc);
const uint32_t mvds_end = mvds_start + const uint32_t mvds_end = mvds_start +
(uint32_from_le(p_avdp->main_vol_desc_seq_ext.len) - 1) / UDF_BLOCKSIZE; (uint32_from_le(p_avdp->main_vol_desc_seq_ext.len) - 1) / UDF_BLOCKSIZE;
uint32_t i_lba; uint32_t i_lba;
uint8_t data[UDF_BLOCKSIZE]; uint8_t data[UDF_BLOCKSIZE];
/* /*
Now we have the joy of finding the Partition Descriptor and the Now we have the joy of finding the Partition Descriptor and the
Logical Volume Descriptor for the Main Volume Descriptor Logical Volume Descriptor for the Main Volume Descriptor
Sequence. Once we've got that, we use the Logical Volume Sequence. Once we've got that, we use the Logical Volume
@ -538,14 +578,14 @@ udf_get_root (udf_t *p_udf, bool b_any_partition, partition_num_t i_partition)
*/ */
for (i_lba = mvds_start; i_lba < mvds_end; i_lba++) { for (i_lba = mvds_start; i_lba < mvds_end; i_lba++) {
uint8_t data2[UDF_BLOCKSIZE]; uint8_t data2[UDF_BLOCKSIZE];
partition_desc_t *p_partition = (partition_desc_t *) &data2; partition_desc_t *p_partition = (partition_desc_t *) &data2;
if (DRIVER_OP_SUCCESS != udf_read_sectors (p_udf, p_partition, i_lba, 1) ) if (DRIVER_OP_SUCCESS != udf_read_sectors (p_udf, p_partition, i_lba, 1) )
return NULL; return NULL;
if (!udf_checktag(&p_partition->tag, TAGID_PARTITION)) { if (!udf_checktag(&p_partition->tag, TAGID_PARTITION)) {
const partition_num_t i_partition_check const partition_num_t i_partition_check
= uint16_from_le(p_partition->number); = uint16_from_le(p_partition->number);
if (b_any_partition || i_partition_check == i_partition) { if (b_any_partition || i_partition_check == i_partition) {
/* Squirrel away some data regarding partition */ /* Squirrel away some data regarding partition */
@ -556,37 +596,37 @@ udf_get_root (udf_t *p_udf, bool b_any_partition, partition_num_t i_partition)
} else if (!udf_checktag(&p_partition->tag, TAGID_LOGVOL)) { } else if (!udf_checktag(&p_partition->tag, TAGID_LOGVOL)) {
/* Get fileset descriptor */ /* Get fileset descriptor */
logical_vol_desc_t *p_logvol = (logical_vol_desc_t *) &data2; logical_vol_desc_t *p_logvol = (logical_vol_desc_t *) &data2;
bool b_valid = bool b_valid =
UDF_BLOCKSIZE == uint32_from_le(p_logvol->logical_blocksize); UDF_BLOCKSIZE == uint32_from_le(p_logvol->logical_blocksize);
if (b_valid) { if (b_valid) {
p_udf->lvd_lba = i_lba; p_udf->lvd_lba = i_lba;
p_udf->fsd_offset = p_udf->fsd_offset =
uint32_from_le(p_logvol->lvd_use.fsd_loc.loc.lba); uint32_from_le(p_logvol->lvd_use.fsd_loc.loc.lba);
if (p_udf->i_part_start) break; if (p_udf->i_part_start) break;
} }
} }
} }
if (p_udf->lvd_lba && p_udf->i_part_start) { if (p_udf->lvd_lba && p_udf->i_part_start) {
udf_fsd_t *p_fsd = (udf_fsd_t *) &data; udf_fsd_t *p_fsd = (udf_fsd_t *) &data;
driver_return_code_t ret = driver_return_code_t ret =
udf_read_sectors(p_udf, p_fsd, p_udf->i_part_start + p_udf->fsd_offset, udf_read_sectors(p_udf, p_fsd, p_udf->i_part_start + p_udf->fsd_offset,
1); 1);
if (DRIVER_OP_SUCCESS == ret && !udf_checktag(&p_fsd->tag, TAGID_FSD)) { if (DRIVER_OP_SUCCESS == ret && !udf_checktag(&p_fsd->tag, TAGID_FSD)) {
udf_file_entry_t *p_udf_fe = (udf_file_entry_t *) &data; udf_file_entry_t *p_udf_fe = (udf_file_entry_t *) &data;
const uint32_t parent_icb = uint32_from_le(p_fsd->root_icb.loc.lba); const uint32_t parent_icb = uint32_from_le(p_fsd->root_icb.loc.lba);
/* Check partition numbers match of last-read block? */ /* Check partition numbers match of last-read block? */
ret = udf_read_sectors(p_udf, p_udf_fe, ret = udf_read_sectors(p_udf, p_udf_fe,
p_udf->i_part_start + parent_icb, 1); p_udf->i_part_start + parent_icb, 1);
if (ret == DRIVER_OP_SUCCESS && if (ret == DRIVER_OP_SUCCESS &&
!udf_checktag(&p_udf_fe->tag, TAGID_FILE_ENTRY)) { !udf_checktag(&p_udf_fe->tag, TAGID_FILE_ENTRY)) {
/* Check partition numbers match of last-read block? */ /* Check partition numbers match of last-read block? */
/* We win! - Save root directory information. */ /* We win! - Save root directory information. */
return udf_new_dirent(p_udf_fe, p_udf, "/", true, false ); return udf_new_dirent(p_udf_fe, p_udf, "/", true, false );
} }
@ -598,13 +638,13 @@ udf_get_root (udf_t *p_udf, bool b_any_partition, partition_num_t i_partition)
#define free_and_null(x) \ #define free_and_null(x) \
free(x); \ free(x); \
x=NULL x=NULL
/*! /*!
Close UDF and free resources associated with p_udf. Close UDF and free resources associated with p_udf.
*/ */
bool bool
udf_close (udf_t *p_udf) udf_close (udf_t *p_udf)
{ {
if (!p_udf) return true; if (!p_udf) return true;
if (p_udf->b_stream) { if (p_udf->b_stream) {
@ -619,22 +659,22 @@ udf_close (udf_t *p_udf)
return true; return true;
} }
udf_dirent_t * udf_dirent_t *
udf_opendir(const udf_dirent_t *p_udf_dirent) udf_opendir(const udf_dirent_t *p_udf_dirent)
{ {
if (p_udf_dirent->b_dir && !p_udf_dirent->b_parent && p_udf_dirent->fid) { if (p_udf_dirent->b_dir && !p_udf_dirent->b_parent && p_udf_dirent->fid) {
udf_t *p_udf = p_udf_dirent->p_udf; udf_t *p_udf = p_udf_dirent->p_udf;
udf_file_entry_t udf_fe; udf_file_entry_t udf_fe;
driver_return_code_t i_ret = driver_return_code_t i_ret =
udf_read_sectors(p_udf, &udf_fe, p_udf->i_part_start udf_read_sectors(p_udf, &udf_fe, p_udf->i_part_start
+ p_udf_dirent->fid->icb.loc.lba, 1); + p_udf_dirent->fid->icb.loc.lba, 1);
if (DRIVER_OP_SUCCESS == i_ret if (DRIVER_OP_SUCCESS == i_ret
&& !udf_checktag(&udf_fe.tag, TAGID_FILE_ENTRY)) { && !udf_checktag(&udf_fe.tag, TAGID_FILE_ENTRY)) {
if (ICBTAG_FILE_TYPE_DIRECTORY == udf_fe.icb_tag.file_type) { if (ICBTAG_FILE_TYPE_DIRECTORY == udf_fe.icb_tag.file_type) {
udf_dirent_t *p_udf_dirent_new = udf_dirent_t *p_udf_dirent_new =
udf_new_dirent(&udf_fe, p_udf, p_udf_dirent->psz_name, true, true); udf_new_dirent(&udf_fe, p_udf, p_udf_dirent->psz_name, true, true);
return p_udf_dirent_new; return p_udf_dirent_new;
} }
@ -647,7 +687,8 @@ udf_dirent_t *
udf_readdir(udf_dirent_t *p_udf_dirent) udf_readdir(udf_dirent_t *p_udf_dirent)
{ {
udf_t *p_udf; udf_t *p_udf;
uint8_t* p;
if (p_udf_dirent->dir_left <= 0) { if (p_udf_dirent->dir_left <= 0) {
udf_dirent_free(p_udf_dirent); udf_dirent_free(p_udf_dirent);
return NULL; return NULL;
@ -657,62 +698,58 @@ udf_readdir(udf_dirent_t *p_udf_dirent)
p_udf = p_udf_dirent->p_udf; p_udf = p_udf_dirent->p_udf;
p_udf->i_position = 0; p_udf->i_position = 0;
if (p_udf_dirent->fid) { if (p_udf_dirent->fid) {
/* advance to next File Identifier Descriptor */ /* advance to next File Identifier Descriptor */
/* FIXME: need to advance file entry (fe) as well. */ /* FIXME: need to advance file entry (fe) as well. */
uint32_t ofs = 4 * uint32_t ofs = 4 *
((sizeof(*(p_udf_dirent->fid)) + p_udf_dirent->fid->u.i_imp_use ((sizeof(*(p_udf_dirent->fid)) + p_udf_dirent->fid->u.i_imp_use
+ p_udf_dirent->fid->i_file_id + 3) / 4); + p_udf_dirent->fid->i_file_id + 3) / 4);
p_udf_dirent->fid = p_udf_dirent->fid =
(udf_fileid_desc_t *)((uint8_t *)p_udf_dirent->fid + ofs); (udf_fileid_desc_t *)((uint8_t *)p_udf_dirent->fid + ofs);
} }
if (!p_udf_dirent->fid) { if (!p_udf_dirent->fid) {
uint32_t i_sectors = uint32_t i_sectors =
(p_udf_dirent->i_loc_end - p_udf_dirent->i_loc + 1); (p_udf_dirent->i_loc_end - p_udf_dirent->i_loc + 1);
uint32_t size = UDF_BLOCKSIZE * i_sectors; uint32_t size = UDF_BLOCKSIZE * i_sectors;
driver_return_code_t i_ret; driver_return_code_t i_ret;
if (!p_udf_dirent->sector) if (!p_udf_dirent->sector)
p_udf_dirent->sector = (uint8_t*) malloc(size); p_udf_dirent->sector = (uint8_t*) malloc(size);
i_ret = udf_read_sectors(p_udf, p_udf_dirent->sector, i_ret = udf_read_sectors(p_udf, p_udf_dirent->sector,
p_udf_dirent->i_part_start+p_udf_dirent->i_loc, p_udf_dirent->i_part_start+p_udf_dirent->i_loc,
i_sectors); i_sectors);
if (DRIVER_OP_SUCCESS == i_ret) if (DRIVER_OP_SUCCESS == i_ret)
p_udf_dirent->fid = (udf_fileid_desc_t *) p_udf_dirent->sector; p_udf_dirent->fid = (udf_fileid_desc_t *) p_udf_dirent->sector;
else else
p_udf_dirent->fid = NULL; p_udf_dirent->fid = NULL;
} }
if (p_udf_dirent->fid && !udf_checktag(&(p_udf_dirent->fid->tag), TAGID_FID)) if (p_udf_dirent->fid && !udf_checktag(&(p_udf_dirent->fid->tag), TAGID_FID))
{ {
uint32_t ofs = uint32_t ofs =
4 * ((sizeof(*p_udf_dirent->fid) + p_udf_dirent->fid->u.i_imp_use 4 * ((sizeof(*p_udf_dirent->fid) + p_udf_dirent->fid->u.i_imp_use
+ p_udf_dirent->fid->i_file_id + 3) / 4); + p_udf_dirent->fid->i_file_id + 3) / 4);
p_udf_dirent->dir_left -= ofs; p_udf_dirent->dir_left -= ofs;
p_udf_dirent->b_dir = p_udf_dirent->b_dir =
(p_udf_dirent->fid->file_characteristics & UDF_FILE_DIRECTORY) != 0; (p_udf_dirent->fid->file_characteristics & UDF_FILE_DIRECTORY) != 0;
p_udf_dirent->b_parent = p_udf_dirent->b_parent =
(p_udf_dirent->fid->file_characteristics & UDF_FILE_PARENT) != 0; (p_udf_dirent->fid->file_characteristics & UDF_FILE_PARENT) != 0;
{ {
const unsigned int i_len = p_udf_dirent->fid->i_file_id; const unsigned int i_len = p_udf_dirent->fid->i_file_id;
if (DRIVER_OP_SUCCESS != udf_read_sectors(p_udf, &p_udf_dirent->fe, p_udf->i_part_start if (DRIVER_OP_SUCCESS != udf_read_sectors(p_udf, &p_udf_dirent->fe, p_udf->i_part_start
+ p_udf_dirent->fid->icb.loc.lba, 1)) { + p_udf_dirent->fid->icb.loc.lba, 1)) {
udf_dirent_free(p_udf_dirent); udf_dirent_free(p_udf_dirent);
return NULL; return NULL;
} }
if (strlen(p_udf_dirent->psz_name) < i_len) free_and_null(p_udf_dirent->psz_name);
p_udf_dirent->psz_name = (char *) p = (uint8_t*)p_udf_dirent->fid->u.imp_use.data + p_udf_dirent->fid->u.i_imp_use;
realloc(p_udf_dirent->psz_name, sizeof(char)*i_len+1); p_udf_dirent->psz_name = unicode16_decode(p, i_len);
unicode16_decode(p_udf_dirent->fid->u.imp_use.data
+ p_udf_dirent->fid->u.i_imp_use,
i_len, p_udf_dirent->psz_name);
} }
return p_udf_dirent; return p_udf_dirent;
} }
@ -723,8 +760,8 @@ udf_readdir(udf_dirent_t *p_udf_dirent)
/*! /*!
free free resources associated with p_udf_dirent. free free resources associated with p_udf_dirent.
*/ */
bool bool
udf_dirent_free(udf_dirent_t *p_udf_dirent) udf_dirent_free(udf_dirent_t *p_udf_dirent)
{ {
if (p_udf_dirent) { if (p_udf_dirent) {
p_udf_dirent->fid = NULL; p_udf_dirent->fid = NULL;

View File

@ -32,7 +32,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 206, 329 IDD_DIALOG DIALOGEX 12, 12, 206, 329
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Rufus 1.4.4.412" CAPTION "Rufus 1.4.4.413"
FONT 8, "MS Shell Dlg", 400, 0, 0x1 FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN BEGIN
DEFPUSHBUTTON "Start",IDC_START,94,291,50,14 DEFPUSHBUTTON "Start",IDC_START,94,291,50,14
@ -165,7 +165,7 @@ END
RTL_IDD_DIALOG DIALOGEX 12, 12, 206, 329 RTL_IDD_DIALOG DIALOGEX 12, 12, 206, 329
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL
CAPTION "Rufus 1.4.4.412" CAPTION "Rufus 1.4.4.413"
FONT 8, "MS Shell Dlg", 400, 0, 0x1 FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN BEGIN
DEFPUSHBUTTON "Start",IDC_START,94,291,50,14 DEFPUSHBUTTON "Start",IDC_START,94,291,50,14
@ -427,8 +427,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,4,4,412 FILEVERSION 1,4,4,413
PRODUCTVERSION 1,4,4,412 PRODUCTVERSION 1,4,4,413
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -445,13 +445,13 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
VALUE "FileDescription", "Rufus" VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "1.4.4.412" VALUE "FileVersion", "1.4.4.413"
VALUE "InternalName", "Rufus" VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2014 Pete Batard (GPL v3)" VALUE "LegalCopyright", "© 2011-2014 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
VALUE "OriginalFilename", "rufus.exe" VALUE "OriginalFilename", "rufus.exe"
VALUE "ProductName", "Rufus" VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "1.4.4.412" VALUE "ProductVersion", "1.4.4.413"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"