File:
[ELWIX - Embedded LightWeight unIX -] /
embedaddon /
mpd /
src /
contrib /
libpdel /
structs /
type /
structs_type_array.c
Revision
1.1.1.1 (vendor branch):
download - view:
text,
annotated -
select for diffs -
revision graph
Mon Jul 22 08:44:30 2013 UTC (11 years, 1 month ago) by
misho
Branches:
mpd,
MAIN
CVS tags:
v5_9p16,
v5_9,
v5_8p7,
v5_8p1_cross,
v5_8p1,
v5_8,
v5_7p0,
v5_7,
v5_6,
HEAD
5.7
/*
* Copyright (c) 2001-2002 Packet Design, LLC.
* All rights reserved.
*
* Subject to the following obligations and disclaimer of warranty,
* use and redistribution of this software, in source or object code
* forms, with or without modifications are expressly permitted by
* Packet Design; provided, however, that:
*
* (i) Any and all reproductions of the source or object code
* must include the copyright notice above and the following
* disclaimer of warranties; and
* (ii) No rights are granted, in any manner or form, to use
* Packet Design trademarks, including the mark "PACKET DESIGN"
* on advertising, endorsements, or otherwise except as such
* appears in the above copyright notice or in the software.
*
* THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
* THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
* OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
* OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
* OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
* RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
* LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
* OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
* DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
* USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 PACKET DESIGN IS ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
* Author: Archie Cobbs <archie@freebsd.org>
*/
#include <sys/types.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include "structs/structs.h"
#include "structs/type/array.h"
#include "util/typed_mem.h"
#define NUM_BYTES(x) (((x) + 7) / 8)
/*********************************************************************
ARRAY TYPES
*********************************************************************/
int
structs_array_copy(const struct structs_type *type,
const void *from, void *to)
{
const struct structs_type *const etype = type->args[0].v;
const char *mtype = type->args[1].v;
const struct structs_array *const fary = from;
struct structs_array *const tary = to;
int errno_save;
u_int i;
/* Make sure it's really an array type */
if (type->tclass != STRUCTS_TYPE_ARRAY) {
errno = EINVAL;
return (-1);
}
/* Allocate a new array */
memset(tary, 0, sizeof(*tary));
if ((tary->elems = MALLOC(mtype,
fary->length * etype->size)) == NULL)
return (-1);
/* Copy elements into it */
for (i = 0; i < fary->length; i++) {
const void *const from_elem
= (char *)fary->elems + (i * etype->size);
void *const to_elem = (char *)tary->elems + (i * etype->size);
if ((*etype->copy)(etype, from_elem, to_elem) == -1)
break;
tary->length++;
}
/* If there was a failure, undo the half completed job */
if (i < fary->length) {
errno_save = errno;
while (i-- > 0) {
(*etype->uninit)(etype,
(char *)tary->elems + (i * etype->size));
}
FREE(mtype, tary->elems);
memset(tary, 0, sizeof(*tary));
errno = errno_save;
return (-1);
}
/* Done */
return (0);
}
int
structs_array_equal(const struct structs_type *type,
const void *v1, const void *v2)
{
const struct structs_type *const etype = type->args[0].v;
const struct structs_array *const ary1 = v1;
const struct structs_array *const ary2 = v2;
u_int i;
/* Make sure it's really an array type */
if (type->tclass != STRUCTS_TYPE_ARRAY)
return (0);
/* Check array lengths first */
if (ary1->length != ary2->length)
return (0);
/* Now compare individual elements */
for (i = 0;
i < ary1->length && (*etype->equal)(etype,
(char *)ary1->elems + (i * etype->size),
(char *)ary2->elems + (i * etype->size));
i++);
return (i == ary1->length);
}
int
structs_array_encode(const struct structs_type *type, const char *mtype,
struct structs_data *code, const void *data)
{
const struct structs_type *const etype = type->args[0].v;
const struct structs_array *const ary = data;
const u_int bitslen = NUM_BYTES(ary->length);
struct structs_data *ecodes;
u_int32_t elength;
u_char *bits;
void *delem;
u_int tlen;
int r = -1;
u_int i;
/* Make sure it's really an array type */
if (type->tclass != STRUCTS_TYPE_ARRAY) {
errno = EINVAL;
return (-1);
}
/* Get the default value for an element */
if ((delem = MALLOC(TYPED_MEM_TEMP, etype->size)) == NULL)
return (-1);
if (structs_init(etype, NULL, delem) == -1)
goto fail1;
/* Create bit array. Each bit indicates an element that is present. */
if ((bits = MALLOC(TYPED_MEM_TEMP, bitslen)) == NULL)
goto fail2;
memset(bits, 0, bitslen);
tlen = 4 + bitslen; /* length word + bits array */
/* Create array of individual encodings, one per element */
if ((ecodes = MALLOC(TYPED_MEM_TEMP,
ary->length * sizeof(*ecodes))) == NULL)
goto fail3;
for (i = 0; i < ary->length; i++) {
const void *const elem = (char *)ary->elems + (i * etype->size);
struct structs_data *const ecode = &ecodes[i];
/* Check for default value, leave out if same as */
if ((*etype->equal)(etype, elem, delem) == 1) {
memset(ecode, 0, sizeof(*ecode));
continue;
}
bits[i / 8] |= (1 << (i % 8));
/* Encode element */
if ((*etype->encode)(etype, TYPED_MEM_TEMP, ecode, elem) == -1)
goto fail4;
tlen += ecode->length;
}
/* Allocate final encoded region */
if ((code->data = MALLOC(mtype, tlen)) == NULL)
goto fail4;
/* Copy array length */
elength = htonl(ary->length);
memcpy(code->data, &elength, 4);
code->length = 4;
/* Copy bits array */
memcpy(code->data + code->length, bits, bitslen);
code->length += bitslen;
/* Copy encoded elements */
for (i = 0; i < ary->length; i++) {
struct structs_data *const ecode = &ecodes[i];
memcpy(code->data + code->length, ecode->data, ecode->length);
code->length += ecode->length;
}
/* OK */
r = 0;
/* Clean up and exit */
fail4: while (i-- > 0)
FREE(TYPED_MEM_TEMP, ecodes[i].data);
FREE(TYPED_MEM_TEMP, ecodes);
fail3: FREE(TYPED_MEM_TEMP, bits);
fail2: structs_free(etype, NULL, delem);
fail1: FREE(TYPED_MEM_TEMP, delem);
return (r);
}
int
structs_array_decode(const struct structs_type *type, const u_char *code,
size_t cmax, void *data, char *ebuf, size_t emax)
{
const struct structs_type *const etype = type->args[0].v;
const char *const mtype = type->args[1].v;
struct structs_array *const ary = data;
const u_char *bits;
u_int32_t elength;
u_int bitslen;
int clen;
u_int i;
/* Make sure it's really an array type */
if (type->tclass != STRUCTS_TYPE_ARRAY) {
errno = EINVAL;
return (-1);
}
/* Get number of elements */
if (cmax < 4)
goto truncated;
memcpy(&elength, code, 4);
ary->length = ntohl(elength);
code += 4;
cmax -= 4;
clen = 4;
/* Get bits array */
bitslen = NUM_BYTES(ary->length);
if (cmax < bitslen) {
truncated: strlcpy(ebuf, "encoded array is truncated", emax);
errno = EINVAL;
return (-1);
}
bits = code;
code += bitslen;
cmax -= bitslen;
clen += bitslen;
/* Allocate array elements */
if ((ary->elems = MALLOC(mtype, ary->length * etype->size)) == NULL)
return (-1);
/* Decode elements */
for (i = 0; i < ary->length; i++) {
void *const edata = (char *)ary->elems + (i * etype->size);
int eclen;
/* If element not present, assign it the default value */
if ((bits[i / 8] & (1 << (i % 8))) == 0) {
if (structs_init(etype, NULL, edata) == -1)
goto fail;
continue;
}
/* Decode element */
if ((eclen = (*etype->decode)(etype,
code, cmax, edata, ebuf, emax)) == -1)
goto fail;
/* Go to next encoded element */
code += eclen;
cmax -= eclen;
clen += eclen;
continue;
/* Un-do work done so far */
fail: while (i-- > 0) {
structs_free(etype, NULL,
(char *)ary->elems + (i * etype->size));
}
FREE(mtype, ary->elems);
return (-1);
}
/* Done */
return (clen);
}
void
structs_array_free(const struct structs_type *type, void *data)
{
const struct structs_type *const etype = type->args[0].v;
const char *mtype = type->args[1].v;
struct structs_array *const ary = data;
u_int i;
/* Make sure it's really an array type */
if (type->tclass != STRUCTS_TYPE_ARRAY)
return;
/* Free individual elements */
for (i = 0; i < ary->length; i++)
(*etype->uninit)(etype, (char *)ary->elems + (i * etype->size));
/* Free array itself */
FREE(mtype, ary->elems);
memset(ary, 0, sizeof(*ary));
}
int
structs_array_length(const struct structs_type *type,
const char *name, const void *data)
{
const struct structs_array *ary = data;
/* Find array */
if ((type = structs_find(type, name, (void **)&ary, 0)) == NULL)
return (-1);
/* Make sure it's really an array type */
if (type->tclass != STRUCTS_TYPE_ARRAY) {
errno = EINVAL;
return (-1);
}
/* Return length */
return (ary->length);
}
int
structs_array_reset(const struct structs_type *type,
const char *name, void *data)
{
/* Find array */
if ((type = structs_find(type, name, &data, 1)) == NULL)
return (-1);
/* Make sure it's really an array type */
if (type->tclass != STRUCTS_TYPE_ARRAY) {
errno = EINVAL;
return (-1);
}
/* Free it, which resets it as well */
structs_array_free(type, data);
return (0);
}
int
structs_array_insert(const struct structs_type *type,
const char *name, u_int index, void *data)
{
struct structs_array *ary = data;
const struct structs_type *etype;
const char *mtype;
void *mem;
/* Find array */
if ((type = structs_find(type, name, (void **)&ary, 0)) == NULL)
return (-1);
etype = type->args[0].v;
mtype = type->args[1].v;
/* Make sure it's really an array type */
if (type->tclass != STRUCTS_TYPE_ARRAY) {
errno = EINVAL;
return (-1);
}
/* Check index */
if (index > ary->length) {
errno = EDOM;
return (-1);
}
/* Reallocate array, leaving room for new element and a shift */
if ((mem = REALLOC(mtype,
ary->elems, (ary->length + 2) * etype->size)) == NULL)
return (-1);
ary->elems = mem;
/* Initialize new element; we'll move it into place later */
if ((*etype->init)(etype,
(char *)ary->elems + (ary->length + 1) * etype->size) == -1)
return (-1);
/* Shift array over by one and move new element into place */
memmove((char *)ary->elems + (index + 1) * etype->size,
(char *)ary->elems + index * etype->size,
(ary->length - index) * etype->size);
memcpy((char *)ary->elems + index * etype->size,
(char *)ary->elems + (ary->length + 1) * etype->size, etype->size);
ary->length++;
return (0);
}
int
structs_array_delete(const struct structs_type *type,
const char *name, u_int index, void *data)
{
const struct structs_type *etype;
struct structs_array *ary = data;
/* Find array */
if ((type = structs_find(type, name, (void **)&ary, 0)) == NULL)
return (-1);
etype = type->args[0].v;
/* Make sure it's really an array type */
if (type->tclass != STRUCTS_TYPE_ARRAY) {
errno = EINVAL;
return (-1);
}
/* Check index */
if (index >= ary->length) {
errno = EDOM;
return (-1);
}
/* Free element */
(*etype->uninit)(etype, (char *)ary->elems + (index * etype->size));
/* Shift array */
memmove((char *)ary->elems + index * etype->size,
(char *)ary->elems + (index + 1) * etype->size,
(--ary->length - index) * etype->size);
return (0);
}
/*
* Given a name, prepare all arrays in the name path for being
* set with a new element.
*
* This means that any array index equal to the length of the array
* causes a new element to be appended to the array rather than
* an element not found error, and that any array index equal to
* zero means to reset the entire array to be empty.
*
* This allows an entire array to be set by setting each element
* in order, as long as this function is called with the name of
* the element before each set operation.
*/
int
structs_array_prep(const struct structs_type *type,
const char *name, void *data)
{
char *nbuf;
char *s;
/* Skip if name cannot be an array element name */
if (name == NULL || *name == '\0')
return (0);
/* Copy name into writable buffer */
if ((nbuf = MALLOC(TYPED_MEM_TEMP, strlen(name) + 2)) == NULL)
return (-1);
nbuf[0] = '*'; /* for debugging */
strcpy(nbuf + 1, name);
/* Check all array element names in name path */
for (s = nbuf; s != NULL; s = strchr(s + 1, STRUCTS_SEPARATOR)) {
const struct structs_type *atype;
struct structs_array *ary = data;
u_long index;
char *eptr;
char *t;
char ch;
/* Go to next descendant node using prefix of name */
ch = *s;
*s = '\0';
if ((atype = structs_find(type,
nbuf + (s != nbuf), (void **)&ary, 1)) == NULL) {
FREE(TYPED_MEM_TEMP, nbuf);
return (-1);
}
*s = ch;
/* If not array type, continue */
if (atype->tclass != STRUCTS_TYPE_ARRAY)
continue;
/* Get array index */
if ((t = strchr(s + 1, STRUCTS_SEPARATOR)) != NULL)
*t = '\0';
index = strtoul(s + 1, &eptr, 10);
if (eptr == s + 1 || *eptr != '\0') {
errno = ENOENT;
FREE(TYPED_MEM_TEMP, nbuf);
return (-1);
}
/* If setting an element that already exists, accept */
if (index < ary->length)
goto next;
/* Must be setting the next new item in the array */
if (index != ary->length) {
errno = ENOENT;
FREE(TYPED_MEM_TEMP, nbuf);
return (-1);
}
/* Add new item; it will be in an initialized state */
if (structs_array_insert(atype, NULL, ary->length, ary) == -1) {
FREE(TYPED_MEM_TEMP, nbuf);
return (-1);
}
next:
/* Repair name buffer for next time */
if (t != NULL)
*t = STRUCTS_SEPARATOR;
}
/* Done */
FREE(TYPED_MEM_TEMP, nbuf);
return (0);
}
/*********************************************************************
FIXEDARRAY TYPES
*********************************************************************/
int
structs_fixedarray_init(const struct structs_type *type, void *data)
{
const struct structs_type *const etype = type->args[0].v;
const u_int length = type->args[2].i;
u_int i;
for (i = 0; i < length; i++) {
if ((*etype->init)(etype,
(char *)data + (i * etype->size)) == -1) {
while (i-- > 0) {
(*etype->uninit)(etype,
(char *)data + (i * etype->size));
}
return (-1);
}
}
return (0);
}
int
structs_fixedarray_copy(const struct structs_type *type,
const void *from, void *to)
{
const struct structs_type *const etype = type->args[0].v;
const u_int length = type->args[2].i;
u_int i;
/* Make sure it's really a fixedarray type */
if (type->tclass != STRUCTS_TYPE_FIXEDARRAY) {
errno = EINVAL;
return (-1);
}
/* Copy elements into it */
for (i = 0; i < length; i++) {
const void *const from_elem = (char *)from + (i * etype->size);
void *const to_elem = (char *)to + (i * etype->size);
if ((*etype->copy)(etype, from_elem, to_elem) == -1)
break;
}
/* If there was a failure, undo the half completed job */
if (i < length) {
while (i-- > 0)
(*etype->uninit)(etype, (char *)to + (i * etype->size));
return (-1);
}
/* Done */
return (0);
}
int
structs_fixedarray_equal(const struct structs_type *type,
const void *v1, const void *v2)
{
const struct structs_type *const etype = type->args[0].v;
const u_int length = type->args[2].i;
u_int i;
/* Make sure it's really a fixedarray type */
if (type->tclass != STRUCTS_TYPE_FIXEDARRAY)
return (0);
/* Compare individual elements */
for (i = 0;
i < length && (*etype->equal)(etype,
(char *)v1 + (i * etype->size), (char *)v2 + (i * etype->size));
i++);
return (i == length);
}
int
structs_fixedarray_encode(const struct structs_type *type, const char *mtype,
struct structs_data *code, const void *data)
{
const struct structs_type *const etype = type->args[0].v;
const u_int length = type->args[2].i;
const u_int bitslen = NUM_BYTES(length);
struct structs_data *ecodes;
u_char *bits;
void *delem;
u_int tlen;
int r = -1;
u_int i;
/* Make sure it's really a fixedarray type */
if (type->tclass != STRUCTS_TYPE_FIXEDARRAY) {
errno = EINVAL;
return (-1);
}
/* Get the default value for an element */
if ((delem = MALLOC(TYPED_MEM_TEMP, etype->size)) == NULL)
return (-1);
if (structs_init(etype, NULL, delem) == -1)
goto fail1;
/* Create bit array. Each bit indicates an element that is present. */
if ((bits = MALLOC(TYPED_MEM_TEMP, bitslen)) == NULL)
goto fail2;
memset(bits, 0, bitslen);
tlen = bitslen;
/* Create array of individual encodings, one per element */
if ((ecodes = MALLOC(TYPED_MEM_TEMP, length * sizeof(*ecodes))) == NULL)
goto fail3;
for (i = 0; i < length; i++) {
const void *const elem = (char *)data + (i * etype->size);
struct structs_data *const ecode = &ecodes[i];
/* Check for default value, leave out if same as */
if ((*etype->equal)(etype, elem, delem) == 1) {
memset(ecode, 0, sizeof(*ecode));
continue;
}
bits[i / 8] |= (1 << (i % 8));
/* Encode element */
if ((*etype->encode)(etype, TYPED_MEM_TEMP, ecode, elem) == -1)
goto fail4;
tlen += ecode->length;
}
/* Allocate final encoded region */
if ((code->data = MALLOC(mtype, tlen)) == NULL)
goto fail4;
/* Copy bits array */
memcpy(code->data, bits, bitslen);
code->length = bitslen;
/* Copy encoded elements */
for (i = 0; i < length; i++) {
struct structs_data *const ecode = &ecodes[i];
memcpy(code->data + code->length, ecode->data, ecode->length);
code->length += ecode->length;
}
/* OK */
r = 0;
/* Clean up and exit */
fail4: while (i-- > 0)
FREE(TYPED_MEM_TEMP, ecodes[i].data);
FREE(TYPED_MEM_TEMP, ecodes);
fail3: FREE(TYPED_MEM_TEMP, bits);
fail2: structs_free(etype, NULL, delem);
fail1: FREE(TYPED_MEM_TEMP, delem);
return (r);
}
int
structs_fixedarray_decode(const struct structs_type *type, const u_char *code,
size_t cmax, void *data, char *ebuf, size_t emax)
{
const struct structs_type *const etype = type->args[0].v;
const u_int length = type->args[2].i;
const u_int bitslen = NUM_BYTES(length);
const u_char *bits;
int clen = 0;
u_int i;
/* Make sure it's really a fixedarray type */
if (type->tclass != STRUCTS_TYPE_FIXEDARRAY) {
errno = EINVAL;
return (-1);
}
/* Get bits array */
if (cmax < bitslen) {
strlcpy(ebuf, "encoded array is truncated", emax);
errno = EINVAL;
return (-1);
}
bits = code;
code += bitslen;
cmax -= bitslen;
clen += bitslen;
/* Decode elements */
for (i = 0; i < length; i++) {
void *const edata = (char *)data + (i * etype->size);
int eclen;
/* If element not present, assign it the default value */
if ((bits[i / 8] & (1 << (i % 8))) == 0) {
if (structs_init(etype, NULL, edata) == -1)
goto fail;
continue;
}
/* Decode element */
if ((eclen = (*etype->decode)(etype,
code, cmax, edata, ebuf, emax)) == -1)
goto fail;
/* Go to next encoded element */
code += eclen;
cmax -= eclen;
clen += eclen;
continue;
/* Un-do work done so far */
fail: while (i-- > 0) {
structs_free(etype, NULL,
(char *)data + (i * etype->size));
}
return (-1);
}
/* Done */
return (clen);
}
void
structs_fixedarray_free(const struct structs_type *type, void *data)
{
const struct structs_type *const etype = type->args[0].v;
const u_int length = type->args[2].i;
u_int i;
/* Make sure it's really a fixedarray type */
if (type->tclass != STRUCTS_TYPE_FIXEDARRAY)
return;
/* Free elements */
for (i = 0; i < length; i++)
(*etype->uninit)(etype, (char *)data + (i * etype->size));
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>