Blame egg/egg-buffer.c

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