]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Implement a string conversion interface to archive_entry and archive_mstring
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Mon, 9 May 2011 12:07:31 +0000 (08:07 -0400)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Mon, 9 May 2011 12:07:31 +0000 (08:07 -0400)
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

Makefile.am
libarchive/CMakeLists.txt
libarchive/archive_entry.c
libarchive/archive_entry_locale.h [new file with mode: 0644]
libarchive/archive_string.c
libarchive/archive_string.h

index c6ffd746359ee448199aa93766b3c66d8cb782bc..0d5af8992ff5be25bdbe6ebf3747098c06388a8c 100644 (file)
@@ -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                         \
index 80a55dcb8eae3409615b6a63e6b4f2788866fc82..a68212915f3128ba25dc2a9f836e022ef6f1a9f5 100644 (file)
@@ -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
index 417e47f4d0a118b6ed0975e242949629f945343d..b94bf6765c04854edfaf395ef88316e2d04d884e 100644 (file)
@@ -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 (file)
index 0000000..7c40d23
--- /dev/null
@@ -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 */
index 0e2ad249bb6aa03c2658b87795491869ef6da7bf..4fe0b004b6dbf43620553f25bf66af53f0ea7d04 100644 (file)
@@ -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
index 65c2bd1edb80fddf5ea52323ff30b7719e784649..b35920cf5ed2057f106976397b43d1c5061cccaf 100644 (file)
@@ -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);