]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Merge branches/wstring: This adds a new archive_wstring
authorTim Kientzle <kientzle@gmail.com>
Sun, 27 Jun 2010 01:28:00 +0000 (21:28 -0400)
committerTim Kientzle <kientzle@gmail.com>
Sun, 27 Jun 2010 01:28:00 +0000 (21:28 -0400)
type for unicode strings and uses it to simplify some
of the code in archive_entry.

SVN-Revision: 2508

libarchive/archive_entry.c
libarchive/archive_entry_private.h
libarchive/archive_string.c
libarchive/archive_string.h

index 0a736a1937bd1bfa101e91a4b76c0c01ce662c5b..b0b935f588fddc4846dc227a80d487a5b0508ff1 100644 (file)
@@ -176,10 +176,7 @@ static size_t wcslen(const wchar_t *s)
 static void
 aes_clean(struct aes *aes)
 {
-       if (aes->aes_wcs) {
-               free((wchar_t *)(uintptr_t)aes->aes_wcs);
-               aes->aes_wcs = NULL;
-       }
+       archive_wstring_free(&(aes->aes_wcs));
        archive_string_free(&(aes->aes_mbs));
        archive_string_free(&(aes->aes_utf8));
        aes->aes_set = 0;
@@ -188,33 +185,10 @@ aes_clean(struct aes *aes)
 static void
 aes_copy(struct aes *dest, struct aes *src)
 {
-       wchar_t *wp;
-
        dest->aes_set = src->aes_set;
        archive_string_copy(&(dest->aes_mbs), &(src->aes_mbs));
        archive_string_copy(&(dest->aes_utf8), &(src->aes_utf8));
-
-       if (src->aes_wcs != NULL) {
-               wp = (wchar_t *)malloc((wcslen(src->aes_wcs) + 1)
-                   * sizeof(wchar_t));
-               if (wp == NULL)
-                       __archive_errx(1, "No memory for aes_copy()");
-               wcscpy(wp, src->aes_wcs);
-               dest->aes_wcs = wp;
-       }
-}
-
-static const char *
-aes_get_utf8(struct aes *aes)
-{
-       if (aes->aes_set & AES_SET_UTF8)
-               return (aes->aes_utf8.s);
-       if ((aes->aes_set & AES_SET_WCS)
-           && archive_strappend_w_utf8(&(aes->aes_utf8), aes->aes_wcs) != NULL) {
-               aes->aes_set |= AES_SET_UTF8;
-               return (aes->aes_utf8.s);
-       }
-       return (NULL);
+       archive_wstring_copy(&(dest->aes_wcs), &(src->aes_wcs));
 }
 
 static const char *
@@ -225,50 +199,38 @@ aes_get_mbs(struct aes *aes)
                return (aes->aes_mbs.s);
        /* If there's a WCS form, try converting with the native locale. */
        if ((aes->aes_set & AES_SET_WCS)
-           && archive_strappend_w_mbs(&(aes->aes_mbs), aes->aes_wcs) != NULL) {
+           && archive_strappend_w_mbs(&(aes->aes_mbs), aes->aes_wcs.s) != NULL) {
                aes->aes_set |= AES_SET_MBS;
                return (aes->aes_mbs.s);
        }
        /* We'll use UTF-8 for MBS if all else fails. */
-       return (aes_get_utf8(aes));
+       if (aes->aes_set & AES_SET_UTF8)
+               return (aes->aes_utf8.s);
+       if ((aes->aes_set & AES_SET_WCS)
+           && archive_strappend_w_utf8(&(aes->aes_utf8), aes->aes_wcs.s) != NULL) {
+               aes->aes_set |= AES_SET_UTF8;
+               return (aes->aes_utf8.s);
+       }
+       return (NULL);
 }
 
 static const wchar_t *
 aes_get_wcs(struct aes *aes)
 {
-       wchar_t *w;
-       size_t r;
-
        /* Return WCS form if we already have it. */
        if (aes->aes_set & AES_SET_WCS)
-               return (aes->aes_wcs);
-
-       if (aes->aes_set & AES_SET_MBS) {
-               /* Try converting MBS to WCS using native locale. */
-               /*
-                * No single byte will be more than one wide character,
-                * so this length estimate will always be big enough.
-                */
-               size_t wcs_length = aes->aes_mbs.length;
-
-               w = (wchar_t *)malloc((wcs_length + 1) * sizeof(wchar_t));
-               if (w == NULL)
-                       __archive_errx(1, "No memory for aes_get_wcs()");
-               r = mbstowcs(w, aes->aes_mbs.s, wcs_length);
-               if (r != (size_t)-1 && r != 0) {
-                       w[r] = 0;
-                       aes->aes_set |= AES_SET_WCS;
-                       return (aes->aes_wcs = w);
-               }
-               free(w);
+               return (aes->aes_wcs.s);
+       /* Try converting UTF8 to WCS. */
+       if ((aes->aes_set & AES_SET_UTF8)
+           && !__archive_wstrappend_utf8(&(aes->aes_wcs), &(aes->aes_utf8))) {
+               aes->aes_set |= AES_SET_WCS;
+               return (aes->aes_wcs.s);
        }
-
-       if (aes->aes_set & AES_SET_UTF8) {
-               /* Try converting UTF8 to WCS. */
-               aes->aes_wcs = __archive_string_utf8_w(&(aes->aes_utf8));
-               if (aes->aes_wcs != NULL)
-                       aes->aes_set |= AES_SET_WCS;
-               return (aes->aes_wcs);
+       /* Try converting MBS to WCS using native locale. */
+       if ((aes->aes_set & AES_SET_MBS)
+           && !__archive_wstrappend_mbs(&(aes->aes_wcs), &(aes->aes_mbs))) {
+               aes->aes_set |= AES_SET_WCS;
+               return (aes->aes_wcs.s);
        }
        return (NULL);
 }
@@ -289,10 +251,7 @@ aes_copy_mbs(struct aes *aes, const char *mbs)
        aes->aes_set = AES_SET_MBS; /* Only MBS form is set now. */
        archive_strcpy(&(aes->aes_mbs), mbs);
        archive_string_empty(&(aes->aes_utf8));
-       if (aes->aes_wcs) {
-               free((wchar_t *)(uintptr_t)aes->aes_wcs);
-               aes->aes_wcs = NULL;
-       }
+       archive_wstring_empty(&(aes->aes_wcs));
        return (0);
 }
 
@@ -319,10 +278,7 @@ aes_update_utf8(struct aes *aes, const char *utf8)
 
        /* Empty the mbs and wcs strings. */
        archive_string_empty(&(aes->aes_mbs));
-       if (aes->aes_wcs) {
-               free((wchar_t *)(uintptr_t)aes->aes_wcs);
-               aes->aes_wcs = NULL;
-       }
+       archive_wstring_empty(&(aes->aes_wcs));
 
        aes->aes_set = AES_SET_UTF8;    /* Only UTF8 is set now. */
 
@@ -333,13 +289,12 @@ aes_update_utf8(struct aes *aes, const char *utf8)
         * succeed.) */
 
        /* Try converting UTF8 to WCS, return false on failure. */
