Blame egg/egg-buffer.c

Packit b00eeb
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
Packit b00eeb
/* egg-buffer.c - Generic data buffer, used by openssh, gnome-keyring
Packit b00eeb
Packit b00eeb
   Copyright (C) 2007 Stefan Walter
Packit b00eeb
Packit b00eeb
   The Gnome Keyring Library is free software; you can redistribute it and/or
Packit b00eeb
   modify it under the terms of the GNU Library General Public License as
Packit b00eeb
   published by the Free Software Foundation; either version 2 of the
Packit b00eeb
   License, or (at your option) any later version.
Packit b00eeb
Packit b00eeb
   The Gnome Keyring Library is distributed in the hope that it will be useful,
Packit b00eeb
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit b00eeb
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit b00eeb
   Library General Public License for more details.
Packit b00eeb
Packit b00eeb
   You should have received a copy of the GNU Library General Public
Packit b00eeb
   License along with the Gnome Library; see the file COPYING.LIB.  If not,
Packit b00eeb
   see <http://www.gnu.org/licenses/>.
Packit b00eeb
Packit b00eeb
   Author: Stef Walter <stef@memberwebs.com>
Packit b00eeb
*/
Packit b00eeb
#include "config.h"
Packit b00eeb
Packit b00eeb
#include <string.h>
Packit b00eeb
#include <stdarg.h>
Packit b00eeb
Packit b00eeb
#include "egg-buffer.h"
Packit b00eeb
Packit b00eeb
#define DEFAULT_ALLOCATOR  ((EggBufferAllocator)realloc)
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_init (EggBuffer *buffer, size_t reserve)
Packit b00eeb
{
Packit b00eeb
	return egg_buffer_init_full (buffer, reserve, NULL);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_init_full (EggBuffer *buffer, size_t reserve, EggBufferAllocator allocator)
Packit b00eeb
{
Packit b00eeb
	memset (buffer, 0, sizeof (*buffer));
Packit b00eeb
Packit b00eeb
	if (!allocator)
Packit b00eeb
		allocator = DEFAULT_ALLOCATOR;
Packit b00eeb
	if (reserve == 0)
Packit b00eeb
		reserve = 64;
Packit b00eeb
Packit b00eeb
	buffer->buf = (allocator) (NULL, reserve);
Packit b00eeb
	if (!buffer->buf) {
Packit b00eeb
		buffer->failures++;
Packit b00eeb
		return 0;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	buffer->len = 0;
Packit b00eeb
	buffer->allocated_len = reserve;
Packit b00eeb
	buffer->failures = 0;
Packit b00eeb
	buffer->allocator = allocator;
Packit b00eeb
Packit b00eeb
	return 1;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
void
Packit b00eeb
egg_buffer_init_static (EggBuffer* buffer, const unsigned char *buf, size_t len)
Packit b00eeb
{
Packit b00eeb
	memset (buffer, 0, sizeof (*buffer));
Packit b00eeb
Packit b00eeb
	buffer->buf = (unsigned char*)buf;
Packit b00eeb
	buffer->len = len;
Packit b00eeb
	buffer->allocated_len = len;
Packit b00eeb
	buffer->failures = 0;
Packit b00eeb
Packit b00eeb
	/* A null allocator, and the buffer can't change in size */
Packit b00eeb
	buffer->allocator = NULL;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
void
Packit b00eeb
egg_buffer_init_allocated (EggBuffer *buffer, unsigned char *buf, size_t len,
Packit b00eeb
                           EggBufferAllocator allocator)
Packit b00eeb
{
Packit b00eeb
	memset (buffer, 0, sizeof (*buffer));
Packit b00eeb
Packit b00eeb
	if (!allocator)
Packit b00eeb
		allocator = DEFAULT_ALLOCATOR;
Packit b00eeb
Packit b00eeb
	buffer->buf = buf;
Packit b00eeb
	buffer->len = len;
Packit b00eeb
	buffer->allocated_len = len;
Packit b00eeb
	buffer->failures = 0;
Packit b00eeb
	buffer->allocator = allocator;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
void
Packit b00eeb
egg_buffer_reset (EggBuffer *buffer)
Packit b00eeb
{
Packit b00eeb
	memset (buffer->buf, 0, buffer->allocated_len);
Packit b00eeb
	buffer->len = 0;
Packit b00eeb
	buffer->failures = 0;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
void
Packit b00eeb
egg_buffer_uninit (EggBuffer *buffer)
Packit b00eeb
{
Packit b00eeb
	if (!buffer)
Packit b00eeb
		return;
Packit b00eeb
Packit b00eeb
	/*
Packit b00eeb
	 * Free the memory block using allocator. If no allocator,
Packit b00eeb
	 * then this memory is ownerd elsewhere and not to be freed.
Packit b00eeb
	 */
Packit b00eeb
	if (buffer->buf && buffer->allocator)
Packit b00eeb
		(buffer->allocator) (buffer->buf, 0);
Packit b00eeb
Packit b00eeb
	memset (buffer, 0, sizeof (*buffer));
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
unsigned char*
Packit b00eeb
egg_buffer_uninit_steal (EggBuffer *buffer, size_t *n_result)
Packit b00eeb
{
Packit b00eeb
	unsigned char *result;
Packit b00eeb
Packit b00eeb
	if (n_result)
Packit b00eeb
		*n_result = buffer->len;
Packit b00eeb
	result = buffer->buf;
Packit b00eeb
Packit b00eeb
	memset (buffer, 0, sizeof (*buffer));
Packit b00eeb
Packit b00eeb
	return result;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_set_allocator (EggBuffer *buffer, EggBufferAllocator allocator)
Packit b00eeb
{
Packit b00eeb
	unsigned char *buf = NULL;
Packit b00eeb
Packit b00eeb
	if (!allocator)
Packit b00eeb
		allocator = DEFAULT_ALLOCATOR;
Packit b00eeb
	if (buffer->allocator == allocator)
Packit b00eeb
		return 1;
Packit b00eeb
Packit b00eeb
	if (buffer->allocated_len) {
Packit b00eeb
		/* Reallocate memory block using new allocator */
Packit b00eeb
		buf = (allocator) (NULL, buffer->allocated_len);
Packit b00eeb
		if (buf == NULL)
Packit b00eeb
			return 0;
Packit b00eeb
Packit b00eeb
		/* Copy stuff into new memory */
Packit b00eeb
		memcpy (buf, buffer->buf, buffer->allocated_len);
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	/* If old wasn't static, then free it */
Packit b00eeb
	if (buffer->allocator && buffer->buf)
Packit b00eeb
		(buffer->allocator) (buffer->buf, 0);
Packit b00eeb
Packit b00eeb
	buffer->buf = buf;
Packit b00eeb
	buffer->allocator = allocator;
Packit b00eeb
Packit b00eeb
	return 1;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_equal (EggBuffer *b1, EggBuffer *b2)
Packit b00eeb
{
Packit b00eeb
	if (b1->len != b2->len)
Packit b00eeb
		return 0;
Packit b00eeb
	return memcmp (b1->buf, b2->buf, b1->len) == 0;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_reserve (EggBuffer *buffer, size_t len)
Packit b00eeb
{
Packit b00eeb
	unsigned char *newbuf;
Packit b00eeb
	size_t newlen;
Packit b00eeb
Packit b00eeb
	if (len < buffer->allocated_len)
Packit b00eeb
		return 1;
Packit b00eeb
Packit b00eeb
	/* Calculate a new length, minimize number of buffer allocations */
Packit b00eeb
	newlen = buffer->allocated_len * 2;
Packit b00eeb
	if (len > newlen)
Packit b00eeb
		newlen += len;
Packit b00eeb
Packit b00eeb
	/* Memory owned elsewhere can't be reallocated */
Packit b00eeb
	if (!buffer->allocator) {
Packit b00eeb
		buffer->failures++;
Packit b00eeb
		return 0;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	/* Reallocate built in buffer using allocator */
Packit b00eeb
	newbuf = (buffer->allocator) (buffer->buf, newlen);
Packit b00eeb
	if (!newbuf) {
Packit b00eeb
		buffer->failures++;
Packit b00eeb
		return 0;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	buffer->buf = newbuf;
Packit b00eeb
	buffer->allocated_len = newlen;
Packit b00eeb
Packit b00eeb
	return 1;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_resize (EggBuffer *buffer, size_t len)
Packit b00eeb
{
Packit b00eeb
	if (!egg_buffer_reserve (buffer, len))
Packit b00eeb
		return 0;
Packit b00eeb
Packit b00eeb
	buffer->len = len;
Packit b00eeb
	return 1;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
unsigned char*
Packit b00eeb
egg_buffer_add_empty (EggBuffer *buffer, size_t len)
Packit b00eeb
{
Packit b00eeb
	size_t pos = buffer->len;
Packit b00eeb
	if (!egg_buffer_reserve (buffer, buffer->len + len))
Packit b00eeb
		return NULL;
Packit b00eeb
	buffer->len += len;
Packit b00eeb
	return buffer->buf + pos;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_append (EggBuffer *buffer, const unsigned char *val,
Packit b00eeb
                             size_t len)
Packit b00eeb
{
Packit b00eeb
	if (!egg_buffer_reserve (buffer, buffer->len + len))
Packit b00eeb
		return 0; /* failures already incremented */
Packit b00eeb
	memcpy (buffer->buf + buffer->len, val, len);
Packit b00eeb
	buffer->len += len;
Packit b00eeb
	return 1;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_add_byte (EggBuffer *buffer, unsigned char val)
Packit b00eeb
{
Packit b00eeb
	if (!egg_buffer_reserve (buffer, buffer->len + 1))
Packit b00eeb
		return 0; /* failures already incremented */
Packit b00eeb
	buffer->buf[buffer->len] = val;
Packit b00eeb
	buffer->len++;
Packit b00eeb
	return 1;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_get_byte (EggBuffer *buffer, size_t offset,
Packit b00eeb
                               size_t *next_offset, unsigned char *val)
Packit b00eeb
{
Packit b00eeb
	unsigned char *ptr;
Packit b00eeb
	if (buffer->len < 1 || offset > buffer->len - 1) {
Packit b00eeb
		buffer->failures++;
Packit b00eeb
		return 0;
Packit b00eeb
	}
Packit b00eeb
	ptr = (unsigned char*)buffer->buf + offset;
Packit b00eeb
	if (val != NULL)
Packit b00eeb
		*val = *ptr;
Packit b00eeb
	if (next_offset != NULL)
Packit b00eeb
		*next_offset = offset + 1;
Packit b00eeb
	return 1;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
void
Packit b00eeb
egg_buffer_encode_uint16 (unsigned char* buf, uint16_t val)
Packit b00eeb
{
Packit b00eeb
	buf[0] = (val >> 8) & 0xff;
Packit b00eeb
	buf[1] = (val >> 0) & 0xff;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
uint16_t
Packit b00eeb
egg_buffer_decode_uint16 (unsigned char* buf)
Packit b00eeb
{
Packit b00eeb
	uint16_t val = buf[0] << 8 | buf[1];
Packit b00eeb
	return val;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_add_uint16 (EggBuffer *buffer, uint16_t val)
Packit b00eeb
{
Packit b00eeb
	if (!egg_buffer_reserve (buffer, buffer->len + 2))
Packit b00eeb
		return 0; /* failures already incremented */
Packit b00eeb
	buffer->len += 2;
Packit b00eeb
	egg_buffer_set_uint16 (buffer, buffer->len - 2, val);
Packit b00eeb
	return 1;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_set_uint16 (EggBuffer *buffer, size_t offset, uint16_t val)
Packit b00eeb
{
Packit b00eeb
	unsigned char *ptr;
Packit b00eeb
	if (buffer->len < 2 || offset > buffer->len - 2) {
Packit b00eeb
		buffer->failures++;
Packit b00eeb
		return 0;
Packit b00eeb
	}
Packit b00eeb
	ptr = (unsigned char*)buffer->buf + offset;
Packit b00eeb
	egg_buffer_encode_uint16 (ptr, val);
Packit b00eeb
	return 1;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_get_uint16 (EggBuffer *buffer, size_t offset,
Packit b00eeb
                       size_t *next_offset, uint16_t *val)
Packit b00eeb
{
Packit b00eeb
	unsigned char *ptr;
Packit b00eeb
	if (buffer->len < 2 || offset > buffer->len - 2) {
Packit b00eeb
		buffer->failures++;
Packit b00eeb
		return 0;
Packit b00eeb
	}
Packit b00eeb
	ptr = (unsigned char*)buffer->buf + offset;
Packit b00eeb
	if (val != NULL)
Packit b00eeb
		*val = egg_buffer_decode_uint16 (ptr);
Packit b00eeb
	if (next_offset != NULL)
Packit b00eeb
		*next_offset = offset + 2;
Packit b00eeb
	return 1;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
void
Packit b00eeb
egg_buffer_encode_uint32 (unsigned char* buf, uint32_t val)
Packit b00eeb
{
Packit b00eeb
	buf[0] = (val >> 24) & 0xff;
Packit b00eeb
	buf[1] = (val >> 16) & 0xff;
Packit b00eeb
	buf[2] = (val >> 8) & 0xff;
Packit b00eeb
	buf[3] = (val >> 0) & 0xff;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
uint32_t
Packit b00eeb
egg_buffer_decode_uint32 (unsigned char* ptr)
Packit b00eeb
{
Packit b00eeb
	uint32_t val = ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
Packit b00eeb
	return val;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_add_uint32 (EggBuffer *buffer, uint32_t val)
Packit b00eeb
{
Packit b00eeb
	if (!egg_buffer_reserve (buffer, buffer->len + 4))
Packit b00eeb
		return 0; /* failures already incremented */
Packit b00eeb
	buffer->len += 4;
Packit b00eeb
	egg_buffer_set_uint32 (buffer, buffer->len - 4, val);
Packit b00eeb
	return 1;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_set_uint32 (EggBuffer *buffer, size_t offset, uint32_t val)
Packit b00eeb
{
Packit b00eeb
	unsigned char *ptr;
Packit b00eeb
	if (buffer->len < 4 || offset > buffer->len - 4) {
Packit b00eeb
		buffer->failures++;
Packit b00eeb
		return 0;
Packit b00eeb
	}
Packit b00eeb
	ptr = (unsigned char*)buffer->buf + offset;
Packit b00eeb
	egg_buffer_encode_uint32 (ptr, val);
Packit b00eeb
	return 1;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_get_uint32 (EggBuffer *buffer, size_t offset, size_t *next_offset,
Packit b00eeb
                                 uint32_t *val)
Packit b00eeb
{
Packit b00eeb
	unsigned char *ptr;
Packit b00eeb
	if (buffer->len < 4 || offset > buffer->len - 4) {
Packit b00eeb
		buffer->failures++;
Packit b00eeb
		return 0;
Packit b00eeb
	}
Packit b00eeb
	ptr = (unsigned char*)buffer->buf + offset;
Packit b00eeb
	if (val != NULL)
Packit b00eeb
		*val = egg_buffer_decode_uint32 (ptr);
Packit b00eeb
	if (next_offset != NULL)
Packit b00eeb
		*next_offset = offset + 4;
Packit b00eeb
	return 1;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_add_uint64 (EggBuffer *buffer, uint64_t val)
Packit b00eeb
{
Packit b00eeb
	if (!egg_buffer_add_uint32 (buffer, ((val >> 32) & 0xffffffff)))
Packit b00eeb
		return 0;
Packit b00eeb
	return egg_buffer_add_uint32 (buffer, (val & 0xffffffff));
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_get_uint64 (EggBuffer *buffer, size_t offset,
Packit b00eeb
					   size_t *next_offset, uint64_t *val)
Packit b00eeb
{
Packit b00eeb
	uint32_t a, b;
Packit b00eeb
	if (!egg_buffer_get_uint32 (buffer, offset, &offset, &a))
Packit b00eeb
		return 0;
Packit b00eeb
	if (!egg_buffer_get_uint32 (buffer, offset, &offset, &b))
Packit b00eeb
		return 0;
Packit b00eeb
	if (val != NULL)
Packit b00eeb
		*val = ((uint64_t)a) << 32 | b;
Packit b00eeb
	if (next_offset != NULL)
Packit b00eeb
		*next_offset = offset;
Packit b00eeb
	return 1;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_add_byte_array (EggBuffer *buffer, const unsigned char *val,
Packit b00eeb
                                     size_t len)
Packit b00eeb
{
Packit b00eeb
	if (val == NULL)
Packit b00eeb
		return egg_buffer_add_uint32 (buffer, 0xffffffff);
Packit b00eeb
	if (len >= 0x7fffffff) {
Packit b00eeb
		buffer->failures++;
Packit b00eeb
		return 0;
Packit b00eeb
	}
Packit b00eeb
	if (!egg_buffer_add_uint32 (buffer, len))
Packit b00eeb
		return 0;
Packit b00eeb
	return egg_buffer_append (buffer, val, len);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
unsigned char*
Packit b00eeb
egg_buffer_add_byte_array_empty (EggBuffer *buffer, size_t vlen)
Packit b00eeb
{
Packit b00eeb
	if (vlen >= 0x7fffffff) {
Packit b00eeb
		buffer->failures++;
Packit b00eeb
		return NULL;
Packit b00eeb
	}
Packit b00eeb
	if (!egg_buffer_add_uint32 (buffer, vlen))
Packit b00eeb
		return NULL;
Packit b00eeb
	return egg_buffer_add_empty (buffer, vlen);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_get_byte_array (EggBuffer *buffer, size_t offset,
Packit b00eeb
                           size_t *next_offset, const unsigned char **val,
Packit b00eeb
                           size_t *vlen)
Packit b00eeb
{
Packit b00eeb
	uint32_t len;
Packit b00eeb
	if (!egg_buffer_get_uint32 (buffer, offset, &offset, &len))
Packit b00eeb
		return 0;
Packit b00eeb
	if (len == 0xffffffff) {
Packit b00eeb
		if (next_offset)
Packit b00eeb
			*next_offset = offset;
Packit b00eeb
		if (val)
Packit b00eeb
			*val = NULL;
Packit b00eeb
		if (vlen)
Packit b00eeb
			*vlen = 0;
Packit b00eeb
		return 1;
Packit b00eeb
	} else if (len >= 0x7fffffff) {
Packit b00eeb
		buffer->failures++;
Packit b00eeb
		return 0;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	if (buffer->len < len || offset > buffer->len - len) {
Packit b00eeb
		buffer->failures++;
Packit b00eeb
		return 0;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	if (val)
Packit b00eeb
		*val = buffer->buf + offset;
Packit b00eeb
	if (vlen)
Packit b00eeb
		*vlen = len;
Packit b00eeb
	if (next_offset)
Packit b00eeb
		*next_offset = offset + len;
Packit b00eeb
Packit b00eeb
	return 1;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_add_string (EggBuffer *buffer, const char *str)
Packit b00eeb
{
Packit b00eeb
	if (str == NULL) {
Packit b00eeb
		return egg_buffer_add_uint32 (buffer, 0xffffffff);
Packit b00eeb
	} else {
Packit b00eeb
		size_t len = strlen (str);
Packit b00eeb
		if (len >= 0x7fffffff)
Packit b00eeb
			return 0;
Packit b00eeb
		if (!egg_buffer_add_uint32 (buffer, len))
Packit b00eeb
			return 0;
Packit b00eeb
		return egg_buffer_append (buffer, (unsigned char*)str, len);
Packit b00eeb
	}
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_get_string (EggBuffer *buffer, size_t offset, size_t *next_offset,
Packit b00eeb
                       char **str_ret, EggBufferAllocator allocator)
Packit b00eeb
{
Packit b00eeb
	uint32_t len;
Packit b00eeb
Packit b00eeb
	if (!allocator)
Packit b00eeb
		allocator = buffer->allocator;
Packit b00eeb
	if (!allocator)
Packit b00eeb
		allocator = DEFAULT_ALLOCATOR;
Packit b00eeb
Packit b00eeb
	if (!egg_buffer_get_uint32 (buffer, offset, &offset, &len)) {
Packit b00eeb
		return 0;
Packit b00eeb
	}
Packit b00eeb
	if (len == 0xffffffff) {
Packit b00eeb
		*next_offset = offset;
Packit b00eeb
		*str_ret = NULL;
Packit b00eeb
		return 1;
Packit b00eeb
	} else if (len >= 0x7fffffff) {
Packit b00eeb
		return 0;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	if (buffer->len < len ||
Packit b00eeb
	    offset > buffer->len - len) {
Packit b00eeb
		return 0;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	/* Make sure no null characters in string */
Packit b00eeb
	if (memchr (buffer->buf + offset, 0, len) != NULL)
Packit b00eeb
		return 0;
Packit b00eeb
Packit b00eeb
	/* The passed allocator may be for non-pageable memory */
Packit b00eeb
	*str_ret = (allocator) (NULL, len + 1);
Packit b00eeb
	if (!*str_ret)
Packit b00eeb
		return 0;
Packit b00eeb
	memcpy (*str_ret, buffer->buf + offset, len);
Packit b00eeb
Packit b00eeb
	/* Always zero terminate */
Packit b00eeb
	(*str_ret)[len] = 0;
Packit b00eeb
	*next_offset = offset + len;
Packit b00eeb
Packit b00eeb
	return 1;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_add_stringv (EggBuffer *buffer, const char** strv)
Packit b00eeb
{
Packit b00eeb
	const char **v;
Packit b00eeb
	uint32_t n = 0;
Packit b00eeb
Packit b00eeb
	if (!strv)
Packit b00eeb
		return 0;
Packit b00eeb
Packit b00eeb
	/* Add the number of strings coming */
Packit b00eeb
	for (v = strv; *v; ++v)
Packit b00eeb
		++n;
Packit b00eeb
	if (!egg_buffer_add_uint32 (buffer, n))
Packit b00eeb
		return 0;
Packit b00eeb
Packit b00eeb
	/* Add the individual strings */
Packit b00eeb
	for (v = strv; *v; ++v) {
Packit b00eeb
		if (!egg_buffer_add_string (buffer, *v))
Packit b00eeb
			return 0;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	return 1;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
int
Packit b00eeb
egg_buffer_get_stringv (EggBuffer *buffer, size_t offset, size_t *next_offset,
Packit b00eeb
		                char ***strv_ret, EggBufferAllocator allocator)
Packit b00eeb
{
Packit b00eeb
	uint32_t n, i, j;
Packit b00eeb
	size_t len;
Packit b00eeb
Packit b00eeb
	if (!allocator)
Packit b00eeb
		allocator = buffer->allocator;
Packit b00eeb
	if (!allocator)
Packit b00eeb
		allocator = DEFAULT_ALLOCATOR;
Packit b00eeb
Packit b00eeb
	/* First the number of environment variable lines */
Packit b00eeb
	if (!egg_buffer_get_uint32 (buffer, offset, &offset, &n))
Packit b00eeb
		return 0;
Packit b00eeb
Packit b00eeb
	/* Then that number of strings */
Packit b00eeb
	len = (n + 1) * sizeof (char*);
Packit b00eeb
	*strv_ret = (char**)(allocator) (NULL, len);
Packit b00eeb
	if (!*strv_ret)
Packit b00eeb
		return 0;
Packit b00eeb
Packit b00eeb
	/* All null strings */
Packit b00eeb
	memset (*strv_ret, 0, len);
Packit b00eeb
Packit b00eeb
	for (i = 0; i < n; ++i) {
Packit b00eeb
		if (!egg_buffer_get_string (buffer, offset, &offset,
Packit b00eeb
		                            &((*strv_ret)[i]), allocator)) {
Packit b00eeb
Packit b00eeb
			/* Free all the strings on failure */
Packit b00eeb
			for (j = 0; j < i; ++j) {
Packit b00eeb
				if ((*strv_ret)[j])
Packit b00eeb
					(allocator) ((*strv_ret)[j], 0);
Packit b00eeb
			}
Packit b00eeb
Packit b00eeb
			return 0;
Packit b00eeb
		}
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	if (next_offset != NULL)
Packit b00eeb
		*next_offset = offset;
Packit b00eeb
Packit b00eeb
	return 1;
Packit b00eeb
}