From a851d66e7c5e2fca091ea1d7e2abf48b4563d993 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Thu, 16 Feb 2012 20:44:16 +0000 Subject: [PATCH] [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 --- src/iso.c | 13 +-- src/libcdio/cdio/ecma_167.h | 44 +++++++--- src/libcdio/driver/utf8.c | 138 +++++++++++++++++++------------ src/libcdio/iso9660/iso9660_fs.c | 89 +++++++++++++++----- src/libcdio/udf/udf_fs.c | 8 +- src/rufus.rc | 12 +-- 6 files changed, 202 insertions(+), 102 deletions(-) diff --git a/src/iso.c b/src/iso.c index 58a94b8c..80177b17 100644 --- a/src/iso.c +++ b/src/iso.c @@ -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, ""); diff --git a/src/libcdio/cdio/ecma_167.h b/src/libcdio/cdio/ecma_167.h index b97cba79..f2c15446 100644 --- a/src/libcdio/cdio/ecma_167.h +++ b/src/libcdio/cdio/ecma_167.h @@ -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; diff --git a/src/libcdio/driver/utf8.c b/src/libcdio/driver/utf8.c index 5ae9adc3..a27bd53d 100644 --- a/src/libcdio/driver/utf8.c +++ b/src/libcdio/driver/utf8.c @@ -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= 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; diff --git a/src/libcdio/udf/udf_fs.c b/src/libcdio/udf/udf_fs.c index 601df95f..c2787e76 100644 --- a/src/libcdio/udf/udf_fs.c +++ b/src/libcdio/udf/udf_fs.c @@ -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; diff --git a/src/rufus.rc b/src/rufus.rc index c6233d0c..36d69b93 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -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 "http://rufus.akeo.ie",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"