[iso] libcdio Joliet and UDF fixes

* Fix for broken UDF access with MSVC on some images
  (eg. Arch Linux)
* Fix for broken Joliet access on ISO9660 images and
  proper Joliet support in iso.c
This commit is contained in:
Pete Batard 2012-02-16 20:44:16 +00:00
parent c79bfa0cb4
commit a851d66e7c
6 changed files with 202 additions and 102 deletions

View File

@ -241,8 +241,10 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path)
psz_basename = &psz_fullpath[i_length];
p_entlist = iso9660_ifs_readdir(p_iso, psz_path);
if (!p_entlist)
if (!p_entlist) {
uprintf("Could not access directory %s\n", psz_path);
return 1;
}
_CDIO_LIST_FOREACH(p_entnode, p_entlist) {
if (FormatStatus) goto out;
@ -389,19 +391,18 @@ BOOL ExtractISO(const char* src_iso, const char* dest_dir, bool scan)
goto out;
try_iso:
p_iso = iso9660_open_ext(src_iso, 0xFF);
p_iso = iso9660_open_ext(src_iso, ISO_EXTENSION_ALL);
if (p_iso == NULL) {
uprintf("Unable to open image '%s'.\n", src_iso);
goto out;
}
i_joliet_level = iso9660_ifs_get_joliet_level(p_iso);
uprintf("Disc image is an ISO9660 image (Joliet = %d)\n", i_joliet_level);
// FIXME: libcdio's Joliet detection seems broken => override
i_joliet_level = ISO_EXTENSION_JOLIET_LEVEL3;
if (scan_only) {
if (iso9660_ifs_get_volume_id(p_iso, &vol_id))
if (iso9660_ifs_get_volume_id(p_iso, &vol_id)) {
safe_strcpy(iso_report.label, sizeof(iso_report.label), vol_id);
else
safe_free(vol_id);
} else
iso_report.label[0] = 0;
}
r = iso_extract_files(p_iso, "");

View File

@ -498,11 +498,20 @@ struct logvol_integrity_desc_s
udf_extent_ad_t next_integrity_ext;
udf_Uint8_t logvol_contents_use[32];
udf_Uint32_t i_partitions;
udf_Uint32_t imp_use_len;
union { /* MSVC workaround for multiple zero sized arrays */
udf_Uint32_t freespace_table[0];
udf_Uint32_t size_table[0];
udf_Uint8_t imp_use[0];
union { /* Same MSVC workaround as with struct udf_fileid_desc_s */
udf_Uint32_t imp_use_len;
struct {
udf_Uint32_t unused;
udf_Uint32_t data[0];
} freespace_table;
struct {
udf_Uint32_t unused;
udf_Uint32_t data[0];
} size_table;
struct {
udf_Uint32_t unused;
udf_Uint32_t data[0];
} imp_use;
} u;
} GNUC_PACKED;
@ -572,11 +581,25 @@ struct udf_fileid_desc_s
udf_Uint8_t file_characteristics;
udf_Uint8_t i_file_id;
udf_long_ad_t icb;
udf_Uint16_t i_imp_use;
union { /* MSVC workaround for multiple zero sized arrays */
udf_Uint8_t imp_use[0];
udf_Uint8_t file_id[0];
udf_Uint8_t padding[0];
/* MSVC workaround for multiple zero sized arrays
Unlike what is the case with GNU, and against logic, an union of zero
sized arrays in the Microsoft world is not zero bytes but one byte!
Thus, for sizeof() is consistent across platforms, we have to use an
ugly workaround that attaches the union to the last non-zero member. */
union {
udf_Uint16_t i_imp_use;
struct {
udf_Uint16_t unused;
udf_Uint8_t data[0];
} imp_use;
struct {
udf_Uint16_t unused;
udf_Uint8_t data[0];
} file_id;
struct {
udf_Uint16_t unused;
udf_Uint8_t data[0];
} padding;
} u;
} GNUC_PACKED;
@ -998,6 +1021,7 @@ struct extended_file_entry
union { /* MSVC workaround for multiple zero sized arrays */
udf_Uint8_t ext_attr[0];
udf_Uint8_t alloc_descs[0];
udf_Uint8_t pad_to_one_block[2048-216];
} u;
} GNUC_PACKED;

View File