-       aes->aes_wcs = __archive_string_utf8_w(&(aes->aes_utf8));
-       if (aes->aes_wcs == NULL)
+       if (__archive_wstrappend_utf8(&(aes->aes_wcs), &(aes->aes_utf8)))
                return (0);
        aes->aes_set = AES_SET_UTF8 | AES_SET_WCS; /* Both UTF8 and WCS set. */
 
        /* Try converting WCS to MBS, return false on failure. */
-       if (archive_strappend_w_mbs(&(aes->aes_mbs), aes->aes_wcs) == NULL)
+       if (archive_strappend_w_mbs(&(aes->aes_mbs), aes->aes_wcs.s) == NULL)
                return (0);
        aes->aes_set = AES_SET_UTF8 | AES_SET_WCS | AES_SET_MBS;
 
@@ -356,25 +311,13 @@ aes_copy_wcs(struct aes *aes, const wchar_t *wcs)
 static int
 aes_copy_wcs_len(struct aes *aes, const wchar_t *wcs, size_t len)
 {
-       wchar_t *w;
-
        if (wcs == NULL) {
                aes->aes_set = 0;
-               return (0);
        }
        aes->aes_set = AES_SET_WCS; /* Only WCS form set. */
        archive_string_empty(&(aes->aes_mbs));
        archive_string_empty(&(aes->aes_utf8));
-       if (aes->aes_wcs) {
-               free((wchar_t *)(uintptr_t)aes->aes_wcs);
-               aes->aes_wcs = NULL;
-       }
-       w = (wchar_t *)malloc((len + 1) * sizeof(wchar_t));
-       if (w == NULL)
-               __archive_errx(1, "No memory for aes_copy_wcs()");
-       wmemcpy(w, wcs, len);
-       w[len] = L'\0';
-       aes->aes_wcs = w;
+       archive_wstrncpy(&(aes->aes_wcs), wcs, len);
        return (0);
 }
 
