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;
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 *
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);
}
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);
}
/* 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. */
* 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;
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);
}
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
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)
{
}
}
+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)
{
}
}
+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)
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,
* 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;
* 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;
/* 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__)
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)
/* 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
__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.
/* 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 *,
__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