]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Introduce
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Thu, 7 Apr 2011 09:52:51 +0000 (05:52 -0400)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Thu, 7 Apr 2011 09:52:51 +0000 (05:52 -0400)
   archive_string_default_conversion_for_read() and
   archive_string_default_conversion_for_write()
for conversion CP_ACP <==> CP_OEMCP(as charset for archive file) on Windows platform.
Those functions on non-Windows platform always return NULL.

SVN-Revision: 3172

libarchive/archive_read_support_format_tar.c
libarchive/archive_read_support_format_zip.c
libarchive/archive_string.c
libarchive/archive_string.h
libarchive/archive_write_set_format_gnutar.c
libarchive/archive_write_set_format_ustar.c
libarchive/archive_write_set_format_zip.c

index 7ad5358ad444def2a437fe8e9740ed84a20b7e08..16db2563233113c2f13d83b6e054f902c1ed11e3 100644 (file)
@@ -146,6 +146,8 @@ struct tar {
        struct archive_string_conv *opt_sconv;
        struct archive_string_conv *sconv;
        struct archive_string_conv *sconv_acl;
+       struct archive_string_conv *sconv_default;
+       int                      init_default_conversion;
 };
 
 static int     archive_block_is_null(const unsigned char *p);
@@ -449,8 +451,16 @@ archive_read_format_tar_read_header(struct archive_read *a,
        tar->sparse_last = NULL;
        tar->realsize = -1; /* Mark this as "unset" */
 
-       /* Set a default character-set of names in an archive file. */
+       /* Setup default string conversion. */
        tar->sconv = tar->opt_sconv;
+       if (tar->sconv == NULL) {
+               if (!tar->init_default_conversion) {
+                       tar->sconv_default =
+                           archive_string_default_conversion_for_read(&(a->archive));
+                       tar->init_default_conversion = 1;
+               }
+               tar->sconv = tar->sconv_default;
+       }
 
        r = tar_read_header(a, tar, entry, &unconsumed);
 
index eae96cfe8c4c18d0b9c6fe494d362cd49643c861..7f26eec8c02a3d89e99c40474eecfd35e385b3e7 100644 (file)
@@ -94,7 +94,9 @@ struct zip {
        struct archive_string   pathname;
        struct archive_string   extra;
        struct archive_string_conv *sconv;
+       struct archive_string_conv *sconv_default;
        struct archive_string_conv *sconv_utf8;
+       int                             init_default_conversion;
        char    format_name[64];
 };
 
@@ -463,8 +465,16 @@ zip_read_file_header(struct archive_read *a, struct archive_entry *entry,
 {
        const struct zip_file_header *p;
        const void *h;
+       struct archive_string_conv *sconv;
        int ret = ARCHIVE_OK;
 
+       /* Setup default conversion. */
+       if (zip->sconv == NULL && !zip->init_default_conversion) {
+               zip->sconv_default =
+                   archive_string_default_conversion_for_read(&(a->archive));
+               zip->init_default_conversion = 1;
+       }
+
        if ((p = __archive_read_ahead(a, sizeof *p, NULL)) == NULL) {
                archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
                    "Truncated ZIP file header");
@@ -501,7 +511,9 @@ zip_read_file_header(struct archive_read *a, struct archive_entry *entry,
                    "Truncated ZIP file header");
                return (ARCHIVE_FATAL);
        }
-       if (zip->sconv == NULL && (zip->flags & ZIP_UTF8_NAME) != 0) {
+       if (zip->sconv != NULL)
+               sconv = zip->sconv;
+       else if (zip->flags & ZIP_UTF8_NAME) {
                /* The filename is stored to be UTF-8. */
                if (zip->sconv_utf8 == NULL) {
                        zip->sconv_utf8 =
@@ -510,24 +522,18 @@ zip_read_file_header(struct archive_read *a, struct archive_entry *entry,
                        if (zip->sconv_utf8 == NULL)
                                return (ARCHIVE_FATAL);
                }
-               if (archive_strncpy_in_locale(&zip->pathname,
-                   h, zip->filename_length, zip->sconv_utf8) != 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_in_locale(&zip->pathname,
-                   h, zip->filename_length, zip->sconv) != 0) {
-                       archive_set_error(&a->archive,
-                           ARCHIVE_ERRNO_FILE_FORMAT,
-                           "Pathname cannot be converted "
-                           "from %s to current locale.",
-                           archive_string_conversion_charset_name(zip->sconv));
-                       ret = ARCHIVE_WARN;
-               }
+               sconv = zip->sconv_utf8;
+       } else
+               sconv = zip->sconv_default;
+
+       if (archive_strncpy_in_locale(&zip->pathname,
+           h, zip->filename_length, sconv) != 0) {
+               archive_set_error(&a->archive,
+                   ARCHIVE_ERRNO_FILE_FORMAT,
+                   "Pathname cannot be converted "
+                   "from %s to current locale.",
+                   archive_string_conversion_charset_name(sconv));
+               ret = ARCHIVE_WARN;
        }
        __archive_read_consume(a, zip->filename_length);
        archive_entry_set_pathname(entry, zip->pathname.s);
index 674c4011b77cb33f460abe510a70697be0220fdd..701f89c84b8b9b41154ecea1c433ea38713e70f3 100644 (file)
@@ -881,6 +881,53 @@ archive_string_conversion_from_charset(struct archive *a, const char *charset,
        return (get_sconv_object(a, charset, get_current_charset(a), flag));
 }
 
+/*
+ * archive_string_default_conversion_*_archive() are provided for Windows
+ * platform because other archiver application use CP_OEMCP for
+ * MultiByteToWideChar() and WideCharToMultiByte() for the filenames
+ * in tar or zip files. But mbstowcs/wcstombs(CRT) usually use CP_ACP
+ * unless you use setlocale(LC_ALL, ".OCP")(specify CP_OEMCP).
+ * So we should make a string conversion between CP_ACP and CP_OEMCP
+ * for compatibillty.
+ */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+struct archive_string_conv *
+archive_string_default_conversion_for_read(struct archive *a)
+{
+       const char *cur_charset = get_current_charset(a);
+
+       if (a->current_codepage == GetOEMCP())
+               return (NULL);/* no conversion. */
+       return (get_sconv_object(a, "CP_OEMCP", cur_charset,
+           SCONV_FROM_CHARSET));
+}
+
+struct archive_string_conv *
+archive_string_default_conversion_for_write(struct archive *a)
+{
+       const char *cur_charset = get_current_charset(a);
+
+       if (a->current_codepage == GetOEMCP())
+               return (NULL);/* no conversion. */
+       return (get_sconv_object(a, "CP_OEMCP", cur_charset,
+           SCONV_TO_CHARSET));
+}
+#else
+struct archive_string_conv *
+archive_string_default_conversion_for_read(struct archive *a)
+{
+       (void)a; /* UNUSED */
+       return (NULL);
+}
+
+struct archive_string_conv *
+archive_string_default_conversion_for_write(struct archive *a)
+{
+       (void)a; /* UNUSED */
+       return (NULL);
+}
+#endif
+
 /*
  * Dispose of all character conversion objects in the archive object.
  */
index 816e1edad6cb0b86240eabdcd3e9ba94e0979efb..65c04e7f340eff56c7004a49c03a659a443f4477 100644 (file)
@@ -87,12 +87,22 @@ int
 archive_string_append_from_wcs_to_mbs(struct archive *, struct archive_string *, const wchar_t *, size_t);
 
 
-/* Test that platform support a character-set conversion.
- * Return -1 and set a error message if the conversion is not supported. */
+/* Create a string conversion object.
+ * Return NULL and set a error message if the conversion is not supported
+ * on the platform. */
 struct archive_string_conv *
 archive_string_conversion_to_charset(struct archive *, const char *, int);
 struct archive_string_conv *
 archive_string_conversion_from_charset(struct archive *, const char *, int);
+/* Create the default string conversion object for reading/writing an archive.
+ * Return NULL if the conversion is unneeded.
+ * Note: On non Windows platform this always returns NULL.
+ */
+struct archive_string_conv *
+archive_string_default_conversion_for_read(struct archive *);
+struct archive_string_conv *
+archive_string_default_conversion_for_write(struct archive *);
+/* Dispose of a string conversion object. */
 void
 archive_string_conversion_free(struct archive *);
 const char *
index 140cd7f9ef79241cae8f3499706ad18281197d17..4a091f2c664d0d4c7a64f50f9c05d6d606528707 100644 (file)
@@ -54,6 +54,8 @@ struct gnutar {
        struct archive_string l_uname;
        struct archive_string l_gname;
        struct archive_string_conv *opt_sconv;
+       struct archive_string_conv *sconv_default;
+       int init_default_conversion;
 };
 
 /*
@@ -271,9 +273,21 @@ archive_write_gnutar_header(struct archive_write *a, struct archive_entry *entry
        int tartype;
        const char *linkname;
        struct gnutar *gnutar;
+       struct archive_string_conv *sconv;
 
        gnutar = (struct gnutar *)a->format_data;
 
+       /* Setup default string conversion. */
+       if (gnutar->opt_sconv == NULL) {
+               if (!gnutar->init_default_conversion) {
+                       gnutar->sconv_default =
+                           archive_string_default_conversion_for_write(&(a->archive));
+                       gnutar->init_default_conversion = 1;
+               }
+               sconv = gnutar->sconv_default;
+       } else
+               sconv = gnutar->opt_sconv;
+
        /* Only regular files (not hardlinks) have data. */
        if (archive_entry_hardlink(entry) != NULL ||
            archive_entry_symlink(entry) != NULL ||
@@ -303,36 +317,36 @@ archive_write_gnutar_header(struct archive_write *a, struct archive_entry *entry
        }
 
        r = archive_strcpy_in_locale(&(gnutar->l_pathname),
-           archive_entry_pathname(entry), gnutar->opt_sconv);
+           archive_entry_pathname(entry), sconv);
        if (r != 0) {
                archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
                    "Can't translate pathname '%s' to %s",
                    archive_entry_pathname(entry),
-                   archive_string_conversion_charset_name(gnutar->opt_sconv));
+                   archive_string_conversion_charset_name(sconv));
                ret2 = ARCHIVE_WARN;
        }
        if (archive_entry_uname(entry) != NULL) {
                r = archive_strcpy_in_locale(&(gnutar->l_uname),
-                   archive_entry_uname(entry), gnutar->opt_sconv);
+                   archive_entry_uname(entry), sconv);
                if (r != 0) {
                        archive_set_error(&a->archive,
                            ARCHIVE_ERRNO_FILE_FORMAT,
                            "Can't translate uname '%s' to %s",
                            archive_entry_uname(entry),
-                           archive_string_conversion_charset_name(gnutar->opt_sconv));
+                           archive_string_conversion_charset_name(sconv));
                        ret2 = ARCHIVE_WARN;
                }
        } else
                archive_string_empty(&(gnutar->l_uname));
        if (archive_entry_gname(entry) != NULL) {
                archive_strcpy_in_locale(&(gnutar->l_gname),
-                   archive_entry_gname(entry), gnutar->opt_sconv);
+                   archive_entry_gname(entry), sconv);
                if (r != 0) {
                        archive_set_error(&a->archive,
                            ARCHIVE_ERRNO_FILE_FORMAT,
                            "Can't translate gname '%s' to %s",
                            archive_entry_gname(entry),
-                           archive_string_conversion_charset_name(gnutar->opt_sconv));
+                           archive_string_conversion_charset_name(sconv));
                        ret2 = ARCHIVE_WARN;
                }
        } else