@ -221,80 +221,110 @@ bool cdio_charset_to_utf8(char *src, size_t src_len, cdio_utf8_t **dst,
* Converts an UTF-16 string to UTF8 (allocate returned string)
* Returns NULL on error
*/
static __inline char* wchar_to_utf8(const wchar_t* wstr)
{
int size = 0;
char* str = NULL;
static inline char* wchar_to_utf8(const wchar_t* wstr)
{
int size = 0;
char* str = NULL;
/* Find out the size we need to allocate for our converted string */
size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
if (size <= 1) // An empty string would be size 1
return NULL;
/* Find out the size we need to allocate for our converted string */
size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
if (size <= 1) /* An empty string would be size 1 */
return NULL;
if ((str = (char*)calloc(size, 1)) == NULL)
return NULL;
if ((str = (char*)calloc(size, 1)) == NULL)
return NULL;
if (wchar_to_utf8_no_alloc(wstr, str, size) != size) {
free(str);
return NULL;
}
if (wchar_to_utf8_no_alloc(wstr, str, size) != size) {
free(str);
return NULL;
}
return str;
}
return str;
}
/*
* Converts an UTF8 string to UTF-16 (allocate returned string)
* Returns NULL on error
*/
static __inline wchar_t* utf8_to_wchar(const char* str)
{
int size = 0;
wchar_t* wstr = NULL;
static inline wchar_t* utf8_to_wchar(const char* str)
{
int size = 0;
wchar_t* wstr = NULL;
/* Find out the size we need to allocate for our converted string */
size = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
if (size <= 1) // An empty string would be size 1
return NULL;
/* Find out the size we need to allocate for our converted string */
size = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
if (size <= 1) /* An empty string would be size 1 */
return NULL;
if ((wstr = (wchar_t*)calloc(size, sizeof(wchar_t))) == NULL)
return NULL;
if ((wstr = (wchar_t*)calloc(size, sizeof(wchar_t))) == NULL)
return NULL;
if (utf8_to_wchar_no_alloc(str, wstr, size) != size) {
free(wstr);
return NULL;
}
return wstr;
}
if (utf8_to_wchar_no_alloc(str, wstr, size) != size) {
free(wstr);
return NULL;
}
return wstr;
}
bool cdio_charset_from_utf8(cdio_utf8_t * src, char ** dst,
int * dst_len, const char * dst_charset)
{
wchar_t* le_dst;
size_t i, len;
if (src == NULL || dst == NULL || dst_len == NULL || dst_charset == NULL || strcmp(dst_charset, "UTF-8") != 0)
return false;
/* Eliminate empty strings */
le_dst = utf8_to_wchar(src);
if ((le_dst == NULL) || (le_dst[0] == 0)) {
free(le_dst);
return false;
}
/* Perform byte reversal */
len = wcslen(le_dst);
*dst = (char*)calloc(len+1, sizeof(wchar_t));
for (i=0; i<2*len; i++) {
(*dst)[i] = ((char*)le_dst)[i+1];
(*dst)[i+1] = ((char*)le_dst)[i];
}
free(le_dst);
return true;
}
bool cdio_charset_to_utf8(char *src, size_t src_len, cdio_utf8_t **dst,
const char * src_charset)
{
wchar_t* le_src;
{
wchar_t* le_src;
int i;
if (src == NULL || dst == NULL || src_charset == NULL || strcmp(src_charset, "UCS-2BE") != 0)
return false;
if (src == NULL || dst == NULL || src_charset == NULL || strcmp(src_charset, "UCS-2BE") != 0)
return false;
if (src_len == (size_t)-1) {
for (src_len = 0; ((uint16_t*)src)[src_len] !=0; src_len++);
src_len <<=2;
}
if (src_len == (size_t)-1) {
for (src_len = 0; ((uint16_t*)src)[src_len] !=0; src_len++);
src_len <<=2;
}
/* zero lenght is a headache (LCMapString doesn't support it)
=> eliminate this case first */
if (src_len == 0) {
*dst = (cdio_utf8_t*)malloc(1);
*dst[0] = 0;
return true;
}
/* Eliminate empty strings */
if ((src_len < 2) || ((src[0] == 0) && (src[1] == 0))) {
*dst = NULL;
return false;
}
le_src = (wchar_t*)malloc(src_len+2);
/* WideCharToMultiByte only takes UCS-2LE, and we are fed UCS-2BE
=> perform byte reversal */
LCMapStringW(0, LCMAP_BYTEREV, (LPCWSTR)src, src_len, le_src, src_len);
*dst = wchar_to_utf8(le_src);
free(le_src);
/* Perform byte reversal */
le_src = (wchar_t*)malloc(src_len+2);
for (i=0; i<src_len; i+=2) {
((char*)le_src)[i] = src[i+1];
((char*)le_src)[i+1] = src[i];
}
le_src[src_len/2] = 0;
*dst = wchar_to_utf8(le_src);
free(le_src);
return (*dst != NULL);
return (*dst != NULL);
}
#endif /* HAVE_ICONV */

View File

@ -85,6 +85,33 @@ struct _iso9660_s {
*/
};
/*!
Change trailing blanks in null-terminated *str to nulls
If the end result is an empty string, *str is freed
*/
static void
strip_trail (char** str)
{
int j;
if (*str == NULL)
return;
for (j = strlen (*str) - 1; j >= 0; j--)
{
if ((*str)[j] != ' ')
break;
(*str)[j] = '\0';
}
if ((*str)[0] == 0)
{
free(*str);
*str = NULL;
}
}
static long int iso9660_seek_read_framesize (const iso9660_t *p_iso,
void *ptr, lsn_t start,
long int size,
@ -294,10 +321,12 @@ iso9660_ifs_get_application_id(iso9660_t *p_iso,
*/
if ( cdio_charset_to_utf8(p_iso->svd.application_id,
ISO_MAX_APPLICATION_ID,
p_psz_app_id, "UCS-2BE"))
return true;
p_psz_app_id, "UCS-2BE")) {
strip_trail(p_psz_app_id);
return (*p_psz_app_id != NULL);
}
}
#endif /*HAVE_JOLIET*/
#endif /*HAVE_JOLIET*/
*p_psz_app_id = iso9660_get_application_id( &(p_iso->pvd) );
return *p_psz_app_id != NULL && strlen(*p_psz_app_id);
}
@ -332,8 +361,10 @@ iso9660_ifs_get_preparer_id(iso9660_t *p_iso,
the PVD, do that.
*/
if ( cdio_charset_to_utf8(p_iso->svd.preparer_id, ISO_MAX_PREPARER_ID,
p_psz_preparer_id, "UCS-2BE") )
return true;
p_psz_preparer_id, "UCS-2BE") ) {
strip_trail(p_psz_preparer_id);
return (*p_psz_preparer_id != NULL);
}
}
#endif /*HAVE_JOLIET*/
*p_psz_preparer_id = iso9660_get_preparer_id( &(p_iso->pvd) );
@ -360,8 +391,10 @@ bool iso9660_ifs_get_publisher_id(iso9660_t *p_iso,
the PVD, do that.
*/
if( cdio_charset_to_utf8(p_iso->svd.publisher_id, ISO_MAX_PUBLISHER_ID,
p_psz_publisher_id, "UCS-2BE") )
return true;
p_psz_publisher_id, "UCS-2BE") ) {
strip_trail(p_psz_publisher_id);
return (*p_psz_publisher_id != NULL);
}
}
#endif /*HAVE_JOLIET*/
*p_psz_publisher_id = iso9660_get_publisher_id( &(p_iso->pvd) );
@ -389,8 +422,10 @@ bool iso9660_ifs_get_system_id(iso9660_t *p_iso,
the PVD, do that.
*/
if ( cdio_charset_to_utf8(p_iso->svd.system_id, ISO_MAX_SYSTEM_ID,
p_psz_system_id, "UCS-2BE") )
return true;
p_psz_system_id, "UCS-2BE") ) {
strip_trail(p_psz_system_id);
return (*p_psz_system_id != NULL);
}
}
#endif /*HAVE_JOLIET*/
*p_psz_system_id = iso9660_get_system_id( &(p_iso->pvd) );
@ -418,10 +453,12 @@ bool iso9660_ifs_get_volume_id(iso9660_t *p_iso,
the PVD, do that.
*/
if ( cdio_charset_to_utf8(p_iso->svd.volume_id, ISO_MAX_VOLUME_ID,
p_psz_volume_id, "UCS-2BE") )
return true;
p_psz_volume_id, "UCS-2BE") ) {
strip_trail(p_psz_volume_id);
return (*p_psz_volume_id != NULL);
}
}
#endif /* HAVE_JOLIET */
#endif /*HAVE_JOLIET*/
*p_psz_volume_id = iso9660_get_volume_id( &(p_iso->pvd) );
return *p_psz_volume_id != NULL && strlen(*p_psz_volume_id);
}
@ -449,8 +486,10 @@ bool iso9660_ifs_get_volumeset_id(iso9660_t *p_iso,
if ( cdio_charset_to_utf8(p_iso->svd.volume_set_id,
ISO_MAX_VOLUMESET_ID,
p_psz_volumeset_id,
"UCS-2BE") )
return true;
"UCS-2BE") ) {
strip_trail(p_psz_volumeset_id);
return (*p_psz_volumeset_id != NULL);
}
}
#endif /*HAVE_JOLIET*/
*p_psz_volumeset_id = iso9660_get_volumeset_id( &(p_iso->pvd) );
@ -494,19 +533,25 @@ bool
iso9660_ifs_read_superblock (iso9660_t *p_iso,
iso_extension_mask_t iso_extension_mask)
{
iso9660_svd_t *p_svd; /* Secondary volume descriptor. */
iso9660_svd_t p_svd; /* Secondary volume descriptor. */
int i;
if (!p_iso || !iso9660_ifs_read_pvd(p_iso, &(p_iso->pvd)))
return false;
p_svd = &(p_iso->svd);
p_iso->i_joliet_level = 0;
if (0 != iso9660_iso_seek_read (p_iso, p_svd, ISO_PVD_SECTOR+1, 1)) {
if ( ISO_VD_SUPPLEMENTARY == from_711(p_svd->type) ) {
if (p_svd->escape_sequences[0] == 0x25
&& p_svd->escape_sequences[1] == 0x2f) {
switch (p_svd->escape_sequences[2]) {
/* There may be multiple Secondary Volume Descriptors (eg. El Torito + Joliet) */
for (i=1; (0 != iso9660_iso_seek_read (p_iso, &p_svd, ISO_PVD_SECTOR+i, 1)); i++) {
if (ISO_VD_END == from_711(p_svd.type) ) /* Last SVD */
break;
if ( ISO_VD_SUPPLEMENTARY == from_711(p_svd.type) ) {
/* We're only interested in Joliet => make sure the SVD isn't overwritten */
if (p_iso->i_joliet_level == 0)
memcpy(&(p_iso->svd), &p_svd, sizeof(iso9660_svd_t));
if (p_svd.escape_sequences[0] == 0x25
&& p_svd.escape_sequences[1] == 0x2f) {
switch (p_svd.escape_sequences[2]) {
case 0x40:
if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL1)
p_iso->i_joliet_level = 1;

View File

@ -659,7 +659,7 @@ udf_readdir(udf_dirent_t *p_udf_dirent)
/* advance to next File Identifier Descriptor */
/* FIXME: need to advance file entry (fe) as well. */
uint32_t ofs = 4 *
((sizeof(*(p_udf_dirent->fid)) + p_udf_dirent->fid->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 =
@ -686,7 +686,7 @@ udf_readdir(udf_dirent_t *p_udf_dirent)
if (p_udf_dirent->fid && !udf_checktag(&(p_udf_dirent->fid->tag), TAGID_FID))
{
uint32_t ofs =
4 * ((sizeof(*p_udf_dirent->fid) + p_udf_dirent->fid->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->dir_left -= ofs;
@ -708,8 +708,8 @@ udf_readdir(udf_dirent_t *p_udf_dirent)
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
+ p_udf_dirent->fid->i_imp_use,
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;

View File

@ -33,7 +33,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 206, 278
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW
CAPTION "Rufus v1.1.1.136"
CAPTION "Rufus v1.1.1.137"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "Start",IDC_START,94,236,50,14
@ -71,7 +71,7 @@ BEGIN
DEFPUSHBUTTON "OK",IDOK,231,175,50,14,WS_GROUP
CONTROL "<a href=""http://rufus.akeo.ie"">http://rufus.akeo.ie</a>",IDC_ABOUT_RUFUS_URL,
"SysLink",WS_TABSTOP,46,47,114,9
LTEXT "Version 1.1.1 (Build 136)",IDC_STATIC,46,19,78,8
LTEXT "Version 1.1.1 (Build 137)",IDC_STATIC,46,19,78,8
PUSHBUTTON "License...",IDC_ABOUT_LICENSE,46,175,50,14,WS_GROUP
EDITTEXT IDC_ABOUT_COPYRIGHTS,46,107,235,63,ES_MULTILINE | ES_READONLY | WS_VSCROLL
LTEXT "Report bugs or request enhancements at:",IDC_STATIC,46,66,187,8
@ -222,8 +222,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,1,1,136
PRODUCTVERSION 1,1,1,136
FILEVERSION 1,1,1,137
PRODUCTVERSION 1,1,1,137
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -240,13 +240,13 @@ BEGIN
BEGIN
VALUE "CompanyName", "akeo.ie"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "1.1.1.136"
VALUE "FileVersion", "1.1.1.137"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
VALUE "OriginalFilename", "rufus.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "1.1.1.136"
VALUE "ProductVersion", "1.1.1.137"
END
END
BLOCK "VarFileInfo"