]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Use native conversion functions on Windows which
authorTim Kientzle <kientzle@gmail.com>
Mon, 29 Dec 2008 00:45:58 +0000 (19:45 -0500)
committerTim Kientzle <kientzle@gmail.com>
Mon, 29 Dec 2008 00:45:58 +0000 (19:45 -0500)
handle UTF-16 encoding correctly.

I have two concerns about the current code:
 * Windows isn't unique in using UTF-16.  Its just a
   couple lines of code to combine surrogate pairs
   prior to converting to UTF-8.  Its another couple
   of lines to expand surrogate pairs when converting
   from UTF-8 (but only if sizeof(wchar_t) == 2).
 * mbtowc() isn't thread-safe.  Although there are
   parts of libarchive that aren't thread safe---in
   particular, archive_write_disk has some umask()
   and chdir() calls that are hard to avoid---most
   of libarchive can be made thread safe with a little
   care.  I originally switched this code to mbtowc()
   style for reasons of portability and error handling,
   so some care is needed.

Submitted by: Michihiro NAKAJIMA

SVN-Revision: 303

libarchive/archive_string.c

index 230cdc6365836604eb0ff2571257170634aa8738..57df4e874c9d2c0eccdade2f0a146b894c2b4f79 100644 (file)
@@ -40,6 +40,9 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_string.c,v 1.17 2008/12/06 05:56:
 #ifdef HAVE_WCHAR_H
 #include <wchar.h>
 #endif
+#ifdef _WIN32
+#include <windows.h>
+#endif
 
 #include "archive_private.h"
 #include "archive_string.h"
@@ -175,6 +178,7 @@ __archive_strappend_int(struct archive_string *as, int d, int base)
        return (as);
 }
 
+#ifndef _WIN32
 /*
  * Home-grown wctomb for UTF-8.
  */
@@ -375,3 +379,83 @@ __archive_string_utf8_w(struct archive_string *as)
        *dest++ = L'\0';
        return (ws);
 }
+
+#else
+
+static struct archive_string *
+my_archive_strappend_w(struct archive_string *as,
+    unsigned int codepage, const wchar_t *w)
+{
+       char *p;
+       int l, wl;
+       BOOL useDefaultChar = FALSE;
+
+       wl = (int)wcslen(w);
+       l = wl * 4 + 4;
+       p = malloc(l);
+       if (p == NULL)
+               __archive_errx(1, "Out of memory");
+       /* To check a useDefaultChar is to simulate error handling of
+        * the my_wcstombs() which is running on non Windows system with
+        * wctomb().
+        * And to set NULL for last argument is necessary when a codepage
+        * is not CP_ACP(current locale).
+        */
+       l = WideCharToMultiByte(codepage, 0, w, wl, p, l, NULL,
+               (codepage == CP_ACP) ? &useDefaultChar : NULL);
+       if (l == 0 || useDefaultChar) {
+               free(p);
+               return (NULL);
+       }
+       __archive_string_append(as, p, l);
+       free(p);
+       return (as);
+}
+
+/*
+ * Translates a wide character string into UTF-8 and appends
+ * to the archive_string.  Note: returns NULL if conversion fails.
+ */
+struct archive_string *
+__archive_strappend_w_utf8(struct archive_string *as, const wchar_t *w)
+{
+
+       return (my_archive_strappend_w(as, CP_UTF8, w));
+}
+
+/*
+ * Translates a wide character string into current locale character set
+ * and appends to the archive_string.  Note: returns NULL if conversion
+ * fails.
+ */
+struct archive_string *
+__archive_strappend_w_mbs(struct archive_string *as, const wchar_t *w)
+{
+
+       return (my_archive_strappend_w(as, CP_ACP, w));
+}
+
+/*
+ * Return a wide-character string by converting this archive_string
+ * from UTF-8.
+ */
+wchar_t *
+__archive_string_utf8_w(struct archive_string *as)
+{
+       wchar_t *ws;
+       int n;
+
+       ws = (wchar_t *)malloc((as->length + 1) * sizeof(wchar_t));
+       if (ws == NULL)
+               __archive_errx(1, "Out of memory");
+       n = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
+               as->s, (int)as->length, ws, (int)as->length);
+       if (n == 0) {
+               free(ws);
+               return (NULL);
+       }
+       ws[n] = L'\0';
+       return (ws);
+}
+
+#endif /* !_WIN32 */