Module Name: src Committed By: agc Date: Sat Aug 7 04:13:57 UTC 2010
Added Files: src/crypto/external/bsd/netpgp/dist/src/libmj: Makefile.am defs.h libmj.3 mj.c mj.h Log Message: Move the minimalist JSON routines into their own library To generate a diff of this commit: cvs rdiff -u -r0 -r1.1 \ src/crypto/external/bsd/netpgp/dist/src/libmj/Makefile.am \ src/crypto/external/bsd/netpgp/dist/src/libmj/defs.h \ src/crypto/external/bsd/netpgp/dist/src/libmj/libmj.3 \ src/crypto/external/bsd/netpgp/dist/src/libmj/mj.c \ src/crypto/external/bsd/netpgp/dist/src/libmj/mj.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Added files: Index: src/crypto/external/bsd/netpgp/dist/src/libmj/Makefile.am diff -u /dev/null src/crypto/external/bsd/netpgp/dist/src/libmj/Makefile.am:1.1 --- /dev/null Sat Aug 7 04:13:57 2010 +++ src/crypto/external/bsd/netpgp/dist/src/libmj/Makefile.am Sat Aug 7 04:13:57 2010 @@ -0,0 +1,14 @@ +## $NetBSD: Makefile.am,v 1.1 2010/08/07 04:13:57 agc Exp $ + +AM_CFLAGS = $(WARNCFLAGS) + +lib_LTLIBRARIES = libmj.la + +libmj_la_CPPFLAGS = -I$(top_srcdir)/include + +libmj_la_SOURCES = \ + mj.c \ + +man3_MANS = mj.3 + +dist_man_MANS = mj.3 Index: src/crypto/external/bsd/netpgp/dist/src/libmj/defs.h diff -u /dev/null src/crypto/external/bsd/netpgp/dist/src/libmj/defs.h:1.1 --- /dev/null Sat Aug 7 04:13:57 2010 +++ src/crypto/external/bsd/netpgp/dist/src/libmj/defs.h Sat Aug 7 04:13:57 2010 @@ -0,0 +1,95 @@ +/* $NetBSD: defs.h,v 1.1 2010/08/07 04:13:57 agc Exp $ */ + +/*- + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Alistair Crooks (a...@netbsd.org) + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifndef DEFS_H_ +#define DEFS_H_ + +#include <sys/types.h> +#include <sys/param.h> + +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> +#endif + +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define NEWARRAY(type,ptr,size,where,action) do { \ + if ((ptr = calloc(sizeof(type), (unsigned)(size))) == NULL) { \ + (void) fprintf(stderr, "%s: can't allocate %lu bytes\n", \ + where, (unsigned long)(size * sizeof(type))); \ + action; \ + } \ +} while( /* CONSTCOND */ 0) + +#define RENEW(type, _ptr, _size, _newsize, where, action) do { \ + type *_newptr; \ + _newptr = realloc(_ptr, (size_t)(_newsize) * sizeof(type)); \ + if (_newptr == NULL) { \ + (void) fprintf(stderr, "%s: can't realloc %lu bytes\n", \ + where, (unsigned long)((_newsize) * sizeof(type))); \ + action; \ + } else { \ + (void) memset(&_newptr[_size], 0x0, \ + (_newsize - _size) * sizeof(type)); \ + _ptr = _newptr; \ + _size = _newsize; \ + } \ +} while( /* CONSTCOND */ 0) + +#define NEW(type, ptr, where, action) NEWARRAY(type, ptr, 1, where, action) + +#define FREE(ptr) free(ptr) + +#define ALLOC(type, v, size, c, init, incr, where, action) do { \ + uint32_t _newsize = size; \ + if (size == 0) { \ + _newsize = init; \ + NEWARRAY(type, v, _newsize, where ": new", action); \ + } else if (c == size) { \ + _newsize = size + incr; \ + RENEW(type, v, size, _newsize, where ": renew", action); \ + } \ + size = _newsize; \ +} while( /* CONSTCOND */ 0) + +#define DEFINE_ARRAY(name, type) \ +typedef struct name { \ + uint32_t c; \ + uint32_t size; \ + type *v; \ +} name + +#endif /* !DEFS_H_ */ Index: src/crypto/external/bsd/netpgp/dist/src/libmj/libmj.3 diff -u /dev/null src/crypto/external/bsd/netpgp/dist/src/libmj/libmj.3:1.1 --- /dev/null Sat Aug 7 04:13:57 2010 +++ src/crypto/external/bsd/netpgp/dist/src/libmj/libmj.3 Sat Aug 7 04:13:57 2010 @@ -0,0 +1,207 @@ +.\" +.\" Copyright (c) 2010 Alistair Crooks <a...@netbsd.org> +.\" 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 AUTHOR ``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 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. +.\" +.Dd August 5, 2010 +.Dt LIBMJ 3 +.Os +.Sh NAME +.Nm libmj +.Nd minimalist JSON lightweight data interchange library +.Sh LIBRARY +.Lb libmj +.Sh SYNOPSIS +.In mj.h +.Ft int +.Fo mj_create +.Fa "mj_t *atom" "const char *text" "..." +.Fc +.Ft int +.Fo mj_parse +.Fa "mj_t *atom" "const char *text" "int *tokfrom" "int *tokto" "int *toktype" +.Fc +.Ft int +.Fo mj_append +.Fa "mj_t *atom" "const char *text" "..." +.Fc +.Ft int +.Fo mj_append_field +.Fa "mj_t *atom" "const char *fieldname" "const char *text" "..." +.Fc +.Ft int +.Fo mj_deepcopy +.Fa "mj_t *dest" "mj_t *src" +.Fc +.Ft void +.Fo mj_delete +.Fa "mj_t *atom" +.Fc +.Pp +Access to objects and array entries is made using the following functions: +.Ft int +.Fo mj_arraycount +.Fa "mj_t *atom" +.Fc +.Ft int +.Fo mj_object_find +.Fa "mj_t *atom" "const char *name" "const unsigned startpoint" +.Fa "const unsigned incr" +.Fc +.Ft mj_t * +.Fo mj_get_atom +.Fa "mj_t *atom" "..." +.Fc +.Pp +JSON object output functions: +.Ft int +.Fo mj_snprint +.Fa "char *buffer" "size_t size" "mj_t *atom" +.Fc +.Ft int +.Fo mj_asprint +.Fa "char **buffer" "mj_t *atom" +.Fc +.Ft int +.Fo mj_string_size +.Fa "mj_t *atom" +.Fc +.Sh DESCRIPTION +.Nm +is a small library interface to allow JSON text to be created and parsed. +JSON is the Java Script Object Notation, +a lightweight data-interchange format, standardised in the ECMA standard. +The library name +.Nm +is derived from a further acronym of +.Dq minimalist JSON . +.\" Hey, Mary! +.Pp +The +.Nm +library can be used to create a string in memory which contains a textutal +representation of a number of objects, arbitrarily structured. +The library can also be used to reconstruct the structure. +Data can thus be serialised easily and efficiently, and data structures +rebuilt to produce the original structure of the data. +.Pp +JSON contains basic units called atoms, the two +basic atoms being strings and numbers. +Three other useful atomic values are provided, +.Dq null , +.Dq false , +and +.Dq true . +Atoms can be grouped together as key/value pairs in an +.Dq object , +and as individual, ordered atoms, in an +.Dq array . +.Pp +To create a new object, the +.Fn mj_create +is used. +It can be deleted using the +.Fn mj_delete +function. +.Pp +Atoms, objects and arrays can be appended +to arrays and objects using the +.Fn mj_append +function. +.Pp +Objects can be printed out +by using the +.Fn mj_snprint +function. +The size of a string of JSON text can be calculated +using the +.Fn mj_string_size +function. +A utility function +.Fn mj_asprint +is provided which will allocate space dynamically, +using +.Xr calloc 3 , +and the JSON serialised text is copied into it. +This memory can later be de-allocated using +.Xr free 3 . +.Pp +The +.Fa type +argument given to the +.Fn mj_create , +.Fn mj_append and +.Fn mj_append_field +functions is taken from a list of +.Dq false +.Dq true +.Dq null +.Dq number +.Dq integer +.Dq string +.Dq array +and +.Dq object +types. +An integer differs from a number in that it cannot take on +any floating point values. +It is implemented internally using a signed 64-bit integer type. +This restriction of values for an integer type may be removed at a later date. +.Pp +Within a JSON object, the key values can be iterated over using an integer +index to access the individual +JSON objects. +The index can also be found using the +.Fn mj_object_index +function, and the object using +the +.Fn mj_object_find +function. +.Pp +The way objects arrays are implemented in +.Nm +is by using varying-sized arrays internally. +Objects have the field name as the even entry in this internal array, +with the value being the odd entry. +Arrays are implemented as a simple array. +Thus, to find an object in an array using +.Fn mj_object_find , +a value of 1 should be used as the +increment value. +This means that every entry in the internal array will be examined, +and the first match after the starting point will be returned. +For objects, an incremental value of 2 should be used, +and an even start value should be specified. +.Sh SEE ALSO +.Xr calloc 3 , +.Xr free 3 +.Rs +.%U http://www.ecma-international.org/publications/files/ecma-st/ECMA-262.pdf +.Re +.Sh HISTORY +The +.Nm +library first appeared in +.Nx 6.0 . +.Sh AUTHOR +.An Alistair Crooks Aq a...@netbsd.org +wrote this implementation and manual page. Index: src/crypto/external/bsd/netpgp/dist/src/libmj/mj.c diff -u /dev/null src/crypto/external/bsd/netpgp/dist/src/libmj/mj.c:1.1 --- /dev/null Sat Aug 7 04:13:57 2010 +++ src/crypto/external/bsd/netpgp/dist/src/libmj/mj.c Sat Aug 7 04:13:57 2010 @@ -0,0 +1,521 @@ +/*- + * Copyright (c) 2010 Alistair Crooks <a...@netbsd.org> + * 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 AUTHOR ``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 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. + */ +#include <sys/types.h> + +#include <inttypes.h> +#include <regex.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "mj.h" +#include "defs.h" + +/* save 'n' chars of 's' in malloc'd memory */ +static char * +strnsave(const char *s, int n, unsigned esc) +{ + char *newc; + char *cp; + int i; + + if (n < 0) { + n = strlen(s); + } + NEWARRAY(char, cp, (n * 2) + 1, "strnsave", return NULL); + if (esc) { + newc = cp; + for (i = 0 ; i < n ; i++) { + if (*s == '\\') { + *newc++ = *s++; + } else if (*s == '"') { + *newc++ = '\\'; + } + *newc++ = *s++; + } + *newc = 0x0; + } else { + (void) memcpy(cp, s, (unsigned)n); + cp[n] = 0x0; + } + return cp; +} + +/* look in an object for the item */ +static int +findentry(mj_t *atom, const char *name, const unsigned from, const unsigned incr) +{ + unsigned i; + + for (i = from ; i < atom->c ; i += incr) { + if (strcmp(name, atom->value.v[i].value.s) == 0) { + return i; + } + } + return -1; +} + +/* create a real number */ +static void +create_number(mj_t *atom, double d) +{ + char number[128]; + + atom->type = MJ_NUMBER; + atom->c = snprintf(number, sizeof(number), "%g", d); + atom->value.s = strnsave(number, (int)atom->c, 0); +} + +/* create an integer */ +static void +create_integer(mj_t *atom, int64_t i) +{ + char number[128]; + + atom->type = MJ_NUMBER; + atom->c = snprintf(number, sizeof(number), "%" PRIi64, i); + atom->value.s = strnsave(number, (int)atom->c, 0); +} + +/* create a string */ +static void +create_string(mj_t *atom, const char *s) +{ + atom->type = MJ_STRING; + atom->value.s = strnsave(s, -1, 1); + atom->c = strlen(atom->value.s); +} + +#define MJ_OPEN_BRACKET (MJ_OBJECT + 1) /* 8 */ +#define MJ_CLOSE_BRACKET (MJ_OPEN_BRACKET + 1) /* 9 */ +#define MJ_OPEN_BRACE (MJ_CLOSE_BRACKET + 1) /* 10 */ +#define MJ_CLOSE_BRACE (MJ_OPEN_BRACE + 1) /* 11 */ +#define MJ_COLON (MJ_CLOSE_BRACE + 1) /* 12 */ +#define MJ_COMMA (MJ_COLON + 1) /* 13 */ + +/* return the token type, and start and finish locations in string */ +static int +gettok(const char *s, int *from, int *to, int *tok) +{ + static regex_t tokregex; + regmatch_t matches[15]; + static int compiled; + + if (!compiled) { + compiled = 1; + (void) regcomp(&tokregex, + "[ \t\r\n]*(([+-]?[0-9]{1,21}(\\.[0-9]*)?([eE][-+][0-9]+)?)|" + "(\"([^\"]|\\\\.)*\")|(null)|(false)|(true)|([][{}:,]))", + REG_EXTENDED); + } + if (regexec(&tokregex, &s[*from = *to], 15, matches, 0) != 0) { + return *tok = -1; + } + *to = *from + (int)(matches[1].rm_eo); + *tok = (matches[2].rm_so >= 0) ? MJ_NUMBER : + (matches[5].rm_so >= 0) ? MJ_STRING : + (matches[7].rm_so >= 0) ? MJ_NULL : + (matches[8].rm_so >= 0) ? MJ_FALSE : + (matches[9].rm_so >= 0) ? MJ_TRUE : + (matches[10].rm_so < 0) ? -1 : + (s[*from + (int)(matches[10].rm_so)] == '[') ? MJ_OPEN_BRACKET : + (s[*from + (int)(matches[10].rm_so)] == ']') ? MJ_CLOSE_BRACKET : + (s[*from + (int)(matches[10].rm_so)] == '{') ? MJ_OPEN_BRACE : + (s[*from + (int)(matches[10].rm_so)] == '}') ? MJ_CLOSE_BRACE : + (s[*from + (int)(matches[10].rm_so)] == ':') ? MJ_COLON : + MJ_COMMA; + *from += (int)(matches[1].rm_so); + return *tok; +} + +/***************************************************************************/ + +/* return the number of entries in the array */ +int +mj_arraycount(mj_t *atom) +{ + return atom->c; +} + +/* create a new JSON node */ +int +mj_create(mj_t *atom, const char *type, ...) +{ + va_list args; + + if (strcmp(type, "false") == 0) { + atom->type = MJ_FALSE; + atom->c = 0; + } else if (strcmp(type, "true") == 0) { + atom->type = MJ_TRUE; + atom->c = 1; + } else if (strcmp(type, "null") == 0) { + atom->type = MJ_NULL; + } else if (strcmp(type, "number") == 0) { + va_start(args, type); + create_number(atom, (double)va_arg(args, double)); + va_end(args); + } else if (strcmp(type, "integer") == 0) { + va_start(args, type); + create_integer(atom, (int64_t)va_arg(args, int64_t)); + va_end(args); + } else if (strcmp(type, "string") == 0) { + va_start(args, type); + create_string(atom, (char *)va_arg(args, char *)); + va_end(args); + } else if (strcmp(type, "array") == 0) { + atom->type = MJ_ARRAY; + } else if (strcmp(type, "object") == 0) { + atom->type = MJ_OBJECT; + } else { + (void) fprintf(stderr, "weird type '%s'\n", type); + return 0; + } + return 1; +} + +/* put a JSON tree into a text string */ +int +mj_snprint(char *buf, size_t size, mj_t *atom) +{ + unsigned i; + int cc; + + switch(atom->type) { + case MJ_NULL: + return snprintf(buf, size, "null"); + case MJ_FALSE: + return snprintf(buf, size, "false"); + case MJ_TRUE: + return snprintf(buf, size, "true"); + case MJ_NUMBER: + return snprintf(buf, size, "%s", atom->value.s); + case MJ_STRING: + return snprintf(buf, size, "\"%s\"", atom->value.s); + case MJ_ARRAY: + cc = snprintf(buf, size, "[ "); + for (i = 0 ; i < atom->c ; i++) { + cc += mj_snprint(&buf[cc], size - cc, &atom->value.v[i]); + if (i < atom->c - 1) { + cc += snprintf(&buf[cc], size - cc, ", "); + } + } + return cc + snprintf(&buf[cc], size - cc, "]\n"); + case MJ_OBJECT: + cc = snprintf(buf, size, "{ "); + for (i = 0 ; i < atom->c ; i += 2) { + cc += mj_snprint(&buf[cc], size - cc, &atom->value.v[i]); + cc += snprintf(&buf[cc], size - cc, ":"); + cc += mj_snprint(&buf[cc], size - cc, &atom->value.v[i + 1]); + if (i + 1 < atom->c - 1) { + cc += snprintf(&buf[cc], size - cc, ", "); + } + } + return cc + snprintf(&buf[cc], size - cc, "}\n"); + default: + (void) fprintf(stderr, "mj_snprint: weird type %d\n", atom->type); + return 0; + } +} + +/* allocate and print the atom */ +int +mj_asprint(char **buf, mj_t *atom) +{ + int size; + + size = mj_string_size(atom); + if ((*buf = calloc(1, (unsigned)(size + 1))) == NULL) { + return -1; + } + (void) mj_snprint(*buf, (unsigned)(size + 1), atom); + return size + 1; +} + +/* read into a JSON tree from a string */ +int +mj_parse(mj_t *atom, const char *s, int *from, int *to, int *tok) +{ + int i; + + switch(atom->type = *tok = gettok(s, from, to, tok)) { + case MJ_NUMBER: + atom->value.s = strnsave(&s[*from], *to - *from, 1); + atom->c = atom->size = strlen(atom->value.s); + return gettok(s, from, to, tok); + case MJ_STRING: + atom->value.s = strnsave(&s[*from + 1], *to - *from - 2, 1); + atom->c = atom->size = strlen(atom->value.s); + return gettok(s, from, to, tok); + case MJ_NULL: + case MJ_FALSE: + case MJ_TRUE: + atom->c = (unsigned)to; + return gettok(s, from, to, tok); + case MJ_OPEN_BRACKET: + mj_create(atom, "array"); + ALLOC(mj_t, atom->value.v, atom->size, atom->c, 10, 10, "mj_parse()", return 0); + while (mj_parse(&atom->value.v[atom->c++], s, from, to, tok) >= 0 && *tok != MJ_CLOSE_BRACKET) { + if (*tok != MJ_COMMA) { + (void) fprintf(stderr, "1. expected comma (got %d) at '%s'\n", *tok, &s[*from]); + break; + } + ALLOC(mj_t, atom->value.v, atom->size, atom->c, 10, 10, "mj_parse()", return 0); + } + return gettok(s, from, to, tok); + case MJ_OPEN_BRACE: + mj_create(atom, "object"); + ALLOC(mj_t, atom->value.v, atom->size, atom->c, 10, 10, "mj_parse()", return 0); + for (i = 0 ; mj_parse(&atom->value.v[atom->c++], s, from, to, tok) >= 0 && *tok != MJ_CLOSE_BRACE ; i++) { + if (((i % 2) == 0 && *tok != MJ_COLON) || ((i % 2) == 1 && *tok != MJ_COMMA)) { + (void) fprintf(stderr, "2. expected comma (got %d) at '%s'\n", *tok, &s[*from]); + break; + } + ALLOC(mj_t, atom->value.v, atom->size, atom->c, 10, 10, "mj_parse()", return 0); + } + return gettok(s, from, to, tok); + default: + return *tok; + } +} + +/* return the index of the item which corresponds to the name in the array */ +int +mj_object_find(mj_t *atom, const char *name, const unsigned from, const unsigned incr) +{ + return findentry(atom, name, from, incr); +} + +/* find an atom in a composite mj JSON node */ +mj_t * +mj_get_atom(mj_t *atom, ...) +{ + unsigned i; + va_list args; + char *name; + int n; + + switch(atom->type) { + case MJ_ARRAY: + va_start(args, atom); + i = va_arg(args, int); + va_end(args); + return (i < atom->c) ? &atom->value.v[i] : NULL; + case MJ_OBJECT: + va_start(args, atom); + name = va_arg(args, char *); + va_end(args); + return ((n = findentry(atom, name, 0, 2)) >= 0) ? &atom->value.v[n + 1] : NULL; + default: + return NULL; + } +} + +/* perform a deep copy on an mj JSON atom */ +int +mj_deepcopy(mj_t *dst, mj_t *src) +{ + unsigned i; + + switch(src->type) { + case MJ_FALSE: + case MJ_TRUE: + case MJ_NULL: + (void) memcpy(dst, src, sizeof(*dst)); + return 1; + case MJ_STRING: + case MJ_NUMBER: + (void) memcpy(dst, src, sizeof(*dst)); + dst->value.s = strnsave(src->value.s, -1, 0); + dst->c = dst->size = strlen(dst->value.s); + return 1; + case MJ_ARRAY: + case MJ_OBJECT: + (void) memcpy(dst, src, sizeof(*dst)); + NEWARRAY(mj_t, dst->value.v, dst->size, "mj_deepcopy()", return 0); + for (i = 0 ; i < src->c ; i++) { + if (!mj_deepcopy(&dst->value.v[i], &src->value.v[i])) { + return 0; + } + } + return 1; + default: + (void) fprintf(stderr, "weird type '%d'\n", src->type); + return 0; + } +} + +/* do a deep delete on the object */ +void +mj_delete(mj_t *atom) +{ + unsigned i; + + switch(atom->type) { + case MJ_STRING: + case MJ_NUMBER: + free(atom->value.s); + break; + case MJ_ARRAY: + case MJ_OBJECT: + for (i = 0 ; i < atom->c ; i++) { + mj_delete(&atom->value.v[i]); + } + break; + default: + break; + } +} + +/* return the string size needed for the textual output of the JSON node */ +int +mj_string_size(mj_t *atom) +{ + unsigned i; + int cc; + + switch(atom->type) { + case MJ_NULL: + case MJ_TRUE: + return 4; + case MJ_FALSE: + return 5; + case MJ_NUMBER: + return atom->c; + case MJ_STRING: + return atom->c + 2; + case MJ_ARRAY: + for (cc = 2, i = 0 ; i < atom->c ; i++) { + cc += mj_string_size(&atom->value.v[i]); + if (i < atom->c - 1) { + cc += 2; + } + } + return cc + 1 + 1; + case MJ_OBJECT: + for (cc = 2, i = 0 ; i < atom->c ; i += 2) { + cc += mj_string_size(&atom->value.v[i]) + 1 + mj_string_size(&atom->value.v[i + 1]); + if (i + 1 < atom->c - 1) { + cc += 2; + } + } + return cc + 1 + 1; + default: + (void) fprintf(stderr, "mj_string_size: weird type %d\n", atom->type); + return 0; + } +} + +/* create a new atom, and append it to the array or object */ +int +mj_append(mj_t *atom, const char *type, ...) +{ + va_list args; + + if (atom->type != MJ_ARRAY && atom->type != MJ_OBJECT) { + return 0; + } + ALLOC(mj_t, atom->value.v, atom->size, atom->c, 10, 10, "mj_append()", return 0); + va_start(args, type); + if (strcmp(type, "string") == 0) { + create_string(&atom->value.v[atom->c++], (char *)va_arg(args, char *)); + } else if (strcmp(type, "integer") == 0) { + create_integer(&atom->value.v[atom->c++], (int64_t)va_arg(args, int64_t)); + } else if (strcmp(type, "object") == 0 || strcmp(type, "array") == 0) { + mj_deepcopy(&atom->value.v[atom->c++], (mj_t *)va_arg(args, mj_t *)); + } else { + (void) fprintf(stderr, "mj_append: weird type '%s'\n", type); + } + va_end(args); + return 1; +} + +/* append a field to an object */ +int +mj_append_field(mj_t *atom, const char *name, const char *type, ...) +{ + va_list args; + + if (atom->type != MJ_OBJECT) { + return 0; + } + mj_append(atom, "string", name); + ALLOC(mj_t, atom->value.v, atom->size, atom->c, 10, 10, "mj_append_field()", return 0); + va_start(args, type); + if (strcmp(type, "string") == 0) { + create_string(&atom->value.v[atom->c++], (char *)va_arg(args, char *)); + } else if (strcmp(type, "integer") == 0) { + create_integer(&atom->value.v[atom->c++], (int64_t)va_arg(args, int64_t)); + } else if (strcmp(type, "object") == 0 || strcmp(type, "array") == 0) { + mj_deepcopy(&atom->value.v[atom->c++], (mj_t *)va_arg(args, mj_t *)); + } else { + (void) fprintf(stderr, "mj_append_field: weird type '%s'\n", type); + } + va_end(args); + return 1; +} + +int +mj_lint(mj_t *obj) +{ + unsigned i; + int ret; + + switch(obj->type) { + case MJ_NULL: + case MJ_FALSE: + case MJ_TRUE: + if (obj->value.s != NULL) { + (void) fprintf(stderr, "null/false/true: non zero string\n"); + return 0; + } + return 1; + case MJ_NUMBER: + case MJ_STRING: + if (obj->c > obj->size) { + (void) fprintf(stderr, "string/number lint c (%u) > size (%u)\n", obj->c, obj->size); + return 0; + } + return 1; + case MJ_ARRAY: + case MJ_OBJECT: + if (obj->c > obj->size) { + (void) fprintf(stderr, "array/object lint c (%u) > size (%u)\n", obj->c, obj->size); + return 0; + } + for (ret = 1, i = 0 ; i < obj->c ; i++) { + if (!mj_lint(&obj->value.v[i])) { + (void) fprintf(stderr, "array/object lint found at %d of %p\n", i, obj); + ret = 0; + } + } + return ret; + default: + (void) fprintf(stderr, "problem type %d in %p\n", obj->type, obj); + return 0; + } +} Index: src/crypto/external/bsd/netpgp/dist/src/libmj/mj.h diff -u /dev/null src/crypto/external/bsd/netpgp/dist/src/libmj/mj.h:1.1 --- /dev/null Sat Aug 7 04:13:57 2010 +++ src/crypto/external/bsd/netpgp/dist/src/libmj/mj.h Sat Aug 7 04:13:57 2010 @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2010 Alistair Crooks <a...@netbsd.org> + * 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 AUTHOR ``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 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. + */ +#ifndef MJ_H_ +#define MJ_H_ 20100718 + +enum { + MJ_NULL = 1, + MJ_FALSE = 2, + MJ_TRUE = 3, + MJ_NUMBER = 4, + MJ_STRING = 5, + MJ_ARRAY = 6, + MJ_OBJECT = 7 +}; + +/* a minimalist JSON node */ +typedef struct mj_t { + unsigned type; /* type of JSON node */ + unsigned c; /* # of chars */ + unsigned size; /* size of array */ + union { + struct mj_t *v; /* sub-objects */ + char *s; /* string value */ + } value; +} mj_t; + +/* creation and deletion */ +int mj_create(mj_t *, const char *, ...); +int mj_parse(mj_t *, const char *, int *, int *, int *); +int mj_append(mj_t *, const char *, ...); +int mj_append_field(mj_t *, const char *, const char *, ...); +int mj_deepcopy(mj_t *, mj_t *); +void mj_delete(mj_t *); + +/* JSON object access */ +int mj_arraycount(mj_t *); +int mj_object_find(mj_t *, const char *, const unsigned, const unsigned); +mj_t *mj_get_atom(mj_t *, ...); +int mj_lint(mj_t *); + +/* textual output */ +int mj_snprint(char *, size_t, mj_t *); +int mj_asprint(char **, mj_t *); +int mj_string_size(mj_t *); + +#endif