]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
In ZIP archive file, a filename and comments field is UTF-8 when Language
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Thu, 24 Mar 2011 09:41:01 +0000 (05:41 -0400)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Thu, 24 Mar 2011 09:41:01 +0000 (05:41 -0400)
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

Makefile.am
libarchive/archive_read_support_format_zip.c
libarchive/test/test_read_format_zip_filename.c
libarchive/test/test_read_format_zip_utf8.zip.uu [new file with mode: 0644]

index d27819d18a3c79466f30bc245852d44388762361..a5e8a4e06500af7b8254a808e58112cf9545fc8a 100644 (file)
@@ -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
 
index 49f10d9d2b1f4fe760c5b48ce0dbdc2eec3e9dd0..c64009f5e614a3da71f885341e00272ebe1b56ab 100644 (file)
@@ -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. */
index ea504d469e5731191ab56fc3d3519639fe10cc35..36d08c7f445e0195ecd36882e0fda806959a1622 100644 (file)
@@ -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 (file)
index 0000000..00c2af3
--- /dev/null
@@ -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<N='AT550)``-H6H5-&NR*375X"P`!!.T#
+M```$`0(``&MA;FII4$L!`AX#"@``"```R51T/@````````````````H`&```
+M```````0`.U!`````.BAJ..!H.."B"]55`4``XI:A4UU>`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