From: Michihiro NAKAJIMA Date: Thu, 7 Apr 2011 09:52:51 +0000 (-0400) Subject: Introduce X-Git-Tag: v3.0.0a~514 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3d4808d1d80daa705ea50ccf53a839e493e372e4;p=thirdparty%2Flibarchive.git Introduce 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 --- diff --git a/libarchive/archive_read_support_format_tar.c b/libarchive/archive_read_support_format_tar.c index 7ad5358ad..16db25632 100644 --- a/libarchive/archive_read_support_format_tar.c +++ b/libarchive/archive_read_support_format_tar.c @@ -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); diff --git a/libarchive/archive_read_support_format_zip.c b/libarchive/archive_read_support_format_zip.c index eae96cfe8..7f26eec8c 100644 --- a/libarchive/archive_read_support_format_zip.c +++ b/libarchive/archive_read_support_format_zip.c @@ -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); diff --git a/libarchive/archive_string.c b/libarchive/archive_string.c index 674c4011b..701f89c84 100644 --- a/libarchive/archive_string.c +++ b/libarchive/archive_string.c @@ -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. */ diff --git a/libarchive/archive_string.h b/libarchive/archive_string.h index 816e1edad..65c04e7f3 100644 --- a/libarchive/archive_string.h +++ b/libarchive/archive_string.h @@ -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 * diff --git a/libarchive/archive_write_set_format_gnutar.c b/libarchive/archive_write_set_format_gnutar.c index 140cd7f9e..4a091f2c6 100644 --- a/libarchive/archive_write_set_format_gnutar.c +++ b/libarchive/archive_write_set_format_gnutar.c @@ -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 diff --git a/libarchive/archive_write_set_format_ustar.c b/libarchive/archive_write_set_format_ustar.c index 1957530ef..ca0a15014 100644 --- a/libarchive/archive_write_set_format_ustar.c +++ b/libarchive/archive_write_set_format_ustar.c @@ -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); diff --git a/libarchive/archive_write_set_format_zip.c b/libarchive/archive_write_set_format_zip.c index a12d52a42..5f71a9ce0 100644 --- a/libarchive/archive_write_set_format_zip.c +++ b/libarchive/archive_write_set_format_zip.c @@ -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);