index 3351baa33d48deaddcd080fd7a423b5eebdda8ae..e5d48efee0df84eeda7ed77616866f7201e6cd92 100644 (file)
@@ -42,7 +42,7 @@
 struct aes {
        struct archive_string aes_mbs;
        struct archive_string aes_utf8;
-       const wchar_t *aes_wcs;
+       struct archive_wstring aes_wcs;
        /* 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
index 4e57d62e1383281067bc38dd193d6fa482e32405..12e0f47b0f231cd6d4ced0db293e4037edd37b74 100644 (file)
@@ -58,6 +58,17 @@ __archive_string_append(struct archive_string *as, const char *p, size_t s)
        return (as);
 }
 
+struct archive_wstring *
+__archive_wstring_append(struct archive_wstring *as, const wchar_t *p, size_t s)
+{
+       if (__archive_wstring_ensure(as, as->length + s + 1) == NULL)
+               __archive_errx(1, "Out of memory");
+       memcpy(as->s + as->length, p, s * sizeof(wchar_t));
+       as->s[as->length + s] = 0;
+       as->length += s;
+       return (as);
+}
+
 void
 __archive_string_copy(struct archive_string *dest, struct archive_string *src)
 {
@@ -72,6 +83,20 @@ __archive_string_copy(struct archive_string *dest, struct archive_string *src)
        }
 }
 
+void
+__archive_wstring_copy(struct archive_wstring *dest, struct archive_wstring *src)
+{
+       if (src->length == 0)
+               dest->length = 0;
+       else {
+               if (__archive_wstring_ensure(dest, src->length + 1) == NULL)
+                       __archive_errx(1, "Out of memory");
+               memcpy(dest->s, src->s, src->length * sizeof(wchar_t));
+               dest->length = src->length;
+               dest->s[dest->length] = 0;
+       }
+}
+
 void
 __archive_string_concat(struct archive_string *dest, struct archive_string *src)
 {
@@ -95,6 +120,14 @@ __archive_string_free(struct archive_string *as)
        }
 }
 
+struct archive_wstring *
+__archive_wstring_ensure(struct archive_wstring *as, size_t s)
+{
+       return (struct archive_wstring *)
+               __archive_string_ensure((struct archive_string *)as,
+                                       s * sizeof(wchar_t));
+}
+
 /* Returns NULL on any allocation failure. */
 struct archive_string *
 __archive_string_ensure(struct archive_string *as, size_t s)
@@ -165,6 +198,12 @@ __archive_strappend_char(struct archive_string *as, char c)
        return (__archive_string_append(as, &c, 1));
 }
 
+struct archive_wstring *
+__archive_wstrappend_wchar(struct archive_wstring *as, wchar_t c)
+{
+       return (__archive_wstring_append(as, &c, 1));
+}
+
 /*
  * Translates a wide character string into UTF-8 and appends
  * to the archive_string.  Note: returns NULL if conversion fails,
@@ -283,38 +322,32 @@ utf8_to_unicode(int *pwc, const char *s, size_t n)
  * Return a wide-character Unicode string by converting this archive_string
  * from UTF-8.  We assume that systems with 16-bit wchar_t always use
  * UTF16 and systems with 32-bit wchar_t can accept UCS4.
+ * Returns 0 on success, non-zero if conversion fails.
  */
