1
1
Fork 0
mirror of https://github.com/pbatard/rufus.git synced 2024-08-14 23:57:05 +00:00

[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
@ -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"
@ -134,6 +137,10 @@ udf_checktag(const udf_tag_t *p_tag, udf_Uint16_t tag_id)
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;
@ -270,23 +277,31 @@ udf_fopen(udf_dirent_t *p_udf_root, const char *psz_name)
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 { switch (data[0])
if( data[ 0 ] == 16 ) p++; /* Ignore MSB of unicode16 */ {
if( p < i_len ) { case 8:
target[ i++ ] = data[ p++ ]; r = (char*)malloc(i_len);
if (r == NULL)
return r;
for (i=0; i<i_len-1; i++)
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;
} }
} while( p < i_len );
target[ i ] = '\0';
return 0;
} }
@ -389,7 +404,8 @@ udf_open (const char *psz_path)
* 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 +
@ -398,7 +414,6 @@ udf_open (const char *psz_path)
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) )
@ -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,10 +469,17 @@ 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;
} }
@ -486,27 +514,39 @@ udf_get_volumeset_id(udf_t *p_udf, /*out*/ uint8_t *volsetid,
} }
/** /**
* 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;
} }
@ -647,6 +687,7 @@ 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);
@ -706,13 +747,9 @@ udf_readdir(udf_dirent_t *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;
} }

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"