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);
#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
{
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);
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;
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;
}
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);
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);
}
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);
}
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);
}
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
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);
}
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);
}
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));
}
/*
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;
}
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));
}
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));
}
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
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
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
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
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
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. */
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. */
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
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
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
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
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
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
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 *
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;
}
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);
}
/*
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);
}
/*
*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);
}
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
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;
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)
#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 {
/*
* 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;
/*-
- * 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
/*
* 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
#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;
}
void
-__archive_wstring_free(struct archive_wstring *as)
+archive_wstring_free(struct archive_wstring *as)
{
as->length = 0;
as->buffer_length = 0;
}
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);
*/
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);
}
}
* 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;
/* 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));
}
/*
* 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;
* 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;
/* 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;
* 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;
* 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;
free(p);
return (NULL);
}
- __archive_string_append(as, p, l);
+ archive_string_append(as, p, l);
free(p);
return (as);
}
* 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
}
#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);
+}
/*-
- * 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. */
/* 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
* 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) \
#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)
#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
void
-__archive_string_sprintf(struct archive_string *as, const char *fmt, ...)
+archive_string_sprintf(struct archive_string *as, const char *fmt, ...)
{
va_list ap;
* 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;
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) {
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) {
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--;
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--;