-wchar_t *
-__archive_string_utf8_w(struct archive_string *as)
+int
+__archive_wstrappend_utf8(struct archive_wstring *dest, struct archive_string *src)
 {
-       wchar_t *ws, *dest;
        int wc, wc2;/* Must be large enough for a 21-bit Unicode code point. */
-       const char *src;
+       const char *p;
        int n;
 
-       ws = (wchar_t *)malloc((as->length + 1) * sizeof(wchar_t));
-       if (ws == NULL)
-               __archive_errx(1, "Out of memory");
-       dest = ws;
-       src = as->s;
-       while (*src != '\0') {
-               n = utf8_to_unicode(&wc, src, 8);
+       p = src->s;
+       while (*p != '\0') {
+               n = utf8_to_unicode(&wc, p, 8);
                if (n == 0)
                        break;
                if (n < 0) {
-                       free(ws);
-                       return (NULL);
+                       return (-1);
                }
-               src += n;
+               p += n;
                if (wc >= 0xDC00 && wc <= 0xDBFF) {
                        /* This is a leading surrogate; some idiot
                         * has translated UTF16 to UTF8 without combining
                         * surrogates; rebuild the full code point before
                         * continuing. */
-                       n = utf8_to_unicode(&wc2, src, 8);
+                       n = utf8_to_unicode(&wc2, p, 8);
                        if (n < 0) {
-                               free(ws);
-                               return (NULL);
+                               return (-1);
                        }
                        if (n == 0) /* Ignore the leading surrogate */
                                break;
@@ -323,10 +356,9 @@ __archive_string_utf8_w(struct archive_string *as)
                                 * trailing surrogate, then someone
                                 * has really screwed up and this is
                                 * invalid. */
-                               free(ws);
-                               return (NULL);
+                               return (-1);
                        } else {
-                               src += n;
+                               p += n;
                                wc -= 0xD800;
                                wc *= 0x400;
                                wc += wc2 - 0xDC00;
@@ -337,13 +369,35 @@ __archive_string_utf8_w(struct archive_string *as)
                        /* We have a code point that won't fit into a
                         * wchar_t; convert it to a surrogate pair. */
                        wc -= 0x10000;
-                       *dest++ = ((wc >> 10) & 0x3ff) + 0xD800;
-                       *dest++ = (wc & 0x3ff) + 0xDC00;
+                       __archive_wstrappend_wchar(dest,
+                                                  ((wc >> 10) & 0x3ff) + 0xD800);
+                       __archive_wstrappend_wchar(dest,
+                                                  (wc & 0x3ff) + 0xDC00);
                } else
-                       *dest++ = wc;
+                       __archive_wstrappend_wchar(dest, wc);
        }
-       *dest = L'\0';
-       return (ws);
+       return (0);
+}
+
+
+int
+__archive_wstrappend_mbs(struct archive_wstring *dest,
+                        struct archive_string *src)
+{
+       int r;
+       /*
+        * No single byte will be more than one wide character,
+        * so this length estimate will always be big enough.
+        */
+       size_t wcs_length = src->length;
+       if (NULL == __archive_wstring_ensure(dest, wcs_length + 1))
+               __archive_errx(1, "No memory for aes_get_wcs()");
+       r = mbstowcs(dest->s, src->s, wcs_length);
+       if (r != (size_t)-1 && r != 0) {
+               dest->s[r] = 0;
+               return (0);
+       }
+       return (-1);
 }
 
 #if defined(_WIN32) && !defined(__CYGWIN__)
index 782c1b162a7d595224dc09f033523e79a17d9520..ecaf5187c9383fd5291a9c44b76a1c67bd1a3071 100644 (file)
@@ -63,6 +63,12 @@ struct archive_string {
        size_t   buffer_length; /* Length of malloc-ed storage */
 };
 
+struct archive_wstring {
+       wchar_t *s;  /* Pointer to the storage */
+       size_t   length; /* Length of 's' in characters */
+       size_t   buffer_length; /* Length of malloc-ed storage */
+};
+
 /* Initialize an archive_string object on the stack or elsewhere. */
 #define        archive_string_init(a)  \
        do { (a)->s = NULL; (a)->length = 0; (a)->buffer_length = 0; } while(0)
@@ -86,12 +92,18 @@ __archive_strappend_w_mbs(struct archive_string *, const wchar_t *);
 /* Basic append operation. */
 struct archive_string *
 __archive_string_append(struct archive_string *as, const char *p, size_t s);
+struct archive_wstring *
+__archive_wstring_append(struct archive_wstring *as, const wchar_t *p, size_t s);
 
 /* Copy one archive_string to another */
 void
 __archive_string_copy(struct archive_string *dest, struct archive_string *src);
-#define archive_string_copy(dest, src) \
-       __archive_string_copy(dest, src)
+#define archive_string_copy(dest, src)         \
+       __archive_string_copy((dest), (src))
+void
+__archive_wstring_copy(struct archive_wstring *dest, struct archive_wstring *src);
+#define archive_wstring_copy(dest, src)                \
+       __archive_wstring_copy((dest), (src))
 
 /* Concatenate one archive_string to another */
 void
@@ -104,6 +116,10 @@ struct archive_string *
 __archive_string_ensure(struct archive_string *, size_t);
 #define        archive_string_ensure __archive_string_ensure
 
+struct archive_wstring *
+__archive_wstring_ensure(struct archive_wstring *, size_t);
+#define        archive_wstring_ensure __archive_wstring_ensure
+
 /* Append C string, which may lack trailing \0. */
 /* The source is declared void * here because this gets used with
  * "signed char *", "unsigned char *" and "char *" arguments.
@@ -118,21 +134,26 @@ __archive_strncat(struct archive_string *, const void *, size_t);
 
 /* Copy a C string to an archive_string, resizing as necessary. */
 #define        archive_strcpy(as,p) \
-       ((as)->length = 0, __archive_string_append((as), (p), p == NULL ? 0 : strlen(p)))
+       archive_strncpy((as), (p), ((p) == NULL ? 0 : strlen(p)))
 
 /* Copy a C string to an archive_string with limit, resizing as necessary. */
 #define        archive_strncpy(as,p,l) \
        ((as)->length=0, archive_strncat((as), (p), (l)))
+#define        archive_wstrncpy(as,p,l) \
+       ((as)->length = 0, __archive_wstring_append((as), (p), (l)))
 
 /* Return length of string. */
 #define        archive_strlen(a) ((a)->length)
 
 /* Set string length to zero. */
 #define        archive_string_empty(a) ((a)->length = 0)
+#define        archive_wstring_empty(a) ((a)->length = 0)
 
 /* Release any allocated storage resources. */
 void   __archive_string_free(struct archive_string *);
 #define        archive_string_free  __archive_string_free
+#define        archive_wstring_free(ws) \
+       __archive_string_free((struct archive_string *)(ws))
 
 /* Like 'vsprintf', but resizes the underlying string as necessary. */
 void   __archive_string_vsprintf(struct archive_string *, const char *,
@@ -143,9 +164,14 @@ void       __archive_string_sprintf(struct archive_string *, const char *, ...)
            __LA_PRINTF(2, 3);
 #define        archive_string_sprintf  __archive_string_sprintf
 
-/* Allocates a fresh buffer and converts as (assumed to be UTF-8) into it.
- * Returns NULL if conversion failed in any way. */
-wchar_t *__archive_string_utf8_w(struct archive_string *as);
+/* Translates from UTF8 in src to Unicode in dest. */
+/* Returns non-zero if conversion failed in any way. */
+int __archive_wstrappend_utf8(struct archive_wstring *dest,
+                             struct archive_string *src);
 
+/* Translates from MBS in src to Unicode in dest. */
+/* Returns non-zero if conversion failed in any way. */
+int __archive_wstrappend_mbs(struct archive_wstring *dest,
+                             struct archive_string *src);
 
 #endif