@@ -344,13 +358,13 @@ archive_write_gnutar_header(struct archive_write *a, struct archive_entry *entry
                linkname = archive_entry_symlink(entry);
        if (linkname != NULL) {
                archive_strcpy_in_locale(&(gnutar->l_linkname),
-                   linkname, gnutar->opt_sconv);
+                   linkname, sconv);
                if (r != 0) {
                        archive_set_error(&a->archive,
                            ARCHIVE_ERRNO_FILE_FORMAT,
                            "Can't translate linkname '%s' to %s",
                            linkname,
-                           archive_string_conversion_charset_name(gnutar->opt_sconv));
+                           archive_string_conversion_charset_name(sconv));
                        ret2 = ARCHIVE_WARN;
                }
        } else
index 1957530ef50b58c345b794223b9cee657708b961..ca0a1501419a7dd9b07c2a6b34446703e33e6803 100644 (file)
@@ -49,6 +49,8 @@ struct ustar {
        uint64_t        entry_padding;
 
        struct archive_string_conv *opt_sconv;
+       struct archive_string_conv *sconv_default;
+       int     init_default_conversion;
 };
 
 /*
@@ -234,10 +236,22 @@ archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
        char buff[512];
        int ret, ret2;
        struct ustar *ustar;
+       struct archive_string_conv *sconv;
 
        ustar = (struct ustar *)a->format_data;
 
-        /* Sanity check. */
+       /* Setup default string conversion. */
+       if (ustar->opt_sconv == NULL) {
+               if (!ustar->init_default_conversion) {
+                       ustar->sconv_default =
+                           archive_string_default_conversion_for_write(&(a->archive));
+                       ustar->init_default_conversion = 1;
+               }
+               sconv = ustar->sconv_default;
+       } else
+               sconv = ustar->opt_sconv;
+
+       /* Sanity check. */
        if (archive_entry_pathname(entry) == NULL) {
                archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
                    "Can't record entry in tar file without pathname");
