]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Big string overhaul:
authorTim Kientzle <kientzle@gmail.com>
Fri, 19 Nov 2010 06:49:07 +0000 (01:49 -0500)
committerTim Kientzle <kientzle@gmail.com>
Fri, 19 Nov 2010 06:49:07 +0000 (01:49 -0500)
  * 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

libarchive/archive_entry.c
libarchive/archive_entry_private.h
libarchive/archive_string.c
libarchive/archive_string.h
libarchive/archive_string_sprintf.c
libarchive/archive_write_set_format_iso9660.c
libarchive/archive_write_set_format_xar.c

index 72b753cf161e3f5041dbe794e8da7933d739a6cb..6af94d2d325fb2e5a03826a512bb3ff5dcc3f687 100644 (file)
@@ -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)
index 6d22c1df81f16109c03b803998d14416fba4eb01..785ca5f6cd7b91a0158881c784cf1dbd3ed1df62 100644 (file)
 
 #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;
index 2dd6b1b8589ab619911112d49c5eceb0b9cde8ec..3092bde81fb59c4880ad1380cde9c56c5f826f68 100644 (file)
@@ -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);
+}
index 8b1f2c404490dbb5addfd91f2c363539b3e829cc..e9bc7116a6ffb11d613b4c55c1c3fd3a57ff8b04 100644 (file)
@@ -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
 #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
index 02f5366df6c5fb69f1e60ecf7be66b2c69e9d82d..48add6e14b98744355d4ab51d9cae20968b14808 100644 (file)
@@ -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) {
index c2f7f0d4332e88258077305ae32d534280cb9aeb..46d2511fd4a5af6f1462151ee4c8807e2e1e4273 100644 (file)
@@ -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--;
index 50f8cc6ccb7810bdf04f3333f88ad309fe918502..8b5169e5a33a092cb7cf33abd3ae76b94785462c 100644 (file)
@@ -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--;