From: Tim Kientzle Date: Fri, 19 Nov 2010 06:49:07 +0000 (-0500) Subject: Big string overhaul: X-Git-Tag: v3.0.0a~849 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9fdf89477ed7bd537899b701d082dee12e3c7078;p=thirdparty%2Flibarchive.git Big string overhaul: * Remove __ from names (ISO C reserves names prefixed with __) * Remove the gratuitous macro wrappers * Remove a couple of unused functions * Try to simplify some of the implementations a bit more. * Move the "archive entry string" (aes) functions into archive_string as "archive_multistring" so these can be used outside of archive_entry SVN-Revision: 2791 --- diff --git a/libarchive/archive_entry.c b/libarchive/archive_entry.c index 72b753cf1..6af94d2d3 100644 --- a/libarchive/archive_entry.c +++ b/libarchive/archive_entry.c @@ -113,16 +113,6 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_entry.c 201096 2009-12-28 02:41: if (ns < 0) { --t; ns += 1000000000; } \ } while (0) -static void aes_clean(struct aes *); -static void aes_copy(struct aes *dest, struct aes *src); -static const char * aes_get_mbs(struct aes *); -static const wchar_t * aes_get_wcs(struct aes *); -static int aes_set_mbs(struct aes *, const char *mbs); -static int aes_copy_mbs(struct aes *, const char *mbs); -/* static void aes_set_wcs(struct aes *, const wchar_t *wcs); */ -static int aes_copy_wcs(struct aes *, const wchar_t *wcs); -static int aes_copy_wcs_len(struct aes *, const wchar_t *wcs, size_t); - static char * ae_fflagstostr(unsigned long bitset, unsigned long bitclear); static const wchar_t *ae_wcstofflags(const wchar_t *stringp, unsigned long *setp, unsigned long *clrp); @@ -173,154 +163,6 @@ static size_t wcslen(const wchar_t *s) #define wmemcpy(a,b,i) (wchar_t *)memcpy((a), (b), (i) * sizeof(wchar_t)) #endif -static void -aes_clean(struct aes *aes) -{ - 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) -{ - dest->aes_set = src->aes_set; - archive_string_copy(&(dest->aes_mbs), &(src->aes_mbs)); - archive_string_copy(&(dest->aes_utf8), &(src->aes_utf8)); - archive_wstring_copy(&(dest->aes_wcs), &(src->aes_wcs)); -} - -static const char * -aes_get_mbs(struct aes *aes) -{ - /* If we already have an MBS form, return that immediately. */ - if (aes->aes_set & AES_SET_MBS) - 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.s) != NULL) { - aes->aes_set |= AES_SET_MBS; - return (aes->aes_mbs.s); - } - /* We'll use UTF-8 for MBS if all else fails. */ - 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) -{ - /* Return WCS form if we already have it. */ - if (aes->aes_set & AES_SET_WCS) - 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); - } - /* 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); -} - -static int -aes_set_mbs(struct aes *aes, const char *mbs) -{ - return (aes_copy_mbs(aes, mbs)); -} - -static int -aes_copy_mbs(struct aes *aes, const char *mbs) -{ - if (mbs == NULL) { - aes->aes_set = 0; - return (0); - } - aes->aes_set = AES_SET_MBS; /* Only MBS form is set now. */ - archive_strcpy(&(aes->aes_mbs), mbs); - archive_string_empty(&(aes->aes_utf8)); - archive_wstring_empty(&(aes->aes_wcs)); - return (0); -} - -/* - * The 'update' form tries to proactively update all forms of - * this string (WCS and MBS) and returns an error if any of - * them fail. This is used by the 'pax' handler, for instance, - * to detect and report character-conversion failures early while - * still allowing clients to get potentially useful values from - * the more tolerant lazy conversions. (get_mbs and get_wcs will - * strive to give the user something useful, so you can get hopefully - * usable values even if some of the character conversions are failing.) - */ -static int -aes_update_utf8(struct aes *aes, const char *utf8) -{ - if (utf8 == NULL) { - aes->aes_set = 0; - return (1); /* Succeeded in clearing everything. */ - } - - /* Save the UTF8 string. */ - archive_strcpy(&(aes->aes_utf8), utf8); - - /* Empty the mbs and wcs strings. */ - archive_string_empty(&(aes->aes_mbs)); - archive_wstring_empty(&(aes->aes_wcs)); - - aes->aes_set = AES_SET_UTF8; /* Only UTF8 is set now. */ - - /* TODO: We should just do a direct UTF-8 to MBS conversion - * here. That would be faster, use less space, and give the - * same information. (If a UTF-8 to MBS conversion succeeds, - * then UTF-8->WCS and Unicode->MBS conversions will both - * succeed.) */ - - /* Try converting UTF8 to WCS, return false on failure. */ - 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.s) == NULL) - return (0); - aes->aes_set = AES_SET_UTF8 | AES_SET_WCS | AES_SET_MBS; - - /* All conversions succeeded. */ - return (1); -} - -static int -aes_copy_wcs(struct aes *aes, const wchar_t *wcs) -{ - return aes_copy_wcs_len(aes, wcs, wcs == NULL ? 0 : wcslen(wcs)); -} - -static int -aes_copy_wcs_len(struct aes *aes, const wchar_t *wcs, size_t len) -{ - if (wcs == NULL) { - aes->aes_set = 0; - } - aes->aes_set = AES_SET_WCS; /* Only WCS form set. */ - archive_string_empty(&(aes->aes_mbs)); - archive_string_empty(&(aes->aes_utf8)); - archive_wstrncpy(&(aes->aes_wcs), wcs, len); - return (0); -} - /**************************************************************************** * * Public Interface @@ -332,13 +174,13 @@ archive_entry_clear(struct archive_entry *entry) { if (entry == NULL) return (NULL); - aes_clean(&entry->ae_fflags_text); - aes_clean(&entry->ae_gname); - aes_clean(&entry->ae_hardlink); - aes_clean(&entry->ae_pathname); - aes_clean(&entry->ae_sourcepath); - aes_clean(&entry->ae_symlink); - aes_clean(&entry->ae_uname); + archive_mstring_clean(&entry->ae_fflags_text); + archive_mstring_clean(&entry->ae_gname); + archive_mstring_clean(&entry->ae_hardlink); + archive_mstring_clean(&entry->ae_pathname); + archive_mstring_clean(&entry->ae_sourcepath); + archive_mstring_clean(&entry->ae_symlink); + archive_mstring_clean(&entry->ae_uname); archive_entry_copy_mac_metadata(entry, NULL, 0); archive_entry_acl_clear(entry); archive_entry_xattr_clear(entry); @@ -366,14 +208,14 @@ archive_entry_clone(struct archive_entry *entry) entry2->ae_fflags_set = entry->ae_fflags_set; entry2->ae_fflags_clear = entry->ae_fflags_clear; - aes_copy(&entry2->ae_fflags_text, &entry->ae_fflags_text); - aes_copy(&entry2->ae_gname, &entry->ae_gname); - aes_copy(&entry2->ae_hardlink, &entry->ae_hardlink); - aes_copy(&entry2->ae_pathname, &entry->ae_pathname); - aes_copy(&entry2->ae_sourcepath, &entry->ae_sourcepath); - aes_copy(&entry2->ae_symlink, &entry->ae_symlink); + archive_mstring_copy(&entry2->ae_fflags_text, &entry->ae_fflags_text); + archive_mstring_copy(&entry2->ae_gname, &entry->ae_gname); + archive_mstring_copy(&entry2->ae_hardlink, &entry->ae_hardlink); + archive_mstring_copy(&entry2->ae_pathname, &entry->ae_pathname); + archive_mstring_copy(&entry2->ae_sourcepath, &entry->ae_sourcepath); + archive_mstring_copy(&entry2->ae_symlink, &entry->ae_symlink); entry2->ae_set = entry->ae_set; - aes_copy(&entry2->ae_uname, &entry->ae_uname); + archive_mstring_copy(&entry2->ae_uname, &entry->ae_uname); /* Copy ACL data over. */ ap = entry->acl.acl_head; @@ -381,7 +223,7 @@ archive_entry_clone(struct archive_entry *entry) ap2 = acl_new_entry(entry2, ap->type, ap->permset, ap->tag, ap->id); if (ap2 != NULL) - aes_copy(&ap2->name, &ap->name); + archive_mstring_copy(&ap2->name, &ap->name); ap = ap->next; } @@ -542,7 +384,7 @@ archive_entry_fflags_text(struct archive_entry *entry) const char *f; char *p; - f = aes_get_mbs(&entry->ae_fflags_text); + f = archive_mstring_get_mbs(&entry->ae_fflags_text); if (f != NULL) return (f); @@ -553,9 +395,9 @@ archive_entry_fflags_text(struct archive_entry *entry) if (p == NULL) return (NULL); - aes_copy_mbs(&entry->ae_fflags_text, p); + archive_mstring_copy_mbs(&entry->ae_fflags_text, p); free(p); - f = aes_get_mbs(&entry->ae_fflags_text); + f = archive_mstring_get_mbs(&entry->ae_fflags_text); return (f); } @@ -573,20 +415,20 @@ archive_entry_gid(struct archive_entry *entry) const char * archive_entry_gname(struct archive_entry *entry) { - return (aes_get_mbs(&entry->ae_gname)); + return (archive_mstring_get_mbs(&entry->ae_gname)); } const wchar_t * archive_entry_gname_w(struct archive_entry *entry) { - return (aes_get_wcs(&entry->ae_gname)); + return (archive_mstring_get_wcs(&entry->ae_gname)); } const char * archive_entry_hardlink(struct archive_entry *entry) { if (entry->ae_set & AE_SET_HARDLINK) - return (aes_get_mbs(&entry->ae_hardlink)); + return (archive_mstring_get_mbs(&entry->ae_hardlink)); return (NULL); } @@ -594,7 +436,7 @@ const wchar_t * archive_entry_hardlink_w(struct archive_entry *entry) { if (entry->ae_set & AE_SET_HARDLINK) - return (aes_get_wcs(&entry->ae_hardlink)); + return (archive_mstring_get_wcs(&entry->ae_hardlink)); return (NULL); } @@ -651,13 +493,13 @@ archive_entry_nlink(struct archive_entry *entry) const char * archive_entry_pathname(struct archive_entry *entry) { - return (aes_get_mbs(&entry->ae_pathname)); + return (archive_mstring_get_mbs(&entry->ae_pathname)); } const wchar_t * archive_entry_pathname_w(struct archive_entry *entry) { - return (aes_get_wcs(&entry->ae_pathname)); + return (archive_mstring_get_wcs(&entry->ae_pathname)); } mode_t @@ -709,14 +551,14 @@ archive_entry_size_is_set(struct archive_entry *entry) const char * archive_entry_sourcepath(struct archive_entry *entry) { - return (aes_get_mbs(&entry->ae_sourcepath)); + return (archive_mstring_get_mbs(&entry->ae_sourcepath)); } const char * archive_entry_symlink(struct archive_entry *entry) { if (entry->ae_set & AE_SET_SYMLINK) - return (aes_get_mbs(&entry->ae_symlink)); + return (archive_mstring_get_mbs(&entry->ae_symlink)); return (NULL); } @@ -724,7 +566,7 @@ const wchar_t * archive_entry_symlink_w(struct archive_entry *entry) { if (entry->ae_set & AE_SET_SYMLINK) - return (aes_get_wcs(&entry->ae_symlink)); + return (archive_mstring_get_wcs(&entry->ae_symlink)); return (NULL); } @@ -742,13 +584,13 @@ archive_entry_uid(struct archive_entry *entry) const char * archive_entry_uname(struct archive_entry *entry) { - return (aes_get_mbs(&entry->ae_uname)); + return (archive_mstring_get_mbs(&entry->ae_uname)); } const wchar_t * archive_entry_uname_w(struct archive_entry *entry) { - return (aes_get_wcs(&entry->ae_uname)); + return (archive_mstring_get_wcs(&entry->ae_uname)); } /* @@ -767,7 +609,7 @@ void archive_entry_set_fflags(struct archive_entry *entry, unsigned long set, unsigned long clear) { - aes_clean(&entry->ae_fflags_text); + archive_mstring_clean(&entry->ae_fflags_text); entry->ae_fflags_set = set; entry->ae_fflags_clear = clear; } @@ -776,7 +618,7 @@ const char * archive_entry_copy_fflags_text(struct archive_entry *entry, const char *flags) { - aes_copy_mbs(&entry->ae_fflags_text, flags); + archive_mstring_copy_mbs(&entry->ae_fflags_text, flags); return (ae_strtofflags(flags, &entry->ae_fflags_set, &entry->ae_fflags_clear)); } @@ -785,7 +627,7 @@ const wchar_t * archive_entry_copy_fflags_text_w(struct archive_entry *entry, const wchar_t *flags) { - aes_copy_wcs(&entry->ae_fflags_text, flags); + archive_mstring_copy_wcs(&entry->ae_fflags_text, flags); return (ae_wcstofflags(flags, &entry->ae_fflags_set, &entry->ae_fflags_clear)); } @@ -805,25 +647,25 @@ archive_entry_set_gid(struct archive_entry *entry, int64_t g) void archive_entry_set_gname(struct archive_entry *entry, const char *name) { - aes_set_mbs(&entry->ae_gname, name); + archive_mstring_copy_mbs(&entry->ae_gname, name); } void archive_entry_copy_gname(struct archive_entry *entry, const char *name) { - aes_copy_mbs(&entry->ae_gname, name); + archive_mstring_copy_mbs(&entry->ae_gname, name); } void archive_entry_copy_gname_w(struct archive_entry *entry, const wchar_t *name) { - aes_copy_wcs(&entry->ae_gname, name); + archive_mstring_copy_wcs(&entry->ae_gname, name); } int archive_entry_update_gname_utf8(struct archive_entry *entry, const char *name) { - return (aes_update_utf8(&entry->ae_gname, name)); + return (archive_mstring_update_utf8(&entry->ae_gname, name)); } #if ARCHIVE_VERSION_NUMBER < 3000000 @@ -852,7 +694,7 @@ archive_entry_set_ino64(struct archive_entry *entry, int64_t ino) void archive_entry_set_hardlink(struct archive_entry *entry, const char *target) { - aes_set_mbs(&entry->ae_hardlink, target); + archive_mstring_copy_mbs(&entry->ae_hardlink, target); if (target != NULL) entry->ae_set |= AE_SET_HARDLINK; else @@ -862,7 +704,7 @@ archive_entry_set_hardlink(struct archive_entry *entry, const char *target) void archive_entry_copy_hardlink(struct archive_entry *entry, const char *target) { - aes_copy_mbs(&entry->ae_hardlink, target); + archive_mstring_copy_mbs(&entry->ae_hardlink, target); if (target != NULL) entry->ae_set |= AE_SET_HARDLINK; else @@ -872,7 +714,7 @@ archive_entry_copy_hardlink(struct archive_entry *entry, const char *target) void archive_entry_copy_hardlink_w(struct archive_entry *entry, const wchar_t *target) { - aes_copy_wcs(&entry->ae_hardlink, target); + archive_mstring_copy_wcs(&entry->ae_hardlink, target); if (target != NULL) entry->ae_set |= AE_SET_HARDLINK; else @@ -886,7 +728,7 @@ archive_entry_update_hardlink_utf8(struct archive_entry *entry, const char *targ entry->ae_set |= AE_SET_HARDLINK; else entry->ae_set &= ~AE_SET_HARDLINK; - return (aes_update_utf8(&entry->ae_hardlink, target)); + return (archive_mstring_update_utf8(&entry->ae_hardlink, target)); } void @@ -969,9 +811,9 @@ void archive_entry_set_link(struct archive_entry *entry, const char *target) { if (entry->ae_set & AE_SET_SYMLINK) - aes_set_mbs(&entry->ae_symlink, target); + archive_mstring_copy_mbs(&entry->ae_symlink, target); else - aes_set_mbs(&entry->ae_hardlink, target); + archive_mstring_copy_mbs(&entry->ae_hardlink, target); } /* Set symlink if symlink is already set, else set hardlink. */ @@ -979,9 +821,9 @@ void archive_entry_copy_link(struct archive_entry *entry, const char *target) { if (entry->ae_set & AE_SET_SYMLINK) - aes_copy_mbs(&entry->ae_symlink, target); + archive_mstring_copy_mbs(&entry->ae_symlink, target); else - aes_copy_mbs(&entry->ae_hardlink, target); + archive_mstring_copy_mbs(&entry->ae_hardlink, target); } /* Set symlink if symlink is already set, else set hardlink. */ @@ -989,18 +831,18 @@ void archive_entry_copy_link_w(struct archive_entry *entry, const wchar_t *target) { if (entry->ae_set & AE_SET_SYMLINK) - aes_copy_wcs(&entry->ae_symlink, target); + archive_mstring_copy_wcs(&entry->ae_symlink, target); else - aes_copy_wcs(&entry->ae_hardlink, target); + archive_mstring_copy_wcs(&entry->ae_hardlink, target); } int archive_entry_update_link_utf8(struct archive_entry *entry, const char *target) { if (entry->ae_set & AE_SET_SYMLINK) - return (aes_update_utf8(&entry->ae_symlink, target)); + return (archive_mstring_update_utf8(&entry->ae_symlink, target)); else - return (aes_update_utf8(&entry->ae_hardlink, target)); + return (archive_mstring_update_utf8(&entry->ae_hardlink, target)); } void @@ -1037,25 +879,25 @@ archive_entry_set_nlink(struct archive_entry *entry, unsigned int nlink) void archive_entry_set_pathname(struct archive_entry *entry, const char *name) { - aes_set_mbs(&entry->ae_pathname, name); + archive_mstring_copy_mbs(&entry->ae_pathname, name); } void archive_entry_copy_pathname(struct archive_entry *entry, const char *name) { - aes_copy_mbs(&entry->ae_pathname, name); + archive_mstring_copy_mbs(&entry->ae_pathname, name); } void archive_entry_copy_pathname_w(struct archive_entry *entry, const wchar_t *name) { - aes_copy_wcs(&entry->ae_pathname, name); + archive_mstring_copy_wcs(&entry->ae_pathname, name); } int archive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name) { - return (aes_update_utf8(&entry->ae_pathname, name)); + return (archive_mstring_update_utf8(&entry->ae_pathname, name)); } void @@ -1108,13 +950,13 @@ archive_entry_unset_size(struct archive_entry *entry) void archive_entry_copy_sourcepath(struct archive_entry *entry, const char *path) { - aes_set_mbs(&entry->ae_sourcepath, path); + archive_mstring_copy_mbs(&entry->ae_sourcepath, path); } void archive_entry_set_symlink(struct archive_entry *entry, const char *linkname) { - aes_set_mbs(&entry->ae_symlink, linkname); + archive_mstring_copy_mbs(&entry->ae_symlink, linkname); if (linkname != NULL) entry->ae_set |= AE_SET_SYMLINK; else @@ -1124,7 +966,7 @@ archive_entry_set_symlink(struct archive_entry *entry, const char *linkname) void archive_entry_copy_symlink(struct archive_entry *entry, const char *linkname) { - aes_copy_mbs(&entry->ae_symlink, linkname); + archive_mstring_copy_mbs(&entry->ae_symlink, linkname); if (linkname != NULL) entry->ae_set |= AE_SET_SYMLINK; else @@ -1134,7 +976,7 @@ archive_entry_copy_symlink(struct archive_entry *entry, const char *linkname) void archive_entry_copy_symlink_w(struct archive_entry *entry, const wchar_t *linkname) { - aes_copy_wcs(&entry->ae_symlink, linkname); + archive_mstring_copy_wcs(&entry->ae_symlink, linkname); if (linkname != NULL) entry->ae_set |= AE_SET_SYMLINK; else @@ -1148,7 +990,7 @@ archive_entry_update_symlink_utf8(struct archive_entry *entry, const char *linkn entry->ae_set |= AE_SET_SYMLINK; else entry->ae_set &= ~AE_SET_SYMLINK; - return (aes_update_utf8(&entry->ae_symlink, linkname)); + return (archive_mstring_update_utf8(&entry->ae_symlink, linkname)); } #if ARCHIVE_VERSION_NUMBER < 3000000 @@ -1166,25 +1008,25 @@ archive_entry_set_uid(struct archive_entry *entry, int64_t u) void archive_entry_set_uname(struct archive_entry *entry, const char *name) { - aes_set_mbs(&entry->ae_uname, name); + archive_mstring_copy_mbs(&entry->ae_uname, name); } void archive_entry_copy_uname(struct archive_entry *entry, const char *name) { - aes_copy_mbs(&entry->ae_uname, name); + archive_mstring_copy_mbs(&entry->ae_uname, name); } void archive_entry_copy_uname_w(struct archive_entry *entry, const wchar_t *name) { - aes_copy_wcs(&entry->ae_uname, name); + archive_mstring_copy_wcs(&entry->ae_uname, name); } int archive_entry_update_uname_utf8(struct archive_entry *entry, const char *name) { - return (aes_update_utf8(&entry->ae_uname, name)); + return (archive_mstring_update_utf8(&entry->ae_uname, name)); } const void * @@ -1227,7 +1069,7 @@ archive_entry_acl_clear(struct archive_entry *entry) while (entry->acl.acl_head != NULL) { ap = entry->acl.acl_head->next; - aes_clean(&entry->acl.acl_head->name); + archive_mstring_clean(&entry->acl.acl_head->name); free(entry->acl.acl_head); entry->acl.acl_head = ap; } @@ -1256,9 +1098,9 @@ archive_entry_acl_add_entry(struct archive_entry *entry, return; } if (name != NULL && *name != '\0') - aes_copy_mbs(&ap->name, name); + archive_mstring_copy_mbs(&ap->name, name); else - aes_clean(&ap->name); + archive_mstring_clean(&ap->name); } /* @@ -1285,9 +1127,9 @@ archive_entry_acl_add_entry_w_len(struct archive_entry *entry, return; } if (name != NULL && *name != L'\0' && len > 0) - aes_copy_wcs_len(&ap->name, name, len); + archive_mstring_copy_wcs_len(&ap->name, name, len); else - aes_clean(&ap->name); + archive_mstring_clean(&ap->name); } /* @@ -1478,7 +1320,7 @@ archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type, *permset = entry->acl.acl_p->permset; *tag = entry->acl.acl_p->tag; *id = entry->acl.acl_p->id; - *name = aes_get_mbs(&entry->acl.acl_p->name); + *name = archive_mstring_get_mbs(&entry->acl.acl_p->name); entry->acl.acl_p = entry->acl.acl_p->next; return (ARCHIVE_OK); } @@ -1516,7 +1358,7 @@ archive_entry_acl_text_w(struct archive_entry *entry, int flags) length += 8; /* "default:" */ length += 5; /* tag name */ length += 1; /* colon */ - wname = aes_get_wcs(&ap->name); + wname = archive_mstring_get_wcs(&ap->name); if (wname != NULL) length += wcslen(wname); else @@ -1558,7 +1400,7 @@ archive_entry_acl_text_w(struct archive_entry *entry, int flags) ap = entry->acl.acl_head; while (ap != NULL) { if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { - wname = aes_get_wcs(&ap->name); + wname = archive_mstring_get_wcs(&ap->name); *wp++ = separator; if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) id = ap->id; @@ -1582,7 +1424,7 @@ archive_entry_acl_text_w(struct archive_entry *entry, int flags) count = 0; while (ap != NULL) { if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) { - wname = aes_get_wcs(&ap->name); + wname = archive_mstring_get_wcs(&ap->name); if (count > 0) *wp++ = separator; if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) diff --git a/libarchive/archive_entry_private.h b/libarchive/archive_entry_private.h index 6d22c1df8..785ca5f6c 100644 --- a/libarchive/archive_entry_private.h +++ b/libarchive/archive_entry_private.h @@ -34,32 +34,13 @@ #include "archive_string.h" -/* - * Handle wide character (i.e., Unicode) and non-wide character - * strings transparently. - */ - -struct aes { - struct archive_string aes_mbs; - struct archive_string aes_utf8; - 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 - * has been set. */ - int aes_set; -#define AES_SET_MBS 1 -#define AES_SET_UTF8 2 -#define AES_SET_WCS 4 -}; - struct ae_ace { struct ae_ace *next; int type; /* E.g., access or default */ int tag; /* E.g., user/group/other/mask */ int permset; /* r/w/x bits */ int id; /* uid/gid for user/group */ - struct aes name; /* uname/gname */ + struct archive_mstring name; /* uname/gname */ }; struct ae_acl { @@ -168,17 +149,17 @@ struct archive_entry { /* * Use aes here so that we get transparent mbs<->wcs conversions. */ - struct aes ae_fflags_text; /* Text fflags per fflagstostr(3) */ + struct archive_mstring ae_fflags_text; /* Text fflags per fflagstostr(3) */ unsigned long ae_fflags_set; /* Bitmap fflags */ unsigned long ae_fflags_clear; - struct aes ae_gname; /* Name of owning group */ - struct aes ae_hardlink; /* Name of target for hardlink */ - struct aes ae_pathname; /* Name of entry */ - struct aes ae_symlink; /* symlink contents */ - struct aes ae_uname; /* Name of owner */ + struct archive_mstring ae_gname; /* Name of owning group */ + struct archive_mstring ae_hardlink; /* Name of target for hardlink */ + struct archive_mstring ae_pathname; /* Name of entry */ + struct archive_mstring ae_symlink; /* symlink contents */ + struct archive_mstring ae_uname; /* Name of owner */ /* Not used within libarchive; useful for some clients. */ - struct aes ae_sourcepath; /* Path this entry is sourced from. */ + struct archive_mstring ae_sourcepath; /* Path this entry is sourced from. */ void *mac_metadata; size_t mac_metadata_size; diff --git a/libarchive/archive_string.c b/libarchive/archive_string.c index 2dd6b1b85..3092bde81 100644 --- a/libarchive/archive_string.c +++ b/libarchive/archive_string.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2003-2010 Tim Kientzle * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,6 +29,10 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_string.c 201095 2009-12-28 02:33 /* * Basic resizable string support, to simplify manipulating arbitrary-sized * strings while minimizing heap activity. + * + * In particular, the buffer used by a string object is only grown, it + * never shrinks, so you can clear and reuse the same string object + * without incurring additional memory allocations. */ #ifdef HAVE_STDLIB_H @@ -47,70 +51,42 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_string.c 201095 2009-12-28 02:33 #include "archive_private.h" #include "archive_string.h" -struct archive_string * -__archive_string_append(struct archive_string *as, const char *p, size_t s) +static struct archive_string * +archive_string_append(struct archive_string *as, const char *p, size_t s) { - if (__archive_string_ensure(as, as->length + s + 1) == NULL) + if (archive_string_ensure(as, as->length + s + 1) == NULL) __archive_errx(1, "Out of memory"); memcpy(as->s + as->length, p, s); - as->s[as->length + s] = 0; as->length += s; + as->s[as->length] = 0; return (as); } -struct archive_wstring * -__archive_wstring_append(struct archive_wstring *as, const wchar_t *p, size_t s) +static 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) + 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; + as->s[as->length] = 0; return (as); } void -__archive_string_copy(struct archive_string *dest, struct archive_string *src) +archive_string_concat(struct archive_string *dest, struct archive_string *src) { - if (src->length == 0) - dest->length = 0; - else { - if (__archive_string_ensure(dest, src->length + 1) == NULL) - __archive_errx(1, "Out of memory"); - memcpy(dest->s, src->s, src->length); - dest->length = src->length; - dest->s[dest->length] = 0; - } + archive_string_append(dest, src->s, src->length); } void -__archive_wstring_copy(struct archive_wstring *dest, struct archive_wstring *src) +archive_wstring_concat(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; - } + archive_wstring_append(dest, src->s, src->length); } void -__archive_string_concat(struct archive_string *dest, struct archive_string *src) -{ - if (src->length > 0) { - if (__archive_string_ensure(dest, dest->length + src->length + 1) == NULL) - __archive_errx(1, "Out of memory"); - memcpy(dest->s + dest->length, src->s, src->length); - dest->length += src->length; - dest->s[dest->length] = 0; - } -} - -void -__archive_string_free(struct archive_string *as) +archive_string_free(struct archive_string *as) { as->length = 0; as->buffer_length = 0; @@ -119,7 +95,7 @@ __archive_string_free(struct archive_string *as) } void -__archive_wstring_free(struct archive_wstring *as) +archive_wstring_free(struct archive_wstring *as) { as->length = 0; as->buffer_length = 0; @@ -128,17 +104,20 @@ __archive_wstring_free(struct archive_wstring *as) } struct archive_wstring * -__archive_wstring_ensure(struct archive_wstring *as, size_t s) +archive_wstring_ensure(struct archive_wstring *as, size_t s) { return (struct archive_wstring *) - __archive_string_ensure((struct archive_string *)as, + 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) +archive_string_ensure(struct archive_string *as, size_t s) { + char *p; + size_t new_length; + /* If buffer is already big enough, don't reallocate. */ if (as->s && (s <= as->buffer_length)) return (as); @@ -152,18 +131,17 @@ __archive_string_ensure(struct archive_string *as, size_t s) */ if (as->buffer_length < 32) /* Start with a minimum 32-character buffer. */ - as->buffer_length = 32; + new_length = 32; else if (as->buffer_length < 8192) /* Buffers under 8k are doubled for speed. */ - as->buffer_length += as->buffer_length; + new_length = as->buffer_length + as->buffer_length; else { /* Buffers 8k and over grow by at least 25% each time. */ - size_t old_length = as->buffer_length; - as->buffer_length += as->buffer_length / 4; - /* Be safe: If size wraps, release buffer and return NULL. */ - if (as->buffer_length < old_length) { - free(as->s); - as->s = NULL; + new_length = as->buffer_length + as->buffer_length / 4; + /* Be safe: If size wraps, fail. */ + if (new_length < as->buffer_length) { + /* On failure, wipe the string and return NULL. */ + archive_string_free(as); return (NULL); } } @@ -172,17 +150,30 @@ __archive_string_ensure(struct archive_string *as, size_t s) * grow the buffer. In any case, we have to grow it enough to * hold the request. */ - if (as->buffer_length < s) - as->buffer_length = s; + if (new_length < s) + new_length = s; /* Now we can reallocate the buffer. */ - as->s = (char *)realloc(as->s, as->buffer_length); - if (as->s == NULL) + p = (char *)realloc(as->s, new_length); + if (p == NULL) { + /* On failure, wipe the string and return NULL. */ + archive_string_free(as); return (NULL); + } + + as->s = p; + as->buffer_length = new_length; return (as); } +/* + * TODO: See if there's a way to avoid scanning + * the source string twice. Then test to see + * if it actually helps (remember that we're almost + * always called with pretty short arguments, so + * such an optimization might not help). + */ struct archive_string * -__archive_strncat(struct archive_string *as, const void *_p, size_t n) +archive_strncat(struct archive_string *as, const void *_p, size_t n) { size_t s; const char *p, *pp; @@ -192,41 +183,58 @@ __archive_strncat(struct archive_string *as, const void *_p, size_t n) /* Like strlen(p), except won't examine positions beyond p[n]. */ s = 0; pp = p; - while (*pp && s < n) { + while (s < n && *pp) { pp++; s++; } - return (__archive_string_append(as, p, s)); + return (archive_string_append(as, p, s)); } struct archive_wstring * -__archive_wstrncat(struct archive_wstring *as, const void *_p, size_t n) +archive_wstrncat(struct archive_wstring *as, const wchar_t *p, size_t n) { size_t s; - const wchar_t *p, *pp; - - p = (const wchar_t *)_p; + const wchar_t *pp; /* Like strlen(p), except won't examine positions beyond p[n]. */ s = 0; pp = p; - while (*pp && s < n) { + while (s < n && *pp) { pp++; s++; } - return (__archive_wstring_append(as, p, s)); + return (archive_wstring_append(as, p, s)); +} + +struct archive_string * +archive_strcat(struct archive_string *as, const void *p) +{ + /* strcat is just strncat without an effective limit. + * Assert that we'll never get called with a source + * string over 16MB. + * TODO: Review all uses of strcat in the source + * and try to replace them with strncat(). + */ + return archive_strncat(as, p, 0x1000000); +} + +struct archive_wstring * +archive_wstrcat(struct archive_wstring *as, const wchar_t *p) +{ + /* Ditto. */ + return archive_wstrncat(as, p, 0x1000000); } struct archive_string * -__archive_strappend_char(struct archive_string *as, char c) +archive_strappend_char(struct archive_string *as, char c) { - return (__archive_string_append(as, &c, 1)); + return (archive_string_append(as, &c, 1)); } struct archive_wstring * -__archive_wstrappend_wchar(struct archive_wstring *as, wchar_t c) +archive_wstrappend_wchar(struct archive_wstring *as, wchar_t c) { - return (__archive_wstring_append(as, &c, 1)); + return (archive_wstring_append(as, &c, 1)); } /* @@ -235,7 +243,7 @@ __archive_wstrappend_wchar(struct archive_wstring *as, wchar_t c) * but still leaves a best-effort conversion in the argument as. */ struct archive_string * -__archive_strappend_w_utf8(struct archive_string *as, const wchar_t *w) +archive_strappend_w_utf8(struct archive_string *as, const wchar_t *w) { char *p; unsigned wc; @@ -350,7 +358,7 @@ utf8_to_unicode(int *pwc, const char *s, size_t n) * Returns 0 on success, non-zero if conversion fails. */ int -__archive_wstrappend_utf8(struct archive_wstring *dest, struct archive_string *src) +archive_wstrappend_utf8(struct archive_wstring *dest, struct archive_string *src) { int wc, wc2;/* Must be large enough for a 21-bit Unicode code point. */ const char *p; @@ -394,19 +402,19 @@ __archive_wstrappend_utf8(struct archive_wstring *dest, struct archive_string *s /* We have a code point that won't fit into a * wchar_t; convert it to a surrogate pair. */ wc -= 0x10000; - __archive_wstrappend_wchar(dest, - ((wc >> 10) & 0x3ff) + 0xD800); - __archive_wstrappend_wchar(dest, - (wc & 0x3ff) + 0xDC00); + archive_wstrappend_wchar(dest, + ((wc >> 10) & 0x3ff) + 0xD800); + archive_wstrappend_wchar(dest, + (wc & 0x3ff) + 0xDC00); } else - __archive_wstrappend_wchar(dest, wc); + archive_wstrappend_wchar(dest, wc); } return (0); } int -__archive_wstrappend_mbs(struct archive_wstring *dest, +archive_wstrappend_mbs(struct archive_wstring *dest, struct archive_string *src) { size_t r; @@ -415,8 +423,8 @@ __archive_wstrappend_mbs(struct archive_wstring *dest, * 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()"); + if (NULL == archive_wstring_ensure(dest, wcs_length + 1)) + __archive_errx(1, "No memory for archive_mstring_get_wcs()"); r = mbstowcs(dest->s, src->s, wcs_length); if (r != (size_t)-1 && r != 0) { dest->s[r] = 0; @@ -438,7 +446,7 @@ __archive_wstrappend_mbs(struct archive_wstring *dest, * wrapper is going to know.) */ struct archive_string * -__archive_strappend_w_mbs(struct archive_string *as, const wchar_t *w) +archive_strappend_w_mbs(struct archive_string *as, const wchar_t *w) { char *p; int l, wl; @@ -460,7 +468,7 @@ __archive_strappend_w_mbs(struct archive_string *as, const wchar_t *w) free(p); return (NULL); } - __archive_string_append(as, p, l); + archive_string_append(as, p, l); free(p); return (as); } @@ -477,11 +485,11 @@ __archive_strappend_w_mbs(struct archive_string *as, const wchar_t *w) * either of these, fall back to the built-in UTF8 conversion. */ struct archive_string * -__archive_strappend_w_mbs(struct archive_string *as, const wchar_t *w) +archive_strappend_w_mbs(struct archive_string *as, const wchar_t *w) { #if !defined(HAVE_WCTOMB) && !defined(HAVE_WCRTOMB) /* If there's no built-in locale support, fall back to UTF8 always. */ - return __archive_strappend_w_utf8(as, w); + return archive_strappend_w_utf8(as, w); #else /* We cannot use the standard wcstombs() here because it * cannot tell us how big the output buffer should be. So @@ -530,3 +538,150 @@ __archive_strappend_w_mbs(struct archive_string *as, const wchar_t *w) } #endif /* _WIN32 && ! __CYGWIN__ */ + + +/* + * Multistring operations. + */ + +void +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)); + aes->aes_set = 0; +} + +void +archive_mstring_copy(struct archive_mstring *dest, struct archive_mstring *src) +{ + dest->aes_set = src->aes_set; + archive_string_copy(&(dest->aes_mbs), &(src->aes_mbs)); + archive_string_copy(&(dest->aes_utf8), &(src->aes_utf8)); + archive_wstring_copy(&(dest->aes_wcs), &(src->aes_wcs)); +} + +const char * +archive_mstring_get_mbs(struct archive_mstring *aes) +{ + /* If we already have an MBS form, return that immediately. */ + if (aes->aes_set & AES_SET_MBS) + 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.s) != NULL) { + aes->aes_set |= AES_SET_MBS; + return (aes->aes_mbs.s); + } + /* We'll use UTF-8 for MBS if all else fails. */ + 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); +} + +const wchar_t * +archive_mstring_get_wcs(struct archive_mstring *aes) +{ + /* Return WCS form if we already have it. */ + if (aes->aes_set & AES_SET_WCS) + 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); + } + /* 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); +} + +int +archive_mstring_copy_mbs(struct archive_mstring *aes, const char *mbs) +{ + if (mbs == NULL) { + aes->aes_set = 0; + return (0); + } + aes->aes_set = AES_SET_MBS; /* Only MBS form is set now. */ + archive_strcpy(&(aes->aes_mbs), mbs); + archive_string_empty(&(aes->aes_utf8)); + archive_wstring_empty(&(aes->aes_wcs)); + return (0); +} + +int +archive_mstring_copy_wcs(struct archive_mstring *aes, const wchar_t *wcs) +{ + return archive_mstring_copy_wcs_len(aes, wcs, wcs == NULL ? 0 : wcslen(wcs)); +} + +int +archive_mstring_copy_wcs_len(struct archive_mstring *aes, const wchar_t *wcs, size_t len) +{ + if (wcs == NULL) { + aes->aes_set = 0; + } + aes->aes_set = AES_SET_WCS; /* Only WCS form set. */ + archive_string_empty(&(aes->aes_mbs)); + archive_string_empty(&(aes->aes_utf8)); + archive_wstrncpy(&(aes->aes_wcs), wcs, len); + return (0); +} + +/* + * The 'update' form tries to proactively update all forms of + * this string (WCS and MBS) and returns an error if any of + * them fail. This is used by the 'pax' handler, for instance, + * to detect and report character-conversion failures early while + * still allowing clients to get potentially useful values from + * the more tolerant lazy conversions. (get_mbs and get_wcs will + * strive to give the user something useful, so you can get hopefully + * usable values even if some of the character conversions are failing.) + */ +int +archive_mstring_update_utf8(struct archive_mstring *aes, const char *utf8) +{ + if (utf8 == NULL) { + aes->aes_set = 0; + return (1); /* Succeeded in clearing everything. */ + } + + /* Save the UTF8 string. */ + archive_strcpy(&(aes->aes_utf8), utf8); + + /* Empty the mbs and wcs strings. */ + archive_string_empty(&(aes->aes_mbs)); + archive_wstring_empty(&(aes->aes_wcs)); + + aes->aes_set = AES_SET_UTF8; /* Only UTF8 is set now. */ + + /* TODO: We should just do a direct UTF-8 to MBS conversion + * here. That would be faster, use less space, and give the + * same information. (If a UTF-8 to MBS conversion succeeds, + * then UTF-8->WCS and Unicode->MBS conversions will both + * succeed.) */ + + /* Try converting UTF8 to WCS, return false on failure. */ + 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.s) == NULL) + return (0); + aes->aes_set = AES_SET_UTF8 | AES_SET_WCS | AES_SET_MBS; + + /* All conversions succeeded. */ + return (1); +} diff --git a/libarchive/archive_string.h b/libarchive/archive_string.h index 8b1f2c404..e9bc7116a 100644 --- a/libarchive/archive_string.h +++ b/libarchive/archive_string.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2003-2010 Tim Kientzle * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -47,26 +47,22 @@ #include "archive.h" /* - * Basic resizable/reusable string support a la Java's "StringBuffer." + * Basic resizable/reusable string support similar to Java's "StringBuffer." * * Unlike sbuf(9), the buffers here are fully reusable and track the * length throughout. - * - * Note that all visible symbols here begin with "__archive" as they - * are internal symbols not intended for anyone outside of this library - * to see or use. */ struct archive_string { char *s; /* Pointer to the storage */ - size_t length; /* Length of 's' */ - size_t buffer_length; /* Length of malloc-ed storage */ + size_t length; /* Length of 's' in characters */ + size_t buffer_length; /* Length of malloc-ed storage in bytes. */ }; 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 */ + size_t buffer_length; /* Length of malloc-ed storage in bytes. */ }; /* Initialize an archive_string object on the stack or elsewhere. */ @@ -75,53 +71,36 @@ struct archive_wstring { /* Append a C char to an archive_string, resizing as necessary. */ struct archive_string * -__archive_strappend_char(struct archive_string *, char); -#define archive_strappend_char __archive_strappend_char +archive_strappend_char(struct archive_string *, char); + +/* Ditto for a wchar_t and an archive_wstring. */ struct archive_wstring * -__archive_wstrappend_wchar(struct archive_wstring *, wchar_t); -#define archive_wstrappend_wchar __archive_wstrappend_wchar +archive_wstrappend_wchar(struct archive_wstring *, wchar_t); -/* Convert a wide-char string to UTF-8 and append the result. */ +/* Convert a Unicode string to UTF-8 and append the result. */ struct archive_string * -__archive_strappend_w_utf8(struct archive_string *, const wchar_t *); -#define archive_strappend_w_utf8 __archive_strappend_w_utf8 +archive_strappend_w_utf8(struct archive_string *, const wchar_t *); -/* Convert a wide-char string to current locale and append the result. */ +/* Convert a Unicode string to current locale and append the result. */ /* Returns NULL if conversion fails. */ struct archive_string * -__archive_strappend_w_mbs(struct archive_string *, const wchar_t *); -#define archive_strappend_w_mbs __archive_strappend_w_mbs - -/* 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); +archive_strappend_w_mbs(struct archive_string *, const wchar_t *); /* 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)) -void -__archive_wstring_copy(struct archive_wstring *dest, struct archive_wstring *src); -#define archive_wstring_copy(dest, src) \ - __archive_wstring_copy((dest), (src)) +#define archive_string_copy(dest, src) \ + ((dest)->length = 0, archive_string_concat((dest), (src))) +#define archive_wstring_copy(dest, src) \ + ((dest)->length = 0, archive_wstring_concat((dest), (src))) /* Concatenate one archive_string to another */ -void -__archive_string_concat(struct archive_string *dest, struct archive_string *src); -#define archive_string_concat(dest, src) \ - __archive_string_concat(dest, src) +void archive_string_concat(struct archive_string *dest, struct archive_string *src); +void archive_wstring_concat(struct archive_wstring *dest, struct archive_wstring *src); /* Ensure that the underlying buffer is at least as large as the request. */ struct archive_string * -__archive_string_ensure(struct archive_string *, size_t); -#define archive_string_ensure __archive_string_ensure - +archive_string_ensure(struct archive_string *, size_t); struct archive_wstring * -__archive_wstring_ensure(struct archive_wstring *, size_t); -#define archive_wstring_ensure __archive_wstring_ensure +archive_wstring_ensure(struct archive_wstring *, size_t); /* Append C string, which may lack trailing \0. */ /* The source is declared void * here because this gets used with @@ -129,15 +108,15 @@ __archive_wstring_ensure(struct archive_wstring *, size_t); * Declaring it "char *" as with some of the other functions just * leads to a lot of extra casts. */ struct archive_string * -__archive_strncat(struct archive_string *, const void *, size_t); -#define archive_strncat __archive_strncat +archive_strncat(struct archive_string *, const void *, size_t); struct archive_wstring * -__archive_wstrncat(struct archive_wstring *, const void *, size_t); -#define archive_wstrncat __archive_wstrncat +archive_wstrncat(struct archive_wstring *, const wchar_t *, size_t); /* Append a C string to an archive_string, resizing as necessary. */ -#define archive_strcat(as,p) __archive_string_append((as),(p),strlen(p)) -#define archive_wstrcat(as,p) __archive_wstring_append((as),(p),wcslen(p)) +struct archive_string * +archive_strcat(struct archive_string *, const void *); +struct archive_wstring * +archive_wstrcat(struct archive_wstring *, const wchar_t *); /* Copy a C string to an archive_string, resizing as necessary. */ #define archive_strcpy(as,p) \ @@ -149,7 +128,7 @@ __archive_wstrncat(struct archive_wstring *, const void *, size_t); #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))) + ((as)->length = 0, archive_wstrncat((as), (p), (l))) /* Return length of string. */ #define archive_strlen(a) ((a)->length) @@ -159,28 +138,54 @@ __archive_wstrncat(struct archive_wstring *, const void *, size_t); #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 -void __archive_wstring_free(struct archive_wstring *); -#define archive_wstring_free __archive_wstring_free +void archive_string_free(struct archive_string *); +void archive_wstring_free(struct archive_wstring *); /* Like 'vsprintf', but resizes the underlying string as necessary. */ -void __archive_string_vsprintf(struct archive_string *, const char *, +/* Note: This only implements a small subset of standard printf functionality. */ +void archive_string_vsprintf(struct archive_string *, const char *, va_list) __LA_PRINTF(2, 0); -#define archive_string_vsprintf __archive_string_vsprintf - -void __archive_string_sprintf(struct archive_string *, const char *, ...) +void archive_string_sprintf(struct archive_string *, const char *, ...) __LA_PRINTF(2, 3); -#define archive_string_sprintf __archive_string_sprintf /* 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, +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, +int archive_wstrappend_mbs(struct archive_wstring *dest, struct archive_string *src); + +/* A "multistring" can hold Unicode, UTF8, or MBS versions of + * the string. If you set and read the same version, no translation + * is done. If you set and read different versions, the library + * will attempt to transparently convert. + */ +struct archive_mstring { + struct archive_string aes_mbs; + struct archive_string aes_utf8; + 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 + * has been set. */ + int aes_set; +#define AES_SET_MBS 1 +#define AES_SET_UTF8 2 +#define AES_SET_WCS 4 +}; + +void archive_mstring_clean(struct archive_mstring *); +void archive_mstring_copy(struct archive_mstring *dest, struct archive_mstring *src); +const char * archive_mstring_get_mbs(struct archive_mstring *); +const wchar_t * archive_mstring_get_wcs(struct archive_mstring *); +int archive_mstring_copy_mbs(struct archive_mstring *, const char *mbs); +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_update_utf8(struct archive_mstring *aes, const char *utf8); + + #endif diff --git a/libarchive/archive_string_sprintf.c b/libarchive/archive_string_sprintf.c index 02f5366df..48add6e14 100644 --- a/libarchive/archive_string_sprintf.c +++ b/libarchive/archive_string_sprintf.c @@ -69,7 +69,7 @@ append_int(struct archive_string *as, intmax_t d, unsigned base) void -__archive_string_sprintf(struct archive_string *as, const char *fmt, ...) +archive_string_sprintf(struct archive_string *as, const char *fmt, ...) { va_list ap; @@ -83,7 +83,7 @@ __archive_string_sprintf(struct archive_string *as, const char *fmt, ...) * necessary. */ void -__archive_string_vsprintf(struct archive_string *as, const char *fmt, +archive_string_vsprintf(struct archive_string *as, const char *fmt, va_list ap) { char long_flag; @@ -92,7 +92,7 @@ __archive_string_vsprintf(struct archive_string *as, const char *fmt, const char *p, *p2; const wchar_t *pw; - if (__archive_string_ensure(as, 64) == NULL) + if (archive_string_ensure(as, 64) == NULL) __archive_errx(1, "Out of memory"); if (fmt == NULL) { @@ -122,11 +122,11 @@ __archive_string_vsprintf(struct archive_string *as, const char *fmt, switch (*p) { case '%': - __archive_strappend_char(as, '%'); + archive_strappend_char(as, '%'); break; case 'c': s = va_arg(ap, int); - __archive_strappend_char(as, s); + archive_strappend_char(as, s); break; case 'd': switch(long_flag) { diff --git a/libarchive/archive_write_set_format_iso9660.c b/libarchive/archive_write_set_format_iso9660.c index c2f7f0d43..46d2511fd 100644 --- a/libarchive/archive_write_set_format_iso9660.c +++ b/libarchive/archive_write_set_format_iso9660.c @@ -5316,7 +5316,7 @@ isoent_tree(struct archive_write *a, struct isoent **isoentpp) struct archive_string as; archive_string_init(&as); - __archive_string_append(&as, p, fn - p + l); + archive_strncat(&as, p, fn - p + l); if (as.s[as.length-1] == '/') { as.s[as.length-1] = '\0'; as.length--; diff --git a/libarchive/archive_write_set_format_xar.c b/libarchive/archive_write_set_format_xar.c index 50f8cc6cc..8b5169e5a 100644 --- a/libarchive/archive_write_set_format_xar.c +++ b/libarchive/archive_write_set_format_xar.c @@ -2225,7 +2225,7 @@ file_tree(struct archive_write *a, struct file **filepp) struct archive_string as; archive_string_init(&as); - __archive_string_append(&as, p, fn - p + l); + archive_strncat(&as, p, fn - p + l); if (as.s[as.length-1] == '/') { as.s[as.length-1] = '\0'; as.length--;