@@ -272,8 +286,7 @@ archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
                }
        }
 
-       ret = __archive_write_format_header_ustar(a, buff, entry, -1, 1,
-           ustar->opt_sconv);
+       ret = __archive_write_format_header_ustar(a, buff, entry, -1, 1, sconv);
        if (ret < ARCHIVE_WARN)
                return (ret);
        ret2 = __archive_write_output(a, buff, 512);
index a12d52a42a928f568aea1a043801151999822847..5f71a9ce01dce6ae2e25c83cbf98334e3efc1306 100644 (file)
@@ -192,6 +192,8 @@ struct zip {
        enum compression compression;
        int flags;
        struct archive_string_conv *opt_sconv;
+       struct archive_string_conv *sconv_default;
+       int     init_default_conversion;
 
 #ifdef HAVE_ZLIB_H
        z_stream stream;
@@ -327,6 +329,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
        struct zip_extra_data_local e;
        struct zip_data_descriptor *d;
        struct zip_file_header_link *l;
+       struct archive_string_conv *sconv;
        int ret, ret2 = ARCHIVE_OK;
        int64_t size;
        mode_t type;
@@ -344,6 +347,13 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
                archive_entry_set_size(entry, 0);
 
        zip = a->format_data;
+       /* Setup default conversion. */
+       if (zip->opt_sconv == NULL && !zip->init_default_conversion) {
+               zip->sconv_default =
+                   archive_string_default_conversion_for_write(&(a->archive));
+               zip->init_default_conversion = 1;
+       }
+
        if (zip->flags == 0) {
                /* Initialize the general purpose flags. */
                zip->flags = ZIP_FLAGS;
@@ -370,14 +380,18 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
        }
        l->entry = archive_entry_clone(entry);
        l->flags = zip->flags;
-       if (zip->opt_sconv != NULL) {
+       if (zip->opt_sconv != NULL)
+               sconv = zip->opt_sconv;
+       else
+               sconv = zip->sconv_default;
+       if (sconv != NULL) {
                if (archive_strcpy_in_locale(&(zip->l_name),
-                   archive_entry_pathname(entry), zip->opt_sconv) != 0) {
+                   archive_entry_pathname(entry), sconv) != 0) {
                        archive_set_error(&a->archive,
                            ARCHIVE_ERRNO_FILE_FORMAT,
                            "Can't translate pathname '%s' to %s",
                            archive_entry_pathname(entry),
-                           archive_string_conversion_charset_name(zip->opt_sconv));
+                           archive_string_conversion_charset_name(sconv));
                        ret2 = ARCHIVE_WARN;
                }
                archive_entry_set_pathname(l->entry, zip->l_name.s);