From: Michihiro NAKAJIMA Date: Mon, 9 May 2011 12:07:31 +0000 (-0400) Subject: Implement a string conversion interface to archive_entry and archive_mstring X-Git-Tag: v3.0.0a~398 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ae5439410438b4cf225de3f52bba24746ef613a2;p=thirdparty%2Flibarchive.git Implement a string conversion interface to archive_entry and archive_mstring for efficient string conversion. Some platform have to do a string conversion through wide characters. And then Windows platform cannot make locale UTF-8, so it means use of wide characters is only way to make a internationalization program. SVN-Revision: 3288 --- diff --git a/Makefile.am b/Makefile.am index c6ffd7463..0d5af8992 100644 --- a/Makefile.am +++ b/Makefile.am @@ -94,6 +94,7 @@ libarchive_la_SOURCES= \ libarchive/archive_entry.h \ libarchive/archive_entry_copy_stat.c \ libarchive/archive_entry_link_resolver.c \ + libarchive/archive_entry_locale.h \ libarchive/archive_entry_private.h \ libarchive/archive_entry_sparse.c \ libarchive/archive_entry_stat.c \ diff --git a/libarchive/CMakeLists.txt b/libarchive/CMakeLists.txt index 80a55dcb8..a68212915 100644 --- a/libarchive/CMakeLists.txt +++ b/libarchive/CMakeLists.txt @@ -20,6 +20,7 @@ SET(libarchive_SOURCES archive_entry.h archive_entry_copy_stat.c archive_entry_link_resolver.c + archive_entry_locale.h archive_entry_private.h archive_entry_sparse.c archive_entry_stat.c diff --git a/libarchive/archive_entry.c b/libarchive/archive_entry.c index 417e47f4d..b94bf6765 100644 --- a/libarchive/archive_entry.c +++ b/libarchive/archive_entry.c @@ -70,6 +70,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_entry.c 201096 2009-12-28 02:41: #include "archive.h" #include "archive_acl_private.h" #include "archive_entry.h" +#include "archive_entry_locale.h" #include "archive_private.h" #include "archive_entry_private.h" @@ -410,6 +411,13 @@ archive_entry_gname_w(struct archive_entry *entry) return (NULL); } +int +_archive_entry_gname_l(struct archive_entry *entry, + const char **p, size_t *len, struct archive_string_conv *sc) +{ + return (archive_mstring_get_mbs_l(&entry->ae_gname, p, len, sc)); +} + const char * archive_entry_hardlink(struct archive_entry *entry) { @@ -430,6 +438,18 @@ archive_entry_hardlink_w(struct archive_entry *entry) return (NULL); } +int +_archive_entry_hardlink_l(struct archive_entry *entry, + const char **p, size_t *len, struct archive_string_conv *sc) +{ + if ((entry->ae_set & AE_SET_HARDLINK) == 0) { + *p = NULL; + *len = 0; + return (0); + } + return (archive_mstring_get_mbs_l(&entry->ae_hardlink, p, len, sc)); +} + int64_t archive_entry_ino(struct archive_entry *entry) { @@ -492,6 +512,13 @@ archive_entry_pathname_w(struct archive_entry *entry) return (NULL); } +int +_archive_entry_pathname_l(struct archive_entry *entry, + const char **p, size_t *len, struct archive_string_conv *sc) +{ + return (archive_mstring_get_mbs_l(&entry->ae_pathname, p, len, sc)); +} + mode_t archive_entry_perm(struct archive_entry *entry) { @@ -578,6 +605,18 @@ archive_entry_symlink_w(struct archive_entry *entry) return (NULL); } +int +_archive_entry_symlink_l(struct archive_entry *entry, + const char **p, size_t *len, struct archive_string_conv *sc) +{ + if ((entry->ae_set & AE_SET_SYMLINK) == 0) { + *p = NULL; + *len = 0; + return (0); + } + return (archive_mstring_get_mbs_l( &entry->ae_symlink, p, len, sc)); +} + int64_t archive_entry_uid(struct archive_entry *entry) { @@ -602,6 +641,13 @@ archive_entry_uname_w(struct archive_entry *entry) return (NULL); } +int +_archive_entry_uname_l(struct archive_entry *entry, + const char **p, size_t *len, struct archive_string_conv *sc) +{ + return (archive_mstring_get_mbs_l(&entry->ae_uname, p, len, sc)); +} + /* * Functions to set archive_entry properties. */ @@ -675,6 +721,13 @@ archive_entry_update_gname_utf8(struct archive_entry *entry, const char *name) return (0); } +int +_archive_entry_copy_gname_l(struct archive_entry *entry, + const char *name, size_t len, struct archive_string_conv *sc) +{ + return (archive_mstring_copy_mbs_len_l(&entry->ae_gname, name, len, sc)); +} + void archive_entry_set_ino(struct archive_entry *entry, int64_t ino) { @@ -732,6 +785,21 @@ archive_entry_update_hardlink_utf8(struct archive_entry *entry, const char *targ return (0); } +int +_archive_entry_copy_hardlink_l(struct archive_entry *entry, + const char *target, size_t len, struct archive_string_conv *sc) +{ + int r; + + r = archive_mstring_copy_mbs_len_l(&entry->ae_hardlink, + target, len, sc); + if (target != NULL && r == 0) + entry->ae_set |= AE_SET_HARDLINK; + else + entry->ae_set &= ~AE_SET_HARDLINK; + return (r); +} + void archive_entry_set_atime(struct archive_entry *entry, time_t t, long ns) { @@ -850,6 +918,21 @@ archive_entry_update_link_utf8(struct archive_entry *entry, const char *target) return ((r == 0)? 1: 0); } +int +_archive_entry_copy_link_l(struct archive_entry *entry, + const char *target, size_t len, struct archive_string_conv *sc) +{ + int r; + + if (entry->ae_set & AE_SET_SYMLINK) + r = archive_mstring_copy_mbs_len_l(&entry->ae_symlink, + target, len, sc); + else + r = archive_mstring_copy_mbs_len_l(&entry->ae_hardlink, + target, len, sc); + return (r); +} + void archive_entry_set_mode(struct archive_entry *entry, mode_t m) { @@ -908,6 +991,14 @@ archive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name return (0); } +int +_archive_entry_copy_pathname_l(struct archive_entry *entry, + const char *name, size_t len, struct archive_string_conv *sc) +{ + return (archive_mstring_copy_mbs_len_l(&entry->ae_pathname, + name, len, sc)); +} + void archive_entry_set_perm(struct archive_entry *entry, mode_t p) { @@ -1010,6 +1101,21 @@ archive_entry_update_symlink_utf8(struct archive_entry *entry, const char *linkn return (0); } +int +_archive_entry_copy_symlink_l(struct archive_entry *entry, + const char *linkname, size_t len, struct archive_string_conv *sc) +{ + int r; + + r = archive_mstring_copy_mbs_len_l(&entry->ae_symlink, + linkname, len, sc); + if (linkname != NULL && r == 0) + entry->ae_set |= AE_SET_SYMLINK; + else + entry->ae_set &= ~AE_SET_SYMLINK; + return (r); +} + void archive_entry_set_uid(struct archive_entry *entry, int64_t u) { @@ -1044,6 +1150,14 @@ archive_entry_update_uname_utf8(struct archive_entry *entry, const char *name) return (0); } +int +_archive_entry_copy_uname_l(struct archive_entry *entry, + const char *name, size_t len, struct archive_string_conv *sc) +{ + return (archive_mstring_copy_mbs_len_l(&entry->ae_uname, + name, len, sc)); +} + const void * archive_entry_mac_metadata(struct archive_entry *entry, size_t *s) { diff --git a/libarchive/archive_entry_locale.h b/libarchive/archive_entry_locale.h new file mode 100644 index 000000000..7c40d236e --- /dev/null +++ b/libarchive/archive_entry_locale.h @@ -0,0 +1,84 @@ +/*- + * Copyright (c) 2011 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef __LIBARCHIVE_BUILD +#error This header is only to be used internally to libarchive. +#endif + +#ifndef ARCHIVE_ENTRY_LOCALE_H_INCLUDED +#define ARCHIVE_ENTRY_LOCALE_H_INCLUDED + +struct archive_entry; +struct archive_string_conv; + +/* + * Utility functions to set and get entry attributes by translating + * character-set. These are designed for use in format readers and writers. + * + * The return code and interface of these are quite different from other + * functions for archive_entry defined in archive_entry.h. + * Common return code are: + * Return 0 if the string conversion succeeded. + * Return -1 if the string conversion failed. + */ + +#define archive_entry_gname_l _archive_entry_gname_l +int _archive_entry_gname_l(struct archive_entry *, + const char **, size_t *, struct archive_string_conv *); +#define archive_entry_hardlink_l _archive_entry_hardlink_l +int _archive_entry_hardlink_l(struct archive_entry *, + const char **, size_t *, struct archive_string_conv *); +#define archive_entry_pathname_l _archive_entry_pathname_l +int _archive_entry_pathname_l(struct archive_entry *, + const char **, size_t *, struct archive_string_conv *); +#define archive_entry_symlink_l _archive_entry_symlink_l +int _archive_entry_symlink_l(struct archive_entry *, + const char **, size_t *, struct archive_string_conv *); +#define archive_entry_uname_l _archive_entry_uname_l +int _archive_entry_uname_l(struct archive_entry *, + const char **, size_t *, struct archive_string_conv *); + +#define archive_entry_copy_gname_l _archive_entry_copy_gname_l +int _archive_entry_copy_gname_l(struct archive_entry *, + const char *, size_t, struct archive_string_conv *); +#define archive_entry_copy_hardlink_l _archive_entry_copy_hardlink_l +int _archive_entry_copy_hardlink_l(struct archive_entry *, + const char *, size_t, struct archive_string_conv *); +#define archive_entry_copy_link_l _archive_entry_copy_link_l +int _archive_entry_copy_link_l(struct archive_entry *, + const char *, size_t, struct archive_string_conv *); +#define archive_entry_copy_pathname_l _archive_entry_copy_pathname_l +int _archive_entry_copy_pathname_l(struct archive_entry *, + const char *, size_t, struct archive_string_conv *); +#define archive_entry_copy_symlink_l _archive_entry_copy_symlink_l +int _archive_entry_copy_symlink_l(struct archive_entry *, + const char *, size_t, struct archive_string_conv *); +#define archive_entry_copy_uname_l _archive_entry_copy_uname_l +int _archive_entry_copy_uname_l(struct archive_entry *, + const char *, size_t, struct archive_string_conv *); + +#endif /* ARCHIVE_ENTRY_LOCALE_H_INCLUDED */ diff --git a/libarchive/archive_string.c b/libarchive/archive_string.c index 0e2ad249b..4fe0b004b 100644 --- a/libarchive/archive_string.c +++ b/libarchive/archive_string.c @@ -575,7 +575,7 @@ archive_string_append_from_wcs_in_codepage(struct archive_string *as, archive_string_ensure(as, as->length + len * 2 + 1); do { defchar_used = 0; - if (to_cp == CP_UTF8) + if (to_cp == CP_UTF8 || sc == NULL) dp = NULL; else dp = &defchar_used; @@ -2926,6 +2926,7 @@ archive_mstring_clean(struct archive_mstring *aes) archive_wstring_free(&(aes->aes_wcs)); archive_string_free(&(aes->aes_mbs)); archive_string_free(&(aes->aes_utf8)); + archive_string_free(&(aes->aes_mbs_in_locale)); aes->aes_set = 0; } @@ -3041,6 +3042,62 @@ archive_mstring_get_wcs(struct archive *a, struct archive_mstring *aes, return (ret); } +int +archive_mstring_get_mbs_l(struct archive_mstring *aes, + const char **p, size_t *length, struct archive_string_conv *sc) +{ + int r, ret = 0; + +#if defined(_WIN32) && !defined(__CYGWIN__) + /* + * Internationalization programing on Windows must use Wide + * characters because Windows platform cannot make locale UTF-8. + */ + if (sc != NULL && (aes->aes_set & AES_SET_WCS) != 0) { + r = archive_string_append_from_wcs_in_codepage( + &(aes->aes_mbs), aes->aes_wcs.s, aes->aes_wcs.length, sc); + if (r == 0) { + *p = aes->aes_mbs_in_locale.s; + if (length != NULL) + *length = aes->aes_mbs_in_locale.length; + return (0); + } else + ret = -1; + } +#endif + + /* If there is not an MBS form but is a WCS form, try converting + * with the native locale to be used for translating it to specified + * character-set. */ + if ((aes->aes_set & AES_SET_MBS) == 0 && + (aes->aes_set & AES_SET_WCS) != 0) { + r = archive_string_append_from_wcs(&(aes->aes_mbs), + aes->aes_wcs.s, aes->aes_wcs.length); + if (r == 0) + aes->aes_set |= AES_SET_MBS; + else + ret = -1; + } + /* If we already have an MBS form, use it to be translated to + * specified character-set. */ + if (aes->aes_set & AES_SET_MBS) { + r = archive_strncpy_in_locale(&(aes->aes_mbs_in_locale), + aes->aes_mbs.s, aes->aes_mbs.length, sc); + if (r == 0) { + *p = aes->aes_mbs_in_locale.s; + if (length != NULL) + *length = aes->aes_mbs_in_locale.length; + return (0); + } else + ret = -1; + } + + *p = NULL; + if (length != NULL) + *length = 0; + return (ret); +} + int archive_mstring_copy_mbs(struct archive_mstring *aes, const char *mbs) { @@ -3086,6 +3143,46 @@ archive_mstring_copy_wcs_len(struct archive_mstring *aes, const wchar_t *wcs, return (0); } +int +archive_mstring_copy_mbs_len_l(struct archive_mstring *aes, + const char *mbs, size_t len, struct archive_string_conv *sc) +{ + int r; + + if (mbs == NULL) { + aes->aes_set = 0; + return (0); + } + archive_string_empty(&(aes->aes_mbs)); + archive_wstring_empty(&(aes->aes_wcs)); + archive_string_empty(&(aes->aes_utf8)); +#if defined(_WIN32) && !defined(__CYGWIN__) + /* + * Internationalization programing on Windows must use Wide + * characters because Windows platform cannot make locale UTF-8. + */ + if (sc == NULL) { + archive_string_append(&(aes->aes_mbs), mbs, len); + aes->aes_set = AES_SET_MBS; + r = 0; + } else { + r = archive_wstring_append_from_mbs_in_codepage( + &(aes->aes_wcs), mbs, len, sc); + if (r == 0) + aes->aes_set = AES_SET_WCS; + else + aes->aes_set = 0; + } +#else + r = archive_strncpy_in_locale(&(aes->aes_mbs), mbs, len, sc); + if (r == 0) + aes->aes_set = AES_SET_MBS; /* Only MBS form is set now. */ + else + aes->aes_set = 0; +#endif + return (r); +} + /* * The 'update' form tries to proactively update all forms of * this string (WCS and MBS) and returns an error if any of diff --git a/libarchive/archive_string.h b/libarchive/archive_string.h index 65c2bd1ed..b35920cf5 100644 --- a/libarchive/archive_string.h +++ b/libarchive/archive_string.h @@ -201,6 +201,7 @@ struct archive_mstring { struct archive_string aes_mbs; struct archive_string aes_utf8; struct archive_wstring aes_wcs; + struct archive_string aes_mbs_in_locale; /* Bitmap of which of the above are valid. Because we're lazy * about malloc-ing and reusing the underlying storage, we * can't rely on NULL pointers to indicate whether a string @@ -216,12 +217,17 @@ void archive_mstring_copy(struct archive_mstring *dest, struct archive_mstring * int archive_mstring_get_mbs(struct archive *, struct archive_mstring *, const char **); int archive_mstring_get_utf8(struct archive *, struct archive_mstring *, const char **); int archive_mstring_get_wcs(struct archive *, struct archive_mstring *, const wchar_t **); +int archive_mstring_get_mbs_l(struct archive_mstring *, const char **, + size_t *, struct archive_string_conv *); int archive_mstring_copy_mbs(struct archive_mstring *, const char *mbs); int archive_mstring_copy_mbs_len(struct archive_mstring *, const char *mbs, size_t); int archive_mstring_copy_utf8(struct archive_mstring *, const char *utf8); int archive_mstring_copy_wcs(struct archive_mstring *, const wchar_t *wcs); -int archive_mstring_copy_wcs_len(struct archive_mstring *, const wchar_t *wcs, size_t); +int archive_mstring_copy_wcs_len(struct archive_mstring *, + const wchar_t *wcs, size_t); +int archive_mstring_copy_mbs_len_l(struct archive_mstring *, + const char *mbs, size_t, struct archive_string_conv *); int archive_mstring_update_utf8(struct archive *, struct archive_mstring *aes, const char *utf8);