/*
* Copyright (c) 2003-2008 Hypertriton, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Serialization functions for strings.
*/
#include
/* Allocate and read a length-encoded string. */
char *
AG_ReadStringLen(AG_DataSource *ds, size_t maxlen)
{
Uint32 len;
char *s;
AG_LockDataSource(ds);
if (AG_CheckTypev(ds, AG_SOURCE_STRING) == -1) {
goto fail;
}
if (AG_ReadUint32v(ds, &len) == -1) {
AG_SetError("String length: %s", AG_GetError());
goto fail;
}
if (len > (Uint32)maxlen) {
AG_SetError("String (%luB): Exceeds %luB limit", (Ulong)len,
(Ulong)maxlen);
goto fail;
}
if ((s = malloc((size_t)len+1)) == NULL) {
AG_SetError("String (%luB): Out of memory", (Ulong)len);
goto fail;
}
if (len > 0) {
if (AG_Read(ds, s, len, 1) != 0) {
AG_SetError("String (%luB): %s", (Ulong)len,
AG_GetError());
free(s);
goto fail;
}
}
s[len] = '\0';
AG_UnlockDataSource(ds);
return (s);
fail:
AG_DataSourceError(ds, NULL);
AG_UnlockDataSource(ds);
return (NULL);
}
/* Allocate and read a length-encoded string (no exceptions). */
int
AG_ReadStringLenv(AG_DataSource *ds, size_t maxlen, char **s)
{
Uint32 len;
AG_LockDataSource(ds);
if (AG_CheckTypev(ds, AG_SOURCE_STRING) == -1) {
goto fail;
}
if (AG_ReadUint32v(ds, &len) == -1) {
AG_SetError("String length: %s", AG_GetError());
goto fail;
}
if (len > (Uint32)maxlen) {
AG_SetError("String (%luB): Exceeds %luB limit", (Ulong)len,
(Ulong)maxlen);
goto fail;
}
if ((*s = malloc((size_t)len+1)) == NULL) {
AG_SetError("String (%luB): Out of memory", (Ulong)len);
goto fail;
}
if (len > 0) {
if (AG_Read(ds, *s, len, 1) != 0) {
AG_SetError("String (%luB): %s", (Ulong)len,
AG_GetError());
free(*s);
*s = NULL;
goto fail;
}
}
(*s)[len] = '\0';
AG_UnlockDataSource(ds);
return (0);
fail:
AG_DataSourceError(ds, NULL);
return (-1);
}
/*
* Allocate and read a NUL-terminated, length-encoded string. Type checking
* is never done.
*/
char *
AG_ReadNulStringLen(AG_DataSource *ds, size_t maxlen)
{
Uint32 len;
char *s;
AG_LockDataSource(ds);
if (AG_ReadUint32v(ds, &len) == -1) {
AG_SetError("String length: %s", AG_GetError());
goto fail;
}
if (len > (Uint32)maxlen) {
AG_SetError("String (%luB): Exceeds %luB limit", (Ulong)len,
(Ulong)maxlen);
goto fail;
}
if ((s = malloc((size_t)len)) == NULL) {
AG_SetError("String (%luB): Out of memory", (Ulong)len);
goto fail;
}
if (len > 0) {
if (AG_Read(ds, s, (size_t)len, 1) != 0) {
AG_SetError("String (%luB): %s", (Ulong)len,
AG_GetError());
free(s);
goto fail;
}
}
AG_UnlockDataSource(ds);
return (s);
fail:
AG_DataSourceError(ds, NULL);
AG_UnlockDataSource(ds);
return (NULL);
}
/* Write a length-encoded string. */
void
AG_WriteString(AG_DataSource *ds, const char *s)
{
size_t len;
AG_WriteType(ds, AG_SOURCE_STRING);
if (s == NULL || s[0] == '\0') {
AG_WriteUint32(ds, 0);
} else {
len = strlen(s);
AG_WriteUint32(ds, (Uint32)len);
if (AG_Write(ds, s, len, 1) != 0)
AG_DataSourceError(ds, NULL);
}
}
/* Write a length-encoded string (no exceptions). */
int
AG_WriteStringv(AG_DataSource *ds, const char *s)
{
Uint32 len = (s != NULL && s[0] != '\0') ? strlen(s) : 0;
if (AG_WriteTypev(ds, AG_SOURCE_STRING) == -1 ||
AG_WriteUint32v(ds, &len) == -1) {
return (-1);
}
return (len > 0) ? AG_Write(ds, s, len, 1) : 0;
}
/*
* Copy at most dst_size bytes from a length-encoded string to a fixed-size
* buffer, returning the number of bytes that would have been copied were
* dst_size unlimited. The function NUL-terminates the string.
*/
size_t
AG_CopyString(char *dst, AG_DataSource *ds, size_t dst_size)
{
size_t rv;
Uint32 len;
AG_LockDataSource(ds);
if (AG_CheckTypev(ds, AG_SOURCE_STRING) == -1) {
goto fail;
}
if (AG_ReadUint32v(ds, &len) == -1) {
AG_SetError("String length: %s", AG_GetError());
goto fail;
}
if (len > (Uint32)(dst_size-1)) {
#ifdef AG_DEBUG
Verbose("0x%x: %luB string truncated to fit %luB buffer\n",
(Uint)AG_Tell(ds), (Ulong)len, (Ulong)dst_size);
#endif
rv = (size_t)len+1; /* Save the intended length */
len = dst_size-1;
} else {
rv = (size_t)len;
}
if (len == 0) {
dst[0] = '\0';
} else {
if (AG_Read(ds, dst, 1, (size_t)len) != 0) {
goto fail;
}
dst[ds->rdLast] = '\0';
}
AG_UnlockDataSource(ds);
return (rv); /* Count does not include NUL */
fail:
AG_DataSourceError(ds, NULL);
AG_UnlockDataSource(ds);
dst[0] = '\0';
return (0);
}
/* Skip over a length-encoded string. */
void
AG_SkipString(AG_DataSource *ds)
{
Uint32 len;
AG_LockDataSource(ds);
if (AG_CheckTypev(ds, AG_SOURCE_STRING) == -1) {
goto fail;
}
if (AG_ReadUint32v(ds, &len) == -1) {
AG_SetError("String length: %s", AG_GetError());
goto fail;
}
if (AG_Seek(ds, (size_t)len, AG_SEEK_CUR) == -1)
goto fail;
AG_UnlockDataSource(ds);
return;
fail:
AG_DataSourceError(ds, NULL);
AG_UnlockDataSource(ds);
}
/*
* Copy at most dst_size bytes from a length-encoded, NUL-terminated string
* to a fixed-size buffer, returning the number of bytes that would have been
* copied were dst_size unlimited. Type checking is never done.
*/
size_t
AG_CopyNulString(char *dst, AG_DataSource *ds, size_t dst_size)
{
size_t rv;
Uint32 len;
AG_LockDataSource(ds);
if (AG_ReadUint32v(ds, &len) == -1) {
AG_SetError("String length: %s", AG_GetError());
goto fail;
}
if (len > (Uint32)dst_size) {
#ifdef AG_DEBUG
Verbose("0x%x: %luB string truncated to fit %luB buffer\n",
(Uint)AG_Tell(ds), (Ulong)len, (Ulong)dst_size);
#endif
rv = (size_t)len; /* Save the intended length */
len = dst_size;
} else {
rv = (size_t)len;
}
if (AG_Read(ds, dst, 1, (size_t)len) != 0)
goto fail;
AG_UnlockDataSource(ds);
return (rv-1); /* Count does not include NUL */
fail:
AG_DataSourceError(ds, NULL);
dst[0] = '\0';
AG_UnlockDataSource(ds);
return (0);
}