[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]; psz_basename = &psz_fullpath[i_length];
p_entlist = iso9660_ifs_readdir(p_iso, psz_path); 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; return 1;
}
_CDIO_LIST_FOREACH(p_entnode, p_entlist) { _CDIO_LIST_FOREACH(p_entnode, p_entlist) {
if (FormatStatus) goto out; if (FormatStatus) goto out;
@ -389,19 +391,18 @@ BOOL ExtractISO(const char* src_iso, const char* dest_dir, bool scan)
goto out; goto out;
try_iso: try_iso:
p_iso = iso9660_open_ext(src_iso, 0xFF); p_iso = iso9660_open_ext(src_iso, ISO_EXTENSION_ALL);
if (p_iso == NULL) { if (p_iso == NULL) {
uprintf("Unable to open image '%s'.\n", src_iso); uprintf("Unable to open image '%s'.\n", src_iso);
goto out; goto out;
} }
i_joliet_level = iso9660_ifs_get_joliet_level(p_iso); i_joliet_level = iso9660_ifs_get_joliet_level(p_iso);
uprintf("Disc image is an ISO9660 image (Joliet = %d)\n", i_joliet_level); 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 (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); safe_strcpy(iso_report.label, sizeof(iso_report.label), vol_id);
else safe_free(vol_id);
} else
iso_report.label[0] = 0; iso_report.label[0] = 0;
} }
r = iso_extract_files(p_iso, ""); 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_extent_ad_t next_integrity_ext;
udf_Uint8_t logvol_contents_use[32]; udf_Uint8_t logvol_contents_use[32];
udf_Uint32_t i_partitions; udf_Uint32_t i_partitions;
union { /* Same MSVC workaround as with struct udf_fileid_desc_s */
udf_Uint32_t imp_use_len; udf_Uint32_t imp_use_len;
union { /* MSVC workaround for multiple zero sized arrays */ struct {
udf_Uint32_t freespace_table[0]; udf_Uint32_t unused;
udf_Uint32_t size_table[0]; udf_Uint32_t data[0];
udf_Uint8_t imp_use[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; } u;
} GNUC_PACKED; } GNUC_PACKED;
@ -572,11 +581,25 @@ struct udf_fileid_desc_s
udf_Uint8_t file_characteristics; udf_Uint8_t file_characteristics;
udf_Uint8_t i_file_id; udf_Uint8_t i_file_id;
udf_long_ad_t icb; udf_long_ad_t icb;
/* 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; udf_Uint16_t i_imp_use;
union { /* MSVC workaround for multiple zero sized arrays */ struct {
udf_Uint8_t imp_use[0]; udf_Uint16_t unused;
udf_Uint8_t file_id[0]; udf_Uint8_t data[0];
udf_Uint8_t padding[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; } u;
} GNUC_PACKED; } GNUC_PACKED;
@ -998,6 +1021,7 @@ struct extended_file_entry
union { /* MSVC workaround for multiple zero sized arrays */ union { /* MSVC workaround for multiple zero sized arrays */
udf_Uint8_t ext_attr[0]; udf_Uint8_t ext_attr[0];
udf_Uint8_t alloc_descs[0]; udf_Uint8_t alloc_descs[0];
udf_Uint8_t pad_to_one_block[2048-216];
} u; } u;
} GNUC_PACKED; } GNUC_PACKED;

View File

@ -221,14 +221,14 @@ 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) * Converts an UTF-16 string to UTF8 (allocate returned string)
* Returns NULL on error * Returns NULL on error
*/ */
static __inline char* wchar_to_utf8(const wchar_t* wstr) static inline char* wchar_to_utf8(const wchar_t* wstr)
{ {
int size = 0; int size = 0;
char* str = NULL; char* str = NULL;
/* Find out the size we need to allocate for our converted string */ /* Find out the size we need to allocate for our converted string */
size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL); size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
if (size <= 1) // An empty string would be size 1 if (size <= 1) /* An empty string would be size 1 */
return NULL; return NULL;
if ((str = (char*)calloc(size, 1)) == NULL) if ((str = (char*)calloc(size, 1)) == NULL)
@ -240,20 +240,20 @@ static __inline char* wchar_to_utf8(const wchar_t* wstr)
} }
return str; return str;
} }
/* /*
* Converts an UTF8 string to UTF-16 (allocate returned string) * Converts an UTF8 string to UTF-16 (allocate returned string)
* Returns NULL on error * Returns NULL on error
*/ */
static __inline wchar_t* utf8_to_wchar(const char* str) static inline wchar_t* utf8_to_wchar(const char* str)
{ {
int size = 0; int size = 0;
wchar_t* wstr = NULL; wchar_t* wstr = NULL;
/* Find out the size we need to allocate for our converted string */ /* Find out the size we need to allocate for our converted string */
size = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); size = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
if (size <= 1) // An empty string would be size 1 if (size <= 1) /* An empty string would be size 1 */
return NULL; return NULL;
if ((wstr = (wchar_t*)calloc(size, sizeof(wchar_t))) == NULL) if ((wstr = (wchar_t*)calloc(size, sizeof(wchar_t))) == NULL)
@ -264,12 +264,41 @@ static __inline wchar_t* utf8_to_wchar(const char* str)
return NULL; return NULL;
} }
return wstr; 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, bool cdio_charset_to_utf8(char *src, size_t src_len, cdio_utf8_t **dst,
const char * src_charset) 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) if (src == NULL || dst == NULL || src_charset == NULL || strcmp(src_charset, "UCS-2BE") != 0)
return false; return false;
@ -279,18 +308,19 @@ bool cdio_charset_to_utf8(char *src, size_t src_len, cdio_utf8_t **dst,
src_len <<=2; src_len <<=2;
} }
/* zero lenght is a headache (LCMapString doesn't support it) /* Eliminate empty strings */
=> eliminate this case first */ if ((src_len < 2) || ((src[0] == 0) && (src[1] == 0))) {
if (src_len == 0) { *dst = NULL;
*dst = (cdio_utf8_t*)malloc(1); return false;
*dst[0] = 0;
return true;
} }
/* Perform byte reversal */
le_src = (wchar_t*)malloc(src_len+2); le_src = (wchar_t*)malloc(src_len+2);
/* WideCharToMultiByte only takes UCS-2LE, and we are fed UCS-2BE for (i=0; i<src_len; i+=2) {
=> perform byte reversal */ ((char*)le_src)[i] = src[i+1];
LCMapStringW(0, LCMAP_BYTEREV, (LPCWSTR)src, src_len, le_src, src_len); ((char*)le_src)[i+1] = src[i];
}
le_src[src_len/2] = 0;
*dst = wchar_to_utf8(le_src); *dst = wchar_to_utf8(le_src);
free(le_src); free(le_src);

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, static long int iso9660_seek_read_framesize (const iso9660_t *p_iso,
void *ptr, lsn_t start, void *ptr, lsn_t start,
long int size, long int size,
@ -294,8 +321,10 @@ iso9660_ifs_get_application_id(iso9660_t *p_iso,
*/ */
if ( cdio_charset_to_utf8(p_iso->svd.application_id, if ( cdio_charset_to_utf8(p_iso->svd.application_id,
ISO_MAX_APPLICATION_ID, ISO_MAX_APPLICATION_ID,
p_psz_app_id, "UCS-2BE")) p_psz_app_id, "UCS-2BE")) {
return true; 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) ); *p_psz_app_id = iso9660_get_application_id( &(p_iso->pvd) );
@ -332,8 +361,10 @@ iso9660_ifs_get_preparer_id(iso9660_t *p_iso,
the PVD, do that. the PVD, do that.
*/ */
if ( cdio_charset_to_utf8(p_iso->svd.preparer_id, ISO_MAX_PREPARER_ID, if ( cdio_charset_to_utf8(p_iso->svd.preparer_id, ISO_MAX_PREPARER_ID,
p_psz_preparer_id, "UCS-2BE") ) p_psz_preparer_id, "UCS-2BE") ) {
return true; strip_trail(p_psz_preparer_id);
return (*p_psz_preparer_id != NULL);
}
} }
#endif /*HAVE_JOLIET*/ #endif /*HAVE_JOLIET*/
*p_psz_preparer_id = iso9660_get_preparer_id( &(p_iso->pvd) ); *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. the PVD, do that.
*/ */
if( cdio_charset_to_utf8(p_iso->svd.publisher_id, ISO_MAX_PUBLISHER_ID, if( cdio_charset_to_utf8(p_iso->svd.publisher_id, ISO_MAX_PUBLISHER_ID,
p_psz_publisher_id, "UCS-2BE") ) p_psz_publisher_id, "UCS-2BE") ) {
return true; strip_trail(p_psz_publisher_id);
return (*p_psz_publisher_id != NULL);
}
} }
#endif /*HAVE_JOLIET*/ #endif /*HAVE_JOLIET*/
*p_psz_publisher_id = iso9660_get_publisher_id( &(p_iso->pvd) ); *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. the PVD, do that.
*/ */
if ( cdio_charset_to_utf8(p_iso->svd.system_id, ISO_MAX_SYSTEM_ID, if ( cdio_charset_to_utf8(p_iso->svd.system_id, ISO_MAX_SYSTEM_ID,
p_psz_system_id, "UCS-2BE") ) p_psz_system_id, "UCS-2BE") ) {
return true; strip_trail(p_psz_system_id);
return (*p_psz_system_id != NULL);
}
} }
#endif /*HAVE_JOLIET*/ #endif /*HAVE_JOLIET*/
*p_psz_system_id = iso9660_get_system_id( &(p_iso->pvd) ); *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. the PVD, do that.
*/ */
if ( cdio_charset_to_utf8(p_iso->svd.volume_id, ISO_MAX_VOLUME_ID, if ( cdio_charset_to_utf8(p_iso->svd.volume_id, ISO_MAX_VOLUME_ID,
p_psz_volume_id, "UCS-2BE") ) p_psz_volume_id, "UCS-2BE") ) {
return true; 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) ); *p_psz_volume_id = iso9660_get_volume_id( &(p_iso->pvd) );
return *p_psz_volume_id != NULL && strlen(*p_psz_volume_id); 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, if ( cdio_charset_to_utf8(p_iso->svd.volume_set_id,
ISO_MAX_VOLUMESET_ID, ISO_MAX_VOLUMESET_ID,
p_psz_volumeset_id, p_psz_volumeset_id,
"UCS-2BE") ) "UCS-2BE") ) {
return true; strip_trail(p_psz_volumeset_id);
return (*p_psz_volumeset_id != NULL);
}
} }
#endif /*HAVE_JOLIET*/ #endif /*HAVE_JOLIET*/
*p_psz_volumeset_id = iso9660_get_volumeset_id( &(p_iso->pvd) ); *p_psz_volumeset_id = iso9660_get_volumeset_id( &(p_iso->pvd) );
@ -494,19 +533,25 @@ bool
iso9660_ifs_read_superblock (iso9660_t *p_iso, iso9660_ifs_read_superblock (iso9660_t *p_iso,
iso_extension_mask_t iso_extension_mask) 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))) if (!p_iso || !iso9660_ifs_read_pvd(p_iso, &(p_iso->pvd)))
return false; return false;
p_svd = &(p_iso->svd);
p_iso->i_joliet_level = 0; p_iso->i_joliet_level = 0;
if (0 != iso9660_iso_seek_read (p_iso, p_svd, ISO_PVD_SECTOR+1, 1)) { /* There may be multiple Secondary Volume Descriptors (eg. El Torito + Joliet) */
if ( ISO_VD_SUPPLEMENTARY == from_711(p_svd->type) ) { for (i=1; (0 != iso9660_iso_seek_read (p_iso, &p_svd, ISO_PVD_SECTOR+i, 1)); i++) {
if (p_svd->escape_sequences[0] == 0x25 if (ISO_VD_END == from_711(p_svd.type) ) /* Last SVD */
&& p_svd->escape_sequences[1] == 0x2f) { break;
switch (p_svd->escape_sequences[2]) { 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: case 0x40:
if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL1) if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL1)
p_iso->i_joliet_level = 1; 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 */ /* 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->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 =
@ -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)) 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->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;
@ -708,8 +708,8 @@ udf_readdir(udf_dirent_t *p_udf_dirent)
p_udf_dirent->psz_name = (char *) p_udf_dirent->psz_name = (char *)
realloc(p_udf_dirent->psz_name, sizeof(char)*i_len+1); realloc(p_udf_dirent->psz_name, sizeof(char)*i_len+1);
unicode16_decode(p_udf_dirent->fid->u.imp_use unicode16_decode(p_udf_dirent->fid->u.imp_use.data
+ p_udf_dirent->fid->i_imp_use, + p_udf_dirent->fid->u.i_imp_use,
i_len, p_udf_dirent->psz_name); i_len, p_udf_dirent->psz_name);
} }
return p_udf_dirent; return p_udf_dirent;

View File

@ -33,7 +33,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 206, 278 IDD_DIALOG DIALOGEX 12, 12, 206, 278
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_APPWINDOW EXSTYLE WS_EX_APPWINDOW
CAPTION "Rufus v1.1.1.136" CAPTION "Rufus v1.1.1.137"
FONT 8, "MS Shell Dlg", 400, 0, 0x1 FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN BEGIN
DEFPUSHBUTTON "Start",IDC_START,94,236,50,14 DEFPUSHBUTTON "Start",IDC_START,94,236,50,14
@ -71,7 +71,7 @@ BEGIN
DEFPUSHBUTTON "OK",IDOK,231,175,50,14,WS_GROUP 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, CONTROL "<a href=""http://rufus.akeo.ie"">http://rufus.akeo.ie</a>",IDC_ABOUT_RUFUS_URL,
"SysLink",WS_TABSTOP,46,47,114,9 "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 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 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 LTEXT "Report bugs or request enhancements at:",IDC_STATIC,46,66,187,8
@ -222,8 +222,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,1,1,136 FILEVERSION 1,1,1,137
PRODUCTVERSION 1,1,1,136 PRODUCTVERSION 1,1,1,137
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -240,13 +240,13 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "akeo.ie" VALUE "CompanyName", "akeo.ie"
VALUE "FileDescription", "Rufus" VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "1.1.1.136" VALUE "FileVersion", "1.1.1.137"
VALUE "InternalName", "Rufus" VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011 Pete Batard (GPL v3)" VALUE "LegalCopyright", "© 2011 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.1.1.136" VALUE "ProductVersion", "1.1.1.137"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"