Hi,
Having recently found that the unicode16_decode() call we use in udf_fs
isn't actually doing any actual Unicode decoding (just strips the MSB
from UTF-16), please find attached a patch that adds Unicode support to
udf_fs and will ensure we always return UTF-8 strings where relevant.
The patch also contains an associated test as well as the required UDF
image (which was created using ImgBurn).
Regards,
/Pete
>From 6310430dd712e9769e49dd942d2200cb27951cec Mon Sep 17 00:00:00 2001
From: Pete Batard <[email protected]>
Date: Thu, 20 Feb 2014 02:21:27 +0000
Subject: [PATCH] Add Unicode support for UDF
---
lib/driver/utf8.c | 3 --
lib/udf/udf_fs.c | 104 ++++++++++++++++++++++++++++++++-----------------
test/check_fuzzyiso.sh | 2 +-
test/data/udf102.iso | Bin 784384 -> 1245184 bytes
test/testudf.c.in | 32 +++++++++++----
5 files changed, 94 insertions(+), 47 deletions(-)
diff --git a/lib/driver/utf8.c b/lib/driver/utf8.c
index db68d5b..b94b833 100644
--- a/lib/driver/utf8.c
+++ b/lib/driver/utf8.c
@@ -113,7 +113,6 @@ FILE* fopen_utf8(const char* filename, const char* mode)
}
#endif
-#ifdef HAVE_JOLIET
#ifdef HAVE_ICONV
#include <iconv.h>
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);
}
#endif /* HAVE_ICONV */
-
-#endif /* HAVE_JOLIET */
diff --git a/lib/udf/udf_fs.c b/lib/udf/udf_fs.c
index 81719b6..e21571a 100644
--- a/lib/udf/udf_fs.c
+++ b/lib/udf/udf_fs.c
@@ -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'};
#include <cdio/bytesex.h>
+#include <cdio/utf8.h>
+#include <cdio/util.h>
+
#include "udf_private.h"
#include "udf_fs.h"
#include "cdio_assert.h"
@@ -274,23 +277,32 @@ udf_fopen(udf_dirent_t *p_udf_root, const char *psz_name)
return p_udf_file;
}
-/* Convert unicode16 to 8-bit char by dripping MSB.
- Wonder if iconv can be used here
+/* Convert unicode16 to UTF-8.
+ The returned string is allocated and must be freed by the caller
*/
-static int
-unicode16_decode( const uint8_t *data, int i_len, char *target )
+static char*
+unicode16_decode(const uint8_t *data, int i_len)
{
- int p = 1, i = 0;
-
- if( ( data[ 0 ] == 8 ) || ( data[ 0 ] == 16 ) ) do {
- if( data[ 0 ] == 16 ) p++; /* Ignore MSB of unicode16 */
- if( p < i_len ) {
- target[ i++ ] = data[ p++ ];
- }
- } while( p < i_len );
+ int i;
+ char* r = NULL;
- target[ i ] = '\0';
- return 0;
+ switch (data[0])
+ {
+ case 8:
+ r = (char*)calloc(i_len, 1);
+ if (r == NULL)
+ return r;
+ for (i=0; i<i_len-1; i++)
+ r[i] = data[i+1];
+ return r;
+ case 16:
+ cdio_charset_to_utf8((char*)&data[1], i_len-1, &r, "UCS-2BE");
+ return r;
+ default:
+ /* Empty string, as some existing sections can't take a NULL pointer */
+ r = (char*)calloc(1, 1);
+ return r;
+ }
}
@@ -431,18 +443,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
* i_volid, size of the buffer psz_volid points to
* returns the size of buffer needed for all data
+ * Note: this call accepts a NULL psz_volid, to retrieve the length required.
*/
-int
-udf_get_volume_id(udf_t *p_udf, /*out*/ char *psz_volid, unsigned int i_volid)
+int
+udf_get_volume_id(udf_t *p_udf, /*out*/ char *psz_volid, unsigned int i_volid)
{
uint8_t data[UDF_BLOCKSIZE];
const udf_pvd_t *p_pvd = (udf_pvd_t *) &data;
+ char* r;
unsigned int volid_len;
+ /* clear the output to empty string */
+ if (psz_volid != NULL)
+ psz_volid[0] = 0;
+
/* get primary volume descriptor */
if ( DRIVER_OP_SUCCESS != udf_read_sectors(p_udf, &data, p_udf->pvd_lba, 1) )
return 0;
@@ -452,10 +470,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 */
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;
}
@@ -490,27 +515,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)
* 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
+ * Note: this call accepts a NULL psz_volid, to retrieve the length required.
*/
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];
logical_vol_desc_t *p_logvol = (logical_vol_desc_t *) &data;
+ char* r;
int logvolid_len;
- if (DRIVER_OP_SUCCESS != udf_read_sectors (p_udf, p_logvol, p_udf->lvd_lba,
1) )
+ /* 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) )
return 0;
- logvolid_len = (p_logvol->logvol_id[127]+1)/2;
- if (i_logvolid > logvolid_len)
- i_logvolid = logvolid_len;
+ r = unicode16_decode((uint8_t *) p_logvol->logvol_id,
p_logvol->logvol_id[127]);
+ if (r == NULL)
+ 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;
}
@@ -651,6 +688,7 @@ udf_dirent_t *
udf_readdir(udf_dirent_t *p_udf_dirent)
{
udf_t *p_udf;
+ uint8_t* p;
if (p_udf_dirent->dir_left <= 0) {
udf_dirent_free(p_udf_dirent);
@@ -710,13 +748,9 @@ udf_readdir(udf_dirent_t *p_udf_dirent)
return NULL;
}
- if (strlen(p_udf_dirent->psz_name) < i_len)
- p_udf_dirent->psz_name = (char *)
- realloc(p_udf_dirent->psz_name, sizeof(char)*i_len+1);
-
- 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);
+ free_and_null(p_udf_dirent->psz_name);
+ p = (uint8_t*)p_udf_dirent->fid->u.imp_use.data +
p_udf_dirent->fid->u.i_imp_use;
+ p_udf_dirent->psz_name = unicode16_decode(p, i_len);
}
return p_udf_dirent;
}
diff --git a/test/check_fuzzyiso.sh b/test/check_fuzzyiso.sh
index 0eb71d9..cef7a5a 100755
--- a/test/check_fuzzyiso.sh
+++ b/test/check_fuzzyiso.sh
@@ -22,7 +22,7 @@ fi
cd $srcdir; src_dir=`pwd`
for file in $src_dir/data/*.bin $src_dir/data/*.iso $src_dir/data/*.nrg ; do
case "$file" in
- $src_dir/data/p1.nrg | $src_dir/data/p1.bin | $src_dir/data/cdda.bin |
$src_dir/data/cdda-mcn.nrg | $src_dir/data/svcdgs.nrg |
$src_dir/data/cdtext.bin )
+ $src_dir/data/p1.nrg | $src_dir/data/p1.bin | $src_dir/data/cdda.bin |
$src_dir/data/cdda-mcn.nrg | $src_dir/data/svcdgs.nrg |
$src_dir/data/cdtext.bin | $src_dir/data/udf102.iso )
good_rc=1
;;
*)
diff --git a/test/data/udf102.iso b/test/data/udf102.iso
index
9e088313db7e397052e6a764757643078a41c8f7..2639d0d451f920c69511b6a58bc453a3b05b03b1
100644
GIT binary patch
delta 1545
zcmd5+O-vI}5T4mxwvUZ9+q7V*2B}CiMoVca6fQy&tR@^pjd+r1tY890Fyf&Hnvf>m
zOoQyhi=c@yUNoyQo{SufiB}JBFnZwT#jGB@`7^V$bcw~pgoE?)_Px%VdEd-8Z(4BL
z3x&a@!h?me`)2qKYPq+7FmlSl7O08|$KbQpr7plUOu-e%(bpqEBp-zal9HzhoitK3
z<B*|mKdqIKAbocU&tp`^)1prb#G%eZCniQSH>R$(OebQgSUMK>+|FC`lTQg@By`pQ
zsMy+gUAF{k`g_8h>6M1S{RpyMU^ehaxFsCNU<oHg)m!S8N#3pGJ#0(E#Aksa1wd!K
zs#Vfwg;Dc=A*)B@Pq38^RoNkMpeBYI1R?MBh&=~XzJ{6DBz!p&v;k1Ug_m{{p1z!0
zp#$dKoBDsvd;J<kJk#r7hx7}K{yX*cNxERzb}%9RCO-WO`#;H$*-sL4+s^)7V!!Ps
zA;{)w=;PveUYlDi){z8CxYsg;Hb1Bc|E6a$ci~o~m{*E<wV2n6`MP3WFXnx=>C9~Z
zToDmesH+f?5obNTYP@oHS`62GnHc1D%QRDGz)?7}MI)E6UlRa|obM5BsM<K7TL)1S
zKL`%M!RM2+w>8_$saBuRMn96)*|$uMzb+arWXB6h3;Zg}!%+FvllGE(R{iZIdyD<t
zwb{mvzNH$ph3O885_BTs10fo(gc}3vc`^pYPOW=fXbtbkB6~3m+>vDKx+?N(Rs>V8
zN%45?aQO(Rc{idbW0o2nXyc-f(;s_7-izm!EBU%BrC+!1Sv!4#cZKP6g=-fuLXFY>
z`f~bBJ5EMp-u>L<Y=bBNT}LW^DqbGA7R&>aU*Unl>X-*3-jPUlrn<V*JvM&NT1!GR
R+Q|V|9UM_!>=fU8zX2rRFfafB
literal 784384
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
z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0
z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{
z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL
zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~
z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**
z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0
z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{
z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL
zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~
z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**
z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0
z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{
z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL
zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~
z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**
z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0
z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{
z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL
zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~
z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**
z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0
z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{
z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL
zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~
z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**
z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0
z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{
z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL
zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~
z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**
z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0
z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{
z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL
zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0;L|E_rgf(EPg--Wxj%YW
z|EFC1R;yJwGx~hlpZP!l0R#|00D;B{%(b3Y)OX<L0|5jOKmY**J}Ux_{But;0Qjtw
zH~B;W0R#|0zyfovv&{dg3J4&800Ibn#sp&if0p_GXRO%CE&>Q3fWT*5;Cwv)k7oeq
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
diff --git a/test/testudf.c.in b/test/testudf.c.in
index 210bd12..3d22c6e 100644
--- a/test/testudf.c.in
+++ b/test/testudf.c.in
@@ -1,6 +1,6 @@
/*
Copyright (C) 2013 Rocky Bernstein <[email protected]>
- Copyright (C) 2013 Pete Batard <[email protected]>
+ Copyright (C) 2013-2014 Pete Batard <[email protected]>
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
@@ -44,18 +44,22 @@
#include <cdio/cdio.h>
#include <cdio/udf.h>
+#define EXPECTED_NAME "FéжΘvrier"
+#define EXPECTED_LENGTH 10
+
int
main(int argc, const char *argv[])
{
char const *psz_fname = UDF_IMAGE;
char volume_id[192]; /* 3*64 to account for UTF-8 */
udf_t* p_udf = NULL;
- udf_dirent_t* p_udf_root;
+ udf_dirent_t *p_udf_root, *p_udf_file;
+ int64_t file_length;
p_udf = udf_open(psz_fname);
if (NULL == p_udf) {
- fprintf(stderr, "Sorry, couldn't open %s as an UDF image\n",
+ fprintf(stderr, "Couldn't open %s as an UDF image\n",
psz_fname);
return 1;
}
@@ -66,14 +70,26 @@ main(int argc, const char *argv[])
return 2;
}
- if (udf_get_logical_volume_id(p_udf, volume_id, sizeof(volume_id)) <= 0) {
- fprintf(stderr, "UDF image %s has no logical volume ID\n",
- psz_fname);
+ if ( (udf_get_logical_volume_id(p_udf, volume_id, sizeof(volume_id)) <= 0)
+ || (strcmp(EXPECTED_NAME, volume_id) != 0) ) {
+ fprintf(stderr, "Unexpected UDF logical volume ID\n");
return 3;
}
- printf("-- Volume id: %s\n", volume_id);
+ printf("-- Good! Volume id matches expected UTF-8 data\n");
- udf_close(p_udf);
+ p_udf_file = udf_fopen(p_udf_root, EXPECTED_NAME);
+ if (!p_udf_file) {
+ fprintf(stderr, "Could not locate expected file in UDF image\n");
+ return 4;
+ }
+ printf("-- Good! File name matches expected UTF-8 data\n");
+
+ file_length = udf_get_file_length(p_udf_file);
+ if (file_length != EXPECTED_LENGTH) {
+ fprintf(stderr, "Unexpected UDF file length\n");
+ return 5;
+ }
+ printf("-- Good! File length matches expected length\n");
return 0;
}
--
1.8.5.2.msysgit.0