From: Michihiro NAKAJIMA Date: Thu, 24 Mar 2011 09:41:01 +0000 (-0400) Subject: In ZIP archive file, a filename and comments field is UTF-8 when Language X-Git-Tag: v3.0.0a~609 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=136ef2d77c2cbf3a1a5440467ef31dcf42cd931b;p=thirdparty%2Flibarchive.git In ZIP archive file, a filename and comments field is UTF-8 when Language encoding flag (Bit 11 of the general purpose bit flag) is set. So we should convert filenames from UTF-8 to current locale. SVN-Revision: 3069 --- diff --git a/Makefile.am b/Makefile.am index d27819d18..a5e8a4e06 100644 --- a/Makefile.am +++ b/Makefile.am @@ -460,6 +460,7 @@ libarchive_test_EXTRA_DIST=\ libarchive/test/test_read_format_tar_empty_filename.tar.uu \ libarchive/test/test_read_format_zip.zip.uu \ libarchive/test/test_read_format_zip_cp932.zip.uu \ + libarchive/test/test_read_format_zip_utf8.zip.uu \ libarchive/test/CMakeLists.txt \ libarchive/test/README diff --git a/libarchive/archive_read_support_format_zip.c b/libarchive/archive_read_support_format_zip.c index 49f10d9d2..c64009f5e 100644 --- a/libarchive/archive_read_support_format_zip.c +++ b/libarchive/archive_read_support_format_zip.c @@ -98,6 +98,7 @@ struct zip { }; #define ZIP_LENGTH_AT_END 8 +#define ZIP_UTF8_NAME (1<<11) struct zip_file_header { char signature[4]; @@ -457,6 +458,7 @@ zip_read_file_header(struct archive_read *a, struct archive_entry *entry, { const struct zip_file_header *p; const void *h; + int ret = ARCHIVE_OK; if ((p = __archive_read_ahead(a, sizeof *p, NULL)) == NULL) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, @@ -494,8 +496,26 @@ zip_read_file_header(struct archive_read *a, struct archive_entry *entry, "Truncated ZIP file header"); return (ARCHIVE_FATAL); } - archive_strncpy_from_locale(&a->archive, &zip->pathname, - h, zip->filename_length, zip->charset); + if (zip->charset == NULL && (zip->flags & ZIP_UTF8_NAME) != 0) { + /* The filename is stored to be UTF-8. */ + if (archive_strncpy_from_locale(&a->archive, &zip->pathname, + h, zip->filename_length, "UTF-8") != 0) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Pathname cannot be converted " + "from UTF-8 to current locale."); + ret = ARCHIVE_WARN; + } + } else { + if (archive_strncpy_from_locale(&a->archive, &zip->pathname, + h, zip->filename_length, zip->charset) != 0) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Pathname cannot be converted " + "from %s to current locale.", zip->charset); + ret = ARCHIVE_WARN; + } + } __archive_read_consume(a, zip->filename_length); archive_entry_set_pathname(entry, zip->pathname.s); @@ -538,7 +558,7 @@ zip_read_file_header(struct archive_read *a, struct archive_entry *entry, zip->compression_name); a->archive.archive_format_name = zip->format_name; - return (ARCHIVE_OK); + return (ret); } /* Convert an MSDOS-style date/time into Unix-style time. */ diff --git a/libarchive/test/test_read_format_zip_filename.c b/libarchive/test/test_read_format_zip_filename.c index ea504d469..36d08c7f4 100644 --- a/libarchive/test/test_read_format_zip_filename.c +++ b/libarchive/test/test_read_format_zip_filename.c @@ -75,8 +75,8 @@ test_read_format_zip_filename_CP932_eucJP(const char *refname) assertEqualIntA(a, ARCHIVE_FORMAT_ZIP, archive_format(a)); /* Close the archive. */ -cleanup: assertEqualInt(ARCHIVE_OK, archive_read_close(a)); +cleanup: assertEqualInt(ARCHIVE_OK, archive_read_free(a)); } @@ -128,7 +128,132 @@ test_read_format_zip_filename_CP932_UTF8(const char *refname) assertEqualIntA(a, ARCHIVE_FORMAT_ZIP, archive_format(a)); /* Close the archive. */ + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); +cleanup: + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + +static void +test_read_format_zip_filename_UTF8_eucJP(const char *refname) +{ + struct archive *a; + struct archive_entry *ae; + + /* + * Read ZIP filename in ja_JP.eucJP without charset option + * because the file name in the sample file is UTF-8 and + * Bit 11 of its general purpose bit flag is set. + */ + if (NULL == setlocale(LC_ALL, "ja_JP.eucJP")) { + skipping("ja_JP.eucJP locale not available on this system."); + return; + } + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a)); + if (ARCHIVE_OK != archive_read_set_options(a, "charset=UTF-8")) { + skipping("This system cannot convert character-set" + " from UTF-8 to eucJP."); + goto cleanup; + } + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); + + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_compression_all(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_filename(a, refname, 10240)); + + /* Verify directory file. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualInt(AE_IFDIR, archive_entry_filetype(ae)); + assertEqualString("\xc9\xbd\xa4\xc0\xa4\xe8\x2f", + archive_entry_pathname(ae)); + assertEqualInt(0, archive_entry_size(ae)); + + /* Verify regular file. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); + assertEqualString( + "\xc9\xbd\xa4\xc0\xa4\xe8\x2f\xb0\xec\xcd\xf7\xc9\xbd\x2e\x74\x78\x74", + archive_entry_pathname(ae)); + assertEqualInt(5, archive_entry_size(ae)); + + /* Verify regular file. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); + assertEqualString( + "\xc9\xbd\xa4\xc0\xa4\xe8\x2f\xb4\xc1\xbb\xfa\x2e\x74\x78\x74", + archive_entry_pathname(ae)); + assertEqualInt(5, archive_entry_size(ae)); + + + /* End of archive. */ + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); + + /* Verify archive format. */ + assertEqualIntA(a, ARCHIVE_COMPRESSION_NONE, archive_compression(a)); + assertEqualIntA(a, ARCHIVE_FORMAT_ZIP, archive_format(a)); + + /* Close the archive. */ + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); cleanup: + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + +static void +test_read_format_zip_filename_UTF8_UTF8(const char *refname) +{ + struct archive *a; + struct archive_entry *ae; + + /* + * Read ZIP filename in ja_JP.UTF-8 without charset option + * because the file name in the sample file is UTF-8 and + * Bit 11 of its general purpose bit flag is set. + */ + if (NULL == setlocale(LC_ALL, "ja_JP.UTF-8")) { + skipping("ja_JP.UTF-8 locale not available on this system."); + return; + } + + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_compression_all(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_filename(a, refname, 10240)); + + /* Verify directory file. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualInt(AE_IFDIR, archive_entry_filetype(ae)); + assertEqualString("\xe8\xa1\xa8\xe3\x81\xa0\xe3\x82\x88\x2f", + archive_entry_pathname(ae)); + assertEqualInt(0, archive_entry_size(ae)); + + /* Verify regular file. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); + assertEqualString("\xe8\xa1\xa8\xe3\x81\xa0\xe3\x82\x88\x2f" + "\xe4\xb8\x80\xe8\xa6\xa7\xe8\xa1\xa8\x2e\x74\x78\x74", + archive_entry_pathname(ae)); + assertEqualInt(5, archive_entry_size(ae)); + + /* Verify regular file. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); + assertEqualString("\xe8\xa1\xa8\xe3\x81\xa0\xe3\x82\x88\x2f" + "\xe6\xbc\xa2\xe5\xad\x97\x2e\x74\x78\x74", + archive_entry_pathname(ae)); + assertEqualInt(5, archive_entry_size(ae)); + + + /* End of archive. */ + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); + + /* Verify archive format. */ + assertEqualIntA(a, ARCHIVE_COMPRESSION_NONE, archive_compression(a)); + assertEqualIntA(a, ARCHIVE_FORMAT_ZIP, archive_format(a)); + + /* Close the archive. */ assertEqualInt(ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); } @@ -136,8 +261,12 @@ cleanup: DEFINE_TEST(test_read_format_zip_filename) { const char *refname = "test_read_format_zip_cp932.zip"; + const char *refname2 = "test_read_format_zip_utf8.zip"; extract_reference_file(refname); test_read_format_zip_filename_CP932_eucJP(refname); test_read_format_zip_filename_CP932_UTF8(refname); + extract_reference_file(refname2); + test_read_format_zip_filename_UTF8_eucJP(refname2); + test_read_format_zip_filename_UTF8_UTF8(refname2); } diff --git a/libarchive/test/test_read_format_zip_utf8.zip.uu b/libarchive/test/test_read_format_zip_utf8.zip.uu new file mode 100644 index 000000000..00c2af337 --- /dev/null +++ b/libarchive/test/test_read_format_zip_utf8.zip.uu @@ -0,0 +1,15 @@ +begin 644 test_read_format_zip_utf8.zip +M4$L#!`H```@``,E4=#X````````````````*`!P`Z*&HXX&@XX*(+U54"0`# +MBEJ%3;[UBDUU>`L``03M`P``!`$"``!02P,$"@``"```]51T/H*)T?<%```` +M!0```!<`'`#HH:CC@:#C@H@OY+B`Z*:GZ*&H+G1X=%54"0`#WEJ%31KLBDUU +M>`L``03M`P``!`$"``!(96QL;U!+`P0*```(``"V5'0^W)UO0@4````%```` +M%``<`.BAJ..!H.."B"_FO*+EK9`L``03M`P``!`$" +M``!02P$"'@,*```(``#U5'0^@HG1]P4````%````%P`8```````!````[8%$ +M````Z*&HXX&@XX*(+^2X@.BFI^BAJ"YT>'155`4``]Y:A4UU>`L``03M`P`` +M!`$"``!02P$"'@,*```(``"V5'0^W)UO0@4````%````%``8```````!```` +M[8&:````Z*&HXX&@XX*(+^:\HN6MERYT>'155`4``VA:A4UU>`L``03M`P`` +;!`$"``!02P4&``````,``P`'`0``[0`````` +` +end