Index: common/include/prop/Makefile
===================================================================
RCS file: /cvsroot/src/common/include/prop/Makefile,v
retrieving revision 1.2
diff -d -p -u -r1.2 Makefile
--- common/include/prop/Makefile 21 Aug 2006 04:13:28 -0000 1.2
+++ common/include/prop/Makefile 7 Jun 2007 13:26:36 -0000
@@ -1,6 +1,6 @@
# $NetBSD: Makefile,v 1.2 2006/08/21 04:13:28 thorpej Exp $
-INCS= prop_array.h prop_bool.h prop_data.h prop_dictionary.h \
+INCS= prop_array.h prop_bool.h prop_codec.h prop_data.h prop_dictionary.h \
prop_ingest.h prop_number.h prop_object.h prop_string.h proplib.h
INCSDIR= /usr/include/prop
Index: common/include/prop/prop_codec.h
===================================================================
RCS file: common/include/prop/prop_codec.h
diff -N common/include/prop/prop_codec.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ common/include/prop/prop_codec.h 7 Jun 2007 13:26:36 -0000
@@ -0,0 +1,58 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jachym Holecek <
[email protected]>
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 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 _PROPLIB_PROP_CODEC_H_
+#define _PROPLIB_PROP_CODEC_H_
+
+typedef const struct _prop_codec *prop_codec_t;
+typedef void *prop_parser_t;
+
+__BEGIN_DECLS
+const char *prop_codec_list(void);
+prop_codec_t prop_codec_lookup(const char *);
+
+int prop_parser_create(prop_codec_t, prop_parser_t *);
+int prop_parser_exec(prop_codec_t, prop_parser_t, const u_char *,
+ size_t);
+prop_object_t prop_parser_yield(prop_codec_t, prop_parser_t);
+void prop_parser_destroy(prop_codec_t, prop_parser_t);
+
+char *prop_codec_externalize(prop_codec_t, prop_object_t);
+__END_DECLS
+
+#endif /* _PROPLIB_PROP_CODEC_H_ */
Index: common/include/prop/proplib.h
===================================================================
RCS file: /cvsroot/src/common/include/prop/proplib.h,v
retrieving revision 1.4
diff -d -p -u -r1.4 proplib.h
--- common/include/prop/proplib.h 22 Sep 2006 04:20:23 -0000 1.4
+++ common/include/prop/proplib.h 7 Jun 2007 13:26:36 -0000
@@ -46,6 +46,7 @@
#include <prop/prop_number.h>
#include <prop/prop_string.h>
+#include <prop/prop_codec.h>
#include <prop/prop_ingest.h>
/*
Index: common/lib/libprop/Makefile.inc
===================================================================
RCS file: /cvsroot/src/common/lib/libprop/Makefile.inc,v
retrieving revision 1.5
diff -d -p -u -r1.5 Makefile.inc
--- common/lib/libprop/Makefile.inc 26 Oct 2006 05:02:12 -0000 1.5
+++ common/lib/libprop/Makefile.inc 7 Jun 2007 13:26:39 -0000
@@ -2,8 +2,20 @@
.PATH: ${.PARSEDIR}
-SRCS+= prop_array.c prop_bool.c prop_data.c prop_dictionary.c \
+# User may restrict available internalizer/externalizer codecs.
+PROPLIB_CODECS?= xml scn
+
+SRCS+= prop_array.c prop_bool.c prop_codec.c prop_data.c prop_dictionary.c \
prop_dictionary_util.c prop_ingest.c prop_kern.c prop_number.c \
prop_object.c prop_string.c
-
SRCS+= prop_rb.c
+
+.if "${PROPLIB_CODECS:M*xml*}" != ""
+SRCS+= prop_xml.c
+CPPFLAGS+= -D_PROPLIB_CODEC_XML
+.endif
+
+.if "${PROPLIB_CODECS:M*scn*}" != ""
+SRCS+= prop_scn.c
+CPPFLAGS+= -D_PROPLIB_CODEC_SCN
+.endif
Index: common/lib/libprop/prop_array.c
===================================================================
RCS file: /cvsroot/src/common/lib/libprop/prop_array.c,v
retrieving revision 1.7
diff -d -p -u -r1.7 prop_array.c
--- common/lib/libprop/prop_array.c 3 Oct 2006 15:45:04 -0000 1.7
+++ common/lib/libprop/prop_array.c 7 Jun 2007 13:26:42 -0000
@@ -43,33 +43,16 @@
#include <errno.h>
#endif
-struct _prop_array {
- struct _prop_object pa_obj;
- _PROP_RWLOCK_DECL(pa_rwlock)
- prop_object_t * pa_array;
- unsigned int pa_capacity;
- unsigned int pa_count;
- int pa_flags;
-
- uint32_t pa_version;
-};
-
-#define PA_F_IMMUTABLE 0x01 /* array is immutable */
-
_PROP_POOL_INIT(_prop_array_pool, sizeof(struct _prop_array), "proparay")
_PROP_MALLOC_DEFINE(M_PROP_ARRAY, "prop array",
"property array container object")
static void _prop_array_free(void *);
-static boolean_t _prop_array_externalize(
- struct _prop_object_externalize_context *,
- void *);
static boolean_t _prop_array_equals(void *, void *);
static const struct _prop_object_type _prop_object_type_array = {
.pot_type = PROP_TYPE_ARRAY,
.pot_free = _prop_array_free,
- .pot_extern = _prop_array_externalize,
.pot_equals = _prop_array_equals,
};
@@ -111,59 +94,6 @@ _prop_array_free(void *v)
}
static boolean_t
-_prop_array_externalize(struct _prop_object_externalize_context *ctx,
- void *v)
-{
- prop_array_t pa = v;
- struct _prop_object *po;
- prop_object_iterator_t pi;
- unsigned int i;
- boolean_t rv = FALSE;
-
- _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
-
- if (pa->pa_count == 0) {
- _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
- return (_prop_object_externalize_empty_tag(ctx, "array"));
- }
-
- /* XXXJRT Hint "count" for the internalize step? */
- if (_prop_object_externalize_start_tag(ctx, "array") == FALSE ||
- _prop_object_externalize_append_char(ctx, '\n') == FALSE)
- goto out;
-
- pi = prop_array_iterator(pa);
- if (pi == NULL)
- goto out;
-
- ctx->poec_depth++;
- _PROP_ASSERT(ctx->poec_depth != 0);
-
- while ((po = prop_object_iterator_next(pi)) != NULL) {
- if ((*po->po_type->pot_extern)(ctx, po) == FALSE) {
- prop_object_iterator_release(pi);
- goto out;
- }
- }
-
- prop_object_iterator_release(pi);
-
- ctx->poec_depth--;
- for (i = 0; i < ctx->poec_depth; i++) {
- if (_prop_object_externalize_append_char(ctx, '\t') == FALSE)
- goto out;
- }
- if (_prop_object_externalize_end_tag(ctx, "array") == FALSE)
- goto out;
-
- rv = TRUE;
-
- out:
- _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
- return (rv);
-}
-
-static boolean_t
_prop_array_equals(void *v1, void *v2)
{
prop_array_t array1 = v1;
@@ -648,142 +578,6 @@ prop_array_equals(prop_array_t array1, p
return (_prop_array_equals(array1, array2));
}
-/*
- * prop_array_externalize --
- * Externalize an array, return a NUL-terminated buffer
- * containing the XML-style representation. The buffer is allocated
- * with the M_TEMP memory type.
- */
-char *
-prop_array_externalize(prop_array_t pa)
-{
- struct _prop_object_externalize_context *ctx;
- char *cp;
-
- ctx = _prop_object_externalize_context_alloc();
- if (ctx == NULL)
- return (NULL);
-
- if (_prop_object_externalize_header(ctx) == FALSE ||
- (*pa->pa_obj.po_type->pot_extern)(ctx, pa) == FALSE ||
- _prop_object_externalize_footer(ctx) == FALSE) {
- /* We are responsible for releasing the buffer. */
- _PROP_FREE(ctx->poec_buf, M_TEMP);
- _prop_object_externalize_context_free(ctx);
- return (NULL);
- }
-
- cp = ctx->poec_buf;
- _prop_object_externalize_context_free(ctx);
-
- return (cp);
-}
-
-/*
- * _prop_array_internalize --
- * Parse an <array>...</array> and return the object created from the
- * external representation.
- */
-prop_object_t
-_prop_array_internalize(struct _prop_object_internalize_context *ctx)
-{
- prop_array_t array;
- prop_object_t obj;
-
- /* We don't currently understand any attributes. */
- if (ctx->poic_tagattr != NULL)
- return (NULL);
-
- array = prop_array_create();
- if (array == NULL)
- return (NULL);
-
- if (ctx->poic_is_empty_element)
- return (array);
-
- for (;;) {
- /* Fetch the next tag. */
- if (_prop_object_internalize_find_tag(ctx, NULL,
- _PROP_TAG_TYPE_EITHER) == FALSE)
- goto bad;
-
- /* Check to see if this is the end of the array. */
- if (_PROP_TAG_MATCH(ctx, "array") &&
- ctx->poic_tag_type == _PROP_TAG_TYPE_END)
- break;
-
- /* Fetch the object. */
- obj = _prop_object_internalize_by_tag(ctx);
- if (obj == NULL)
- goto bad;
-
- if (prop_array_add(array, obj) == FALSE) {
- prop_object_release(obj);
- goto bad;
- }
- prop_object_release(obj);
- }
-
- return (array);
-
- bad:
- prop_object_release(array);
- return (NULL);
-}
-
-/*
- * prop_array_internalize --
- * Create an array by parsing the XML-style representation.
- */
-prop_array_t
-prop_array_internalize(const char *xml)
-{
- prop_array_t array = NULL;
- struct _prop_object_internalize_context *ctx;
-
- ctx = _prop_object_internalize_context_alloc(xml);
- if (ctx == NULL)
- return (NULL);
-
- /* We start with a <plist> tag. */
- if (_prop_object_internalize_find_tag(ctx, "plist",
- _PROP_TAG_TYPE_START) == FALSE)
- goto out;
-
- /* Plist elements cannot be empty. */
- if (ctx->poic_is_empty_element)
- goto out;
-
- /*
- * We don't understand any plist attributes, but Apple XML
- * property lists often have a "version" attribute. If we
- * see that one, we simply ignore it.
- */
- if (ctx->poic_tagattr != NULL &&
- !_PROP_TAGATTR_MATCH(ctx, "version"))
- goto out;
-
- /* Next we expect to see <array>. */
- if (_prop_object_internalize_find_tag(ctx, "array",
- _PROP_TAG_TYPE_START) == FALSE)
- goto out;
-
- array = _prop_array_internalize(ctx);
- if (array == NULL)
- goto out;
-
- /* We've advanced past </array>. Now we want </plist>. */
- if (_prop_object_internalize_find_tag(ctx, "plist",
- _PROP_TAG_TYPE_END) == FALSE) {
- prop_object_release(array);
- array = NULL;
- }
-
- out:
- _prop_object_internalize_context_free(ctx);
- return (array);
-}
-
#if !defined(_KERNEL) && !defined(_STANDALONE)
/*
* prop_array_externalize_to_file --
Index: common/lib/libprop/prop_bool.c
===================================================================
RCS file: /cvsroot/src/common/lib/libprop/prop_bool.c,v
retrieving revision 1.9
diff -d -p -u -r1.9 prop_bool.c
--- common/lib/libprop/prop_bool.c 16 Oct 2006 03:21:07 -0000 1.9
+++ common/lib/libprop/prop_bool.c 7 Jun 2007 13:26:42 -0000
@@ -51,15 +51,11 @@ _PROP_MUTEX_DECL_STATIC(_prop_bool_initi
static boolean_t _prop_bool_initialized;
static void _prop_bool_free(void *);
-static boolean_t _prop_bool_externalize(
- struct _prop_object_externalize_context *,
- void *);
static boolean_t _prop_bool_equals(void *, void *);
static const struct _prop_object_type _prop_object_type_bool = {
.pot_type = PROP_TYPE_BOOL,
.pot_free = _prop_bool_free,
- .pot_extern = _prop_bool_externalize,
.pot_equals = _prop_bool_equals,
};
@@ -79,16 +75,6 @@ _prop_bool_free(void *v _PROP_ARG_UNUSED
}
static boolean_t
-_prop_bool_externalize(struct _prop_object_externalize_context *ctx,
- void *v)
-{
- prop_bool_t pb = v;
-
- return (_prop_object_externalize_empty_tag(ctx,
- pb->pb_value ? "true" : "false"));
-}
-
-static boolean_t
_prop_bool_equals(void *v1, void *v2)
{
prop_bool_t b1 = v1;
@@ -187,28 +173,3 @@ prop_bool_equals(prop_bool_t b1, prop_bo
return (_prop_bool_equals(b1, b2));
}
-
-/*
- * _prop_bool_internalize --
- * Parse a <true/> or <false/> and return the object created from
- * the external representation.
- */
-prop_object_t
-_prop_bool_internalize(struct _prop_object_internalize_context *ctx)
-{
- boolean_t val;
-
- /* No attributes, and it must be an empty element. */
- if (ctx->poic_tagattr != NULL ||
- ctx->poic_is_empty_element == FALSE)
- return (NULL);
-
- if (_PROP_TAG_MATCH(ctx, "true"))
- val = TRUE;
- else {
- _PROP_ASSERT(_PROP_TAG_MATCH(ctx, "false"));
- val = FALSE;
- }
-
- return (prop_bool_create(val));
-}
Index: common/lib/libprop/prop_codec.c
===================================================================
RCS file: common/lib/libprop/prop_codec.c
diff -N common/lib/libprop/prop_codec.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ common/lib/libprop/prop_codec.c 7 Jun 2007 13:26:42 -0000
@@ -0,0 +1,304 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 2007 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jachym Holecek <
[email protected]>.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 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.
+ */
+
+#include <sys/errno.h>
+
+#include <prop/proplib.h>
+
+#include "prop_object_impl.h"
+#include "prop_codec_impl.h"
+
+
+extern const struct _prop_codec prop_codec_xml;
+extern const struct _prop_codec prop_codec_scn;
+
+static prop_codec_t prop_codec_table[] = {
+#if defined(_PROPLIB_CODEC_XML)
+ &prop_codec_xml,
+#endif
+#if defined(_PROPLIB_CODEC_SCN)
+ &prop_codec_scn,
+#endif
+ NULL
+};
+
+/* Default to the codec with smallest external representation available. */
+#if !defined(_PROP_DEFAULT_CODEC)
+#if defined(_PROPLIB_CODEC_SCN)
+#define _PROP_DEFAULT_CODEC "scn"
+#elif defined(_PROPLIB_CODEC_XML)
+#define _PROP_DEFAULT_CODEC "xml"
+#else
+#define _PROP_DEFAULT_CODEC "" /* Runtime failure */
+#endif
+#endif
+
+static const char *
+prop_skip_space(const char *str)
+{
+ if (str == NULL)
+ return (NULL);
+
+ while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r')
+ str++;
+
+ return (str);
+}
+
+static prop_codec_t
+prop_codec_guess(char c)
+{
+ int i;
+
+ /*
+ * Must be able to tell codec by the first non-white character.
+ * For binary codecs this implies their header must not begin
+ * with whitespace characters.
+ */
+ for (i = 0; prop_codec_table[i]; i++)
+ if (strchr((const char *)prop_codec_table[i]->codec_sense,
+ c) != NULL)
+ return (prop_codec_table[i]);
+
+ return (NULL);
+}
+
+static prop_object_t
+prop_parse_single(prop_codec_t co, const char *str, prop_type_t type)
+{
+ prop_parser_t pa;
+ prop_object_t po, pq;
+
+ if (prop_parser_create(co, &pa))
+ goto fail_0;
+
+ if (prop_parser_exec(co, pa, (const u_char *)str, strlen(str)))
+ goto fail_1;
+
+ if ((po = prop_parser_yield(co, pa)) == NULL)
+ goto fail_1;
+
+ /* Expect ${str} contains exactly one object. */
+ if ((pq = prop_parser_yield(co, pa)) != NULL) {
+ prop_object_release(pq);
+ goto fail_2;
+ }
+
+ if (prop_object_type(po) != type)
+ goto fail_2;
+
+ prop_parser_destroy(co, pa);
+ return (po);
+
+ fail_2:
+ prop_object_release(po);
+ fail_1:
+ prop_parser_destroy(co, pa);
+ fail_0:
+ return (NULL);
+}
+
+const char *
+prop_codec_list(void)
+{
+ static boolean_t doinit = TRUE;
+ static char names[8]; /* XXX Large enough */
+ size_t idx = 0;
+ int i;
+
+ /* XXX locking? */
+ if (doinit) {
+ for (i = 0; prop_codec_table[i]; i++) {
+ strcpy(names + idx, prop_codec_table[i]->codec_name);
+ idx += strlen(prop_codec_table[i]->codec_name);
+
+ if (prop_codec_table[i + 1])
+ names[idx++] = ' ';
+ }
+
+ names[idx] = '\0';
+ doinit = FALSE;
+ }
+
+ return (names);
+}
+
+prop_codec_t
+prop_codec_lookup(const char *name)
+{
+ int i;
+
+ if (name == NULL)
+ name = _PROP_DEFAULT_CODEC;
+
+ for (i = 0; prop_codec_table[i]; i++)
+ if (strcmp(prop_codec_table[i]->codec_name, name) == 0)
+ return (prop_codec_table[i]);
+
+ return (NULL);
+}
+
+prop_dictionary_t
+prop_dictionary_internalize(const char *str)
+{
+ prop_codec_t co;
+
+ if ((str = prop_skip_space(str)) == NULL)
+ return (NULL);
+
+ if ((co = prop_codec_guess(*str)) == NULL)
+ return (NULL);
+
+ if (co->codec_dictionary_internalize)
+ return ((co->codec_dictionary_internalize)(str));
+
+ return (prop_parse_single(co, str, PROP_TYPE_DICTIONARY));
+}
+
+prop_array_t
+prop_array_internalize(const char *str)
+{
+ prop_codec_t co;
+
+ if ((str = prop_skip_space(str)) == NULL)
+ return (NULL);
+
+ if ((co = prop_codec_guess(*str)) == NULL)
+ return (NULL);
+
+ if (co->codec_array_internalize)
+ return ((co->codec_array_internalize)(str));
+
+ return (prop_parse_single(co, str, PROP_TYPE_ARRAY));
+}
+
+char *
+prop_dictionary_externalize(prop_dictionary_t pd)
+{
+ prop_codec_t co = prop_codec_lookup(_PROP_DEFAULT_CODEC);
+
+ _PROP_ASSERT(co);
+
+ if (co->codec_dictionary_externalize)
+ return ((co->codec_dictionary_externalize)(pd));
+
+ if (co->codec_externalize_compound)
+ return ((co->codec_externalize_compound)(pd));
+
+ return (NULL);
+}
+
+char *
+prop_array_externalize(prop_array_t pa)
+{
+ prop_codec_t co = prop_codec_lookup(_PROP_DEFAULT_CODEC);
+
+ _PROP_ASSERT(co);
+
+ if (co->codec_array_externalize)
+ return ((co->codec_array_externalize)(pa));
+
+ if (co->codec_externalize_compound)
+ return ((co->codec_externalize_compound)(pa));
+
+ return (NULL);
+}
+
+char *
+prop_codec_externalize(prop_codec_t co, prop_object_t po)
+{
+ _PROP_ASSERT(co);
+
+ if (co->codec_externalize_compound)
+ return ((co->codec_externalize_compound)(po));
+
+ switch (prop_object_type(po)) {
+ case PROP_TYPE_DICTIONARY:
+ return ((co->codec_dictionary_externalize)(po));
+ case PROP_TYPE_ARRAY:
+ return ((co->codec_array_externalize)(po));
+ default:
+ return (NULL);
+ }
+}
+
+int
+prop_parser_create(prop_codec_t co, prop_parser_t *pp)
+{
+ _PROP_ASSERT(co);
+
+ if (pp == NULL)
+ return (EINVAL);
+
+ if (co->codec_parser_create)
+ return ((co->codec_parser_create)(pp));
+
+ return (EOPNOTSUPP);
+}
+
+int
+prop_parser_exec(prop_codec_t co, prop_parser_t pa, const u_char *str,
+ size_t len)
+{
+ _PROP_ASSERT(co);
+
+ if (co->codec_parser_exec)
+ return ((co->codec_parser_exec)(pa, str, len));
+
+ return (EOPNOTSUPP);
+}
+
+prop_object_t
+prop_parser_yield(prop_codec_t co, prop_parser_t pa)
+{
+ _PROP_ASSERT(co);
+
+ if (co->codec_parser_yield)
+ return ((co->codec_parser_yield)(pa));
+
+ return (NULL);
+}
+
+void
+prop_parser_destroy(prop_codec_t co, prop_parser_t pa)
+{
+ _PROP_ASSERT(co);
+
+ if (co->codec_parser_destroy)
+ (co->codec_parser_destroy)(pa);
+}
Index: common/lib/libprop/prop_codec_impl.h
===================================================================
RCS file: common/lib/libprop/prop_codec_impl.h
diff -N common/lib/libprop/prop_codec_impl.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ common/lib/libprop/prop_codec_impl.h 7 Jun 2007 13:26:44 -0000
@@ -0,0 +1,61 @@
+/* $NetBSD: prop_object_impl.h,v 1.12 2007/03/12 18:18:39 ad Exp $ */
+
+/*-
+ * Copyright (c) 2007 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jachym Holecek <
[email protected]>
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 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 _PROPLIB_PROP_CODEC_IMPL_H_
+#define _PROPLIB_PROP_CODEC_IMPL_H_
+
+struct _prop_codec {
+ const char *codec_name;
+ const u_char *codec_sense;
+
+ /* Either we provide direct backends for public functions. */
+ char * (*codec_dictionary_externalize)(prop_dictionary_t);
+ char * (*codec_array_externalize)(prop_array_t);
+ prop_dictionary_t (*codec_dictionary_internalize)(const char *);
+ prop_array_t (*codec_array_internalize)(const char *);
+
+ /* Or we provide "stream-friendly" API and emulate the above. */
+ char * (*codec_externalize_compound)(prop_object_t);
+ int (*codec_parser_create)(prop_parser_t *);
+ int (*codec_parser_exec)(prop_parser_t, const u_char *,
+ size_t);
+ prop_object_t (*codec_parser_yield)(prop_parser_t);
+ void (*codec_parser_destroy)(prop_parser_t);
+};
+
+#endif /* _PROPLIB_PROP_CODEC_IMPL_H_ */
Index: common/lib/libprop/prop_data.c
===================================================================
RCS file: /cvsroot/src/common/lib/libprop/prop_data.c,v
retrieving revision 1.6
diff -d -p -u -r1.6 prop_data.c
--- common/lib/libprop/prop_data.c 4 Mar 2007 22:31:43 -0000 1.6
+++ common/lib/libprop/prop_data.c 7 Jun 2007 13:26:44 -0000
@@ -50,35 +50,17 @@
#include <stdlib.h>
#endif
-struct _prop_data {
- struct _prop_object pd_obj;
- union {
- void * pdu_mutable;
- const void * pdu_immutable;
- } pd_un;
-#define pd_mutable pd_un.pdu_mutable
-#define pd_immutable pd_un.pdu_immutable
- size_t pd_size;
- int pd_flags;
-};
-
-#define PD_F_NOCOPY 0x01
-
_PROP_POOL_INIT(_prop_data_pool, sizeof(struct _prop_data), "propdata")
_PROP_MALLOC_DEFINE(M_PROP_DATA, "prop data",
"property data container object")
static void _prop_data_free(void *);
-static boolean_t _prop_data_externalize(
- struct _prop_object_externalize_context *,
- void *);
static boolean_t _prop_data_equals(void *, void *);
static const struct _prop_object_type _prop_object_type_data = {
.pot_type = PROP_TYPE_DATA,
.pot_free = _prop_data_free,
- .pot_extern = _prop_data_externalize,
.pot_equals = _prop_data_equals,
};
@@ -95,85 +77,6 @@ _prop_data_free(void *v)
_PROP_POOL_PUT(_prop_data_pool, v);
}
-static const char _prop_data_base64[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-static const char _prop_data_pad64 = '=';
-
-static boolean_t
-_prop_data_externalize(struct _prop_object_externalize_context *ctx, void *v)
-{
- prop_data_t pd = v;
- size_t i, srclen;
- const uint8_t *src;
- uint8_t output[4];
- uint8_t input[3];
-
- if (pd->pd_size == 0)
- return (_prop_object_externalize_empty_tag(ctx, "data"));
-
- if (_prop_object_externalize_start_tag(ctx, "data") == FALSE)
- return (FALSE);
-
- for (src = pd->pd_immutable, srclen = pd->pd_size;
- srclen > 2; srclen -= 3) {
- input[0] = *src++;
- input[1] = *src++;
- input[2] = *src++;
-
- output[0] = (uint32_t)input[0] >> 2;
- output[1] = ((uint32_t)(input[0] & 0x03) << 4) +
- ((uint32_t)input[1] >> 4);
- output[2] = ((u_int32_t)(input[1] & 0x0f) << 2) +
- ((uint32_t)input[2] >> 6);
- output[3] = input[2] & 0x3f;
- _PROP_ASSERT(output[0] < 64);
- _PROP_ASSERT(output[1] < 64);
- _PROP_ASSERT(output[2] < 64);
- _PROP_ASSERT(output[3] < 64);
-
- if (_prop_object_externalize_append_char(ctx,
- _prop_data_base64[output[0]]) == FALSE ||
- _prop_object_externalize_append_char(ctx,
- _prop_data_base64[output[1]]) == FALSE ||
- _prop_object_externalize_append_char(ctx,
- _prop_data_base64[output[2]]) == FALSE ||
- _prop_object_externalize_append_char(ctx,
- _prop_data_base64[output[3]]) == FALSE)
- return (FALSE);
- }
-
- if (srclen != 0) {
- input[0] = input[1] = input[2] = '\0';
- for (i = 0; i < srclen; i++)
- input[i] = *src++;
-
- output[0] = (uint32_t)input[0] >> 2;
- output[1] = ((uint32_t)(input[0] & 0x03) << 4) +
- ((uint32_t)input[1] >> 4);
- output[2] = ((u_int32_t)(input[1] & 0x0f) << 2) +
- ((uint32_t)input[2] >> 6);
- _PROP_ASSERT(output[0] < 64);
- _PROP_ASSERT(output[1] < 64);
- _PROP_ASSERT(output[2] < 64);
-
- if (_prop_object_externalize_append_char(ctx,
- _prop_data_base64[output[0]]) == FALSE ||
- _prop_object_externalize_append_char(ctx,
- _prop_data_base64[output[1]]) == FALSE ||
- _prop_object_externalize_append_char(ctx,
- srclen == 1 ? _prop_data_pad64
- : _prop_data_base64[output[2]]) == FALSE ||
- _prop_object_externalize_append_char(ctx,
- _prop_data_pad64) == FALSE)
- return (FALSE);
- }
-
- if (_prop_object_externalize_end_tag(ctx, "data") == FALSE)
- return (FALSE);
-
- return (TRUE);
-}
-
static boolean_t
_prop_data_equals(void *v1, void *v2)
{
@@ -197,7 +100,7 @@ _prop_data_equals(void *v1, void *v2)
pd1->pd_size) == 0);
}
-static prop_data_t
+prop_data_t
_prop_data_alloc(void)
{
prop_data_t pd;
@@ -376,230 +279,3 @@ prop_data_equals_data(prop_data_t pd, co
return (FALSE);
return (memcmp(pd->pd_immutable, v, size) == 0);
}
-
-static boolean_t
-_prop_data_internalize_decode(struct _prop_object_internalize_context *ctx,
- uint8_t *target, size_t targsize, size_t *sizep,
- const char **cpp)
-{
- const char *src;
- size_t tarindex;
- int state, ch;
- const char *pos;
-
- state = 0;
- tarindex = 0;
- src = ctx->poic_cp;
-
- for (;;) {
- ch = (unsigned char) *src++;
- if (_PROP_EOF(ch))
- return (FALSE);
- if (_PROP_ISSPACE(ch))
- continue;
- if (ch == '<') {
- src--;
- break;
- }
- if (ch == _prop_data_pad64)
- break;
-
- pos = strchr(_prop_data_base64, ch);
- if (pos == NULL)
- return (FALSE);
-
- switch (state) {
- case 0:
- if (target) {
- if (tarindex >= targsize)
- return (FALSE);
- target[tarindex] =
- (uint8_t)((pos - _prop_data_base64) << 2);
- }
- state = 1;
- break;
-
- case 1:
- if (target) {
- if (tarindex + 1 >= targsize)
- return (FALSE);
- target[tarindex] |=
- (uint32_t)(pos - _prop_data_base64) >> 4;
- target[tarindex + 1] =
- (uint8_t)(((pos - _prop_data_base64) & 0xf)
- << 4);
- }
- tarindex++;
- state = 2;
- break;
-
- case 2:
- if (target) {
- if (tarindex + 1 >= targsize)
- return (FALSE);
- target[tarindex] |=
- (uint32_t)(pos - _prop_data_base64) >> 2;
- target[tarindex + 1] =
- (uint8_t)(((pos - _prop_data_base64)
- & 0x3) << 6);
- }
- tarindex++;
- state = 3;
- break;
-
- case 3:
- if (target) {
- if (tarindex >= targsize)
- return (FALSE);
- target[tarindex] |= (uint8_t)
- (pos - _prop_data_base64);
- }
- tarindex++;
- state = 0;
- break;
-
- default:
- _PROP_ASSERT(/*CONSTCOND*/0);
- }
- }
-
- /*
- * We are done decoding the Base64 characters. Let's see if we
- * ended up on a byte boundary and/or with unrecognized trailing
- * characters.
- */
- if (ch == _prop_data_pad64) {
- ch = (unsigned char) *src; /* src already advanced */
- if (_PROP_EOF(ch))
- return (FALSE);
- switch (state) {
- case 0: /* Invalid = in first position */
- case 1: /* Invalid = in second position */
- return (FALSE);
-
- case 2: /* Valid, one byte of info */
- /* Skip whitespace */
- for (ch = (unsigned char) *src++;
- ch != '<'; ch = (unsigned char) *src++) {
- if (_PROP_EOF(ch))
- return (FALSE);
- if (!_PROP_ISSPACE(ch))
- break;
- }
- /* Make sure there is another trailing = */
- if (ch != _prop_data_pad64)
- return (FALSE);
- ch = (unsigned char) *src;
- /* FALLTHROUGH */
-
- case 3: /* Valid, two bytes of info */
- /*
- * We know this char is a =. Is there anything but
- * whitespace after it?
- */
- for (ch = (unsigned char) *src++;
- ch != '<'; ch = (unsigned char) *src++) {
- if (_PROP_EOF(ch))
- return (FALSE);
- if (!_PROP_ISSPACE(ch))
- return (FALSE);
- }
- /* back up to '<' */
- src--;
- }
- } else {
- /*
- * We ended by seeing the end of the Base64 string. Make
- * sure there are no partial bytes lying around.
- */
- if (state != 0)
- return (FALSE);
- }
-
- _PROP_ASSERT(*src == '<');
- if (sizep != NULL)
- *sizep = tarindex;
- if (cpp != NULL)
- *cpp = src;
-
- return (TRUE);
-}
-
-/*
- * _prop_data_internalize --
- * Parse a <data>...</data> and return the object created from the
- * external representation.
- */
-prop_object_t
-_prop_data_internalize(struct _prop_object_internalize_context *ctx)
-{
- prop_data_t data;
- uint8_t *buf;
- size_t len, alen;
-
- /* We don't accept empty elements. */
- if (ctx->poic_is_empty_element)
- return (NULL);
-
- /*
- * If we got a "size" attribute, get the size of the data blob
- * from that. Otherwise, we have to figure it out from the base64.
- */
- if (ctx->poic_tagattr != NULL) {
- char *cp;
-
- if (!_PROP_TAGATTR_MATCH(ctx, "size") ||
- ctx->poic_tagattrval_len == 0)
- return (NULL);
-
-#ifndef _KERNEL
- errno = 0;
-#endif
- /* XXX Assumes size_t and unsigned long are the same size. */
- len = strtoul(ctx->poic_tagattrval, &cp, 0);
-#ifndef _KERNEL /* XXX can't check for ERANGE in the kernel */
- if (len == ULONG_MAX && errno == ERANGE)
- return (NULL);
-#endif
- if (cp != ctx->poic_tagattrval + ctx->poic_tagattrval_len)
- return (NULL);
- _PROP_ASSERT(*cp == '\"');
- } else if (_prop_data_internalize_decode(ctx, NULL, 0, &len,
- NULL) == FALSE)
- return (NULL);
-
- /*
- * Always allocate one extra in case we don't land on an even byte
- * boundary during the decode.
- */
- buf = _PROP_MALLOC(len + 1, M_PROP_DATA);
- if (buf == NULL)
- return (NULL);
-
- if (_prop_data_internalize_decode(ctx, buf, len + 1, &alen,
- &ctx->poic_cp) == FALSE) {
- _PROP_FREE(buf, M_PROP_DATA);
- return (NULL);
- }
- if (alen != len) {
- _PROP_FREE(buf, M_PROP_DATA);
- return (NULL);
- }
-
- if (_prop_object_internalize_find_tag(ctx, "data",
- _PROP_TAG_TYPE_END) == FALSE) {
- _PROP_FREE(buf, M_PROP_DATA);
- return (NULL);
- }
-
- data = _prop_data_alloc();
- if (data == NULL) {
- _PROP_FREE(buf, M_PROP_DATA);
- return (NULL);
- }
-
- data->pd_mutable = buf;
- data->pd_size = len;
-
- return (data);
-}
Index: common/lib/libprop/prop_dictionary.c
===================================================================
RCS file: /cvsroot/src/common/lib/libprop/prop_dictionary.c,v
retrieving revision 1.16
diff -d -p -u -r1.16 prop_dictionary.c
--- common/lib/libprop/prop_dictionary.c 26 Oct 2006 05:02:12 -0000 1.16
+++ common/lib/libprop/prop_dictionary.c 7 Jun 2007 13:26:49 -0000
@@ -82,7 +82,10 @@ struct _prop_dictionary_keysym {
#define PDK_SIZE_32 (sizeof(struct _prop_dictionary_keysym) + 32)
#define PDK_SIZE_128 (sizeof(struct _prop_dictionary_keysym) + 128)
-#define PDK_MAXKEY 128
+_PROP_POOL_INIT(_prop_dictionary_pool, sizeof(struct _prop_dictionary),
+ "propdict")
+_PROP_MALLOC_DEFINE(M_PROP_DICT, "prop dictionary",
+ "property dictionary container object")
_PROP_POOL_INIT(_prop_dictionary_keysym16_pool, PDK_SIZE_16, "pdict16")
_PROP_POOL_INIT(_prop_dictionary_keysym32_pool, PDK_SIZE_32, "pdict32")
@@ -93,47 +96,21 @@ struct _prop_dict_entry {
prop_object_t pde_objref;
};
-struct _prop_dictionary {
- struct _prop_object pd_obj;
- _PROP_RWLOCK_DECL(pd_rwlock)
- struct _prop_dict_entry *pd_array;
- unsigned int pd_capacity;
- unsigned int pd_count;
- int pd_flags;
-
- uint32_t pd_version;
-};
-
-#define PD_F_IMMUTABLE 0x01 /* dictionary is immutable */
-
-_PROP_POOL_INIT(_prop_dictionary_pool, sizeof(struct _prop_dictionary),
- "propdict")
-_PROP_MALLOC_DEFINE(M_PROP_DICT, "prop dictionary",
- "property dictionary container object")
-
static void _prop_dictionary_free(void *);
-static boolean_t _prop_dictionary_externalize(
- struct _prop_object_externalize_context *,
- void *);
static boolean_t _prop_dictionary_equals(void *, void *);
static const struct _prop_object_type _prop_object_type_dictionary = {
.pot_type = PROP_TYPE_DICTIONARY,
.pot_free = _prop_dictionary_free,
- .pot_extern = _prop_dictionary_externalize,
.pot_equals = _prop_dictionary_equals,
};
static void _prop_dict_keysym_free(void *);
-static boolean_t _prop_dict_keysym_externalize(
- struct _prop_object_externalize_context *,
- void *);
static boolean_t _prop_dict_keysym_equals(void *, void *);
static const struct _prop_object_type _prop_object_type_dict_keysym = {
.pot_type = PROP_TYPE_DICT_KEYSYM,
.pot_free = _prop_dict_keysym_free,
- .pot_extern = _prop_dict_keysym_externalize,
.pot_equals = _prop_dict_keysym_equals,
};
@@ -213,25 +190,6 @@ _prop_dict_keysym_free(void *v)
}
static boolean_t
-_prop_dict_keysym_externalize(struct _prop_object_externalize_context *ctx,
- void *v)
-{
- prop_dictionary_keysym_t pdk = v;
-
- /* We externalize these as strings, and they're never empty. */
-
- _PROP_ASSERT(pdk->pdk_key[0] != '\0');
-
- if (_prop_object_externalize_start_tag(ctx, "string") == FALSE ||
- _prop_object_externalize_append_encoded_cstring(ctx,
- pdk->pdk_key) == FALSE ||
- _prop_object_externalize_end_tag(ctx, "string") == FALSE)
- return (FALSE);
-
- return (TRUE);
-}
-
-static boolean_t
_prop_dict_keysym_equals(void *v1, void *v2)
{
prop_dictionary_keysym_t pdk1 = v1;
@@ -346,65 +304,6 @@ _prop_dictionary_free(void *v)
}
static boolean_t
-_prop_dictionary_externalize(struct _prop_object_externalize_context *ctx,
- void *v)
-{
- prop_dictionary_t pd = v;
- prop_dictionary_keysym_t pdk;
- struct _prop_object *po;
- prop_object_iterator_t pi;
- unsigned int i;
- boolean_t rv = FALSE;
-
- _PROP_RWLOCK_RDLOCK(pd->pd_rwlock);
-
- if (pd->pd_count == 0) {
- _PROP_RWLOCK_UNLOCK(pd->pd_rwlock);
- return (_prop_object_externalize_empty_tag(ctx, "dict"));
- }
-
- if (_prop_object_externalize_start_tag(ctx, "dict") == FALSE ||
- _prop_object_externalize_append_char(ctx, '\n') == FALSE)
- goto out;
-
- pi = prop_dictionary_iterator(pd);
- if (pi == NULL)
- goto out;
-
- ctx->poec_depth++;
- _PROP_ASSERT(ctx->poec_depth != 0);
-
- while ((pdk = prop_object_iterator_next(pi)) != NULL) {
- po = prop_dictionary_get_keysym(pd, pdk);
- if (po == NULL ||
- _prop_object_externalize_start_tag(ctx, "key") == FALSE ||
- _prop_object_externalize_append_encoded_cstring(ctx,
- pdk->pdk_key) == FALSE ||
- _prop_object_externalize_end_tag(ctx, "key") == FALSE ||
- (*po->po_type->pot_extern)(ctx, po) == FALSE) {
- prop_object_iterator_release(pi);
- goto out;
- }
- }
-
- prop_object_iterator_release(pi);
-
- ctx->poec_depth--;
- for (i = 0; i < ctx->poec_depth; i++) {
- if (_prop_object_externalize_append_char(ctx, '\t') == FALSE)
- goto out;
- }
- if (_prop_object_externalize_end_tag(ctx, "dict") == FALSE)
- goto out;
-
- rv = TRUE;
-
- out:
- _PROP_RWLOCK_UNLOCK(pd->pd_rwlock);
- return (rv);
-}
-
-static boolean_t
_prop_dictionary_equals(void *v1, void *v2)
{
prop_dictionary_t dict1 = v1;
@@ -1029,174 +928,6 @@ prop_dictionary_keysym_equals(prop_dicti
return (_prop_dict_keysym_equals(pdk1, pdk2));
}
-/*
- * prop_dictionary_externalize --
- * Externalize a dictionary, returning a NUL-terminated buffer
- * containing the XML-style representation. The buffer is allocated
- * with the M_TEMP memory type.
- */
-char *
-prop_dictionary_externalize(prop_dictionary_t pd)
-{
- struct _prop_object_externalize_context *ctx;
- char *cp;
-
- ctx = _prop_object_externalize_context_alloc();
- if (ctx == NULL)
- return (NULL);
-
- if (_prop_object_externalize_header(ctx) == FALSE ||
- (*pd->pd_obj.po_type->pot_extern)(ctx, pd) == FALSE ||
- _prop_object_externalize_footer(ctx) == FALSE) {
- /* We are responsible for releasing the buffer. */
- _PROP_FREE(ctx->poec_buf, M_TEMP);
- _prop_object_externalize_context_free(ctx);
- return (NULL);
- }
-
- cp = ctx->poec_buf;
- _prop_object_externalize_context_free(ctx);
-
- return (cp);
-}
-
-/*
- * _prop_dictionary_internalize --
- * Parse a <dict>...</dict> and return the object created from the
- * external representation.
- */
-prop_object_t
-_prop_dictionary_internalize(struct _prop_object_internalize_context *ctx)
-{
- prop_dictionary_t dict;
- prop_object_t val;
- size_t keylen;
- char *tmpkey;
-
- /* We don't currently understand any attributes. */
- if (ctx->poic_tagattr != NULL)
- return (NULL);
-
- dict = prop_dictionary_create();
- if (dict == NULL)
- return (NULL);
-
- if (ctx->poic_is_empty_element)
- return (dict);
-
- tmpkey = _PROP_MALLOC(PDK_MAXKEY + 1, M_TEMP);
- if (tmpkey == NULL)
- goto bad;
-
- for (;;) {
- /* Fetch the next tag. */
- if (_prop_object_internalize_find_tag(ctx, NULL,
- _PROP_TAG_TYPE_EITHER) == FALSE)
- goto bad;
-
- /* Check to see if this is the end of the dictionary. */
- if (_PROP_TAG_MATCH(ctx, "dict") &&
- ctx->poic_tag_type == _PROP_TAG_TYPE_END)
- break;
-
- /* Ok, it must be a non-empty key start tag. */
- if (!_PROP_TAG_MATCH(ctx, "key") ||
- ctx->poic_tag_type != _PROP_TAG_TYPE_START ||
- ctx->poic_is_empty_element)
- goto bad;
-
- if (_prop_object_internalize_decode_string(ctx,
- tmpkey, PDK_MAXKEY, &keylen,
- &ctx->poic_cp) == FALSE)
- goto bad;
-
- _PROP_ASSERT(keylen <= PDK_MAXKEY);
- tmpkey[keylen] = '\0';
-
- if (_prop_object_internalize_find_tag(ctx, "key",
- _PROP_TAG_TYPE_END) == FALSE)
- goto bad;
-
- /* ..and now the beginning of the value. */
- if (_prop_object_internalize_find_tag(ctx, NULL,
- _PROP_TAG_TYPE_START) == FALSE)
- goto bad;
-
- val = _prop_object_internalize_by_tag(ctx);
- if (val == NULL)
- goto bad;
-
- if (prop_dictionary_set(dict, tmpkey, val) == FALSE) {
- prop_object_release(val);
- goto bad;
- }
- prop_object_release(val);
- }
-
- _PROP_FREE(tmpkey, M_TEMP);
- return (dict);
-
- bad:
- if (tmpkey != NULL)
- _PROP_FREE(tmpkey, M_TEMP);
- prop_object_release(dict);
- return (NULL);
-}
-
-/*
- * prop_dictionary_internalize --
- * Create a dictionary by parsing the NUL-terminated XML-style
- * representation.
- */
-prop_dictionary_t
-prop_dictionary_internalize(const char *xml)
-{
- prop_dictionary_t dict = NULL;
- struct _prop_object_internalize_context *ctx;
-
- ctx = _prop_object_internalize_context_alloc(xml);
- if (ctx == NULL)
- return (NULL);
-
- /* We start with a <plist> tag. */
- if (_prop_object_internalize_find_tag(ctx, "plist",
- _PROP_TAG_TYPE_START) == FALSE)
- goto out;
-
- /* Plist elements cannot be empty. */
- if (ctx->poic_is_empty_element)
- goto out;
-
- /*
- * We don't understand any plist attributes, but Apple XML
- * property lists often have a "version" attribute. If we
- * see that one, we simply ignore it.
- */
- if (ctx->poic_tagattr != NULL &&
- !_PROP_TAGATTR_MATCH(ctx, "version"))
- goto out;
-
- /* Next we expect to see <dict>. */
- if (_prop_object_internalize_find_tag(ctx, "dict",
- _PROP_TAG_TYPE_START) == FALSE)
- goto out;
-
- dict = _prop_dictionary_internalize(ctx);
- if (dict == NULL)
- goto out;
-
- /* We've advanced past </dict>. Now we want </plist>. */
- if (_prop_object_internalize_find_tag(ctx, "plist",
- _PROP_TAG_TYPE_END) == FALSE) {
- prop_object_release(dict);
- dict = NULL;
- }
-
- out:
- _prop_object_internalize_context_free(ctx);
- return (dict);
-}
-
#if !defined(_KERNEL) && !defined(_STANDALONE)
/*
* prop_dictionary_externalize_to_file --
Index: common/lib/libprop/prop_number.c
===================================================================
RCS file: /cvsroot/src/common/lib/libprop/prop_number.c,v
retrieving revision 1.11
diff -d -p -u -r1.11 prop_number.c
--- common/lib/libprop/prop_number.c 15 Oct 2006 19:11:58 -0000 1.11
+++ common/lib/libprop/prop_number.c 7 Jun 2007 13:26:52 -0000
@@ -50,19 +50,11 @@
#include <stdlib.h>
#endif
+
struct _prop_number {
- struct _prop_object pn_obj;
- struct rb_node pn_link;
- struct _prop_number_value {
- union {
- int64_t pnu_signed;
- uint64_t pnu_unsigned;
- } pnv_un;
-#define pnv_signed pnv_un.pnu_signed
-#define pnv_unsigned pnv_un.pnu_unsigned
- unsigned int pnv_is_unsigned :1,
- :31;
- } pn_value;
+ struct _prop_object pn_obj;
+ struct rb_node pn_link;
+ struct _prop_number_value pn_value;
};
#define RBNODE_TO_PN(n) \
@@ -72,15 +64,11 @@ struct _prop_number {
_PROP_POOL_INIT(_prop_number_pool, sizeof(struct _prop_number), "propnmbr")
static void _prop_number_free(void *);
-static boolean_t _prop_number_externalize(
- struct _prop_object_externalize_context *,
- void *);
static boolean_t _prop_number_equals(void *, void *);
static const struct _prop_object_type _prop_object_type_number = {
.pot_type = PROP_TYPE_NUMBER,
.pot_free = _prop_number_free,
- .pot_extern = _prop_number_externalize,
.pot_equals = _prop_number_equals,
};
@@ -162,30 +150,6 @@ _prop_number_free(void *v)
}
static boolean_t
-_prop_number_externalize(struct _prop_object_externalize_context *ctx,
- void *v)
-{
- prop_number_t pn = v;
- char tmpstr[32];
-
- /*
- * For unsigned numbers, we output in hex. For signed numbers,
- * we output in decimal.
- */
- if (pn->pn_value.pnv_is_unsigned)
- sprintf(tmpstr, "0x%" PRIx64, pn->pn_value.pnv_unsigned);
- else
- sprintf(tmpstr, "%" PRIi64, pn->pn_value.pnv_signed);
-
- if (_prop_object_externalize_start_tag(ctx, "integer") == FALSE ||
- _prop_object_externalize_append_cstring(ctx, tmpstr) == FALSE ||
- _prop_object_externalize_end_tag(ctx, "integer") == FALSE)
- return (FALSE);
-
- return (TRUE);
-}
-
-static boolean_t
_prop_number_equals(void *v1, void *v2)
{
prop_number_t num1 = v1;
@@ -239,7 +203,7 @@ _prop_number_equals(void *v1, void *v2)
return (num1->pn_value.pnv_signed == num2->pn_value.pnv_signed);
}
-static prop_number_t
+prop_number_t
_prop_number_alloc(const struct _prop_number_value *pnv)
{
prop_number_t opn, pn;
@@ -476,91 +440,3 @@ prop_number_equals_unsigned_integer(prop
return (pn->pn_value.pnv_unsigned == val);
}
-
-static boolean_t
-_prop_number_internalize_unsigned(struct _prop_object_internalize_context *ctx,
- struct _prop_number_value *pnv)
-{
- char *cp;
-
- _PROP_ASSERT(/*CONSTCOND*/sizeof(unsigned long long) ==
- sizeof(uint64_t));
-
-#ifndef _KERNEL
- errno = 0;
-#endif
- pnv->pnv_unsigned = (uint64_t) strtoull(ctx->poic_cp, &cp, 0);
-#ifndef _KERNEL /* XXX can't check for ERANGE in the kernel */
- if (pnv->pnv_unsigned == UINT64_MAX && errno == ERANGE)
- return (FALSE);
-#endif
- pnv->pnv_is_unsigned = TRUE;
- ctx->poic_cp = cp;
-
- return (TRUE);
-}
-
-static boolean_t
-_prop_number_internalize_signed(struct _prop_object_internalize_context *ctx,
- struct _prop_number_value *pnv)
-{
- char *cp;
-
- _PROP_ASSERT(/*CONSTCOND*/sizeof(long long) == sizeof(int64_t));
-
-#ifndef _KERNEL
- errno = 0;
-#endif
- pnv->pnv_signed = (int64_t) strtoll(ctx->poic_cp, &cp, 0);
-#ifndef _KERNEL /* XXX can't check for ERANGE in the kernel */
- if ((pnv->pnv_signed == INT64_MAX || pnv->pnv_signed == INT64_MIN) &&
- errno == ERANGE)
- return (FALSE);
-#endif
- pnv->pnv_is_unsigned = FALSE;
- ctx->poic_cp = cp;
-
- return (TRUE);
-}
-
-/*
- * _prop_number_internalize --
- * Parse a <number>...</number> and return the object created from
- * the external representation.
- */
-prop_object_t
-_prop_number_internalize(struct _prop_object_internalize_context *ctx)
-{
- struct _prop_number_value pnv;
-
- memset(&pnv, 0, sizeof(pnv));
-
- /* No attributes, no empty elements. */
- if (ctx->poic_tagattr != NULL || ctx->poic_is_empty_element)
- return (NULL);
-
- /*
- * If the first character is '-', then we treat as signed.
- * If the first two characters are "0x" (i.e. the number is
- * in hex), then we treat as unsigned. Otherwise, we try
- * signed first, and if that fails (presumably due to ERANGE),
- * then we switch to unsigned.
- */
- if (ctx->poic_cp[0] == '-') {
- if (_prop_number_internalize_signed(ctx, &pnv) == FALSE)
- return (NULL);
- } else if (ctx->poic_cp[0] == '0' && ctx->poic_cp[1] == 'x') {
- if (_prop_number_internalize_unsigned(ctx, &pnv) == FALSE)
- return (NULL);
- } else {
- if (_prop_number_internalize_signed(ctx, &pnv) == FALSE &&
- _prop_number_internalize_unsigned(ctx, &pnv) == FALSE)
- return (NULL);
- }
-
- if (_prop_object_internalize_find_tag(ctx, "integer",
- _PROP_TAG_TYPE_END) == FALSE)
- return (NULL);
-
- return (_prop_number_alloc(&pnv));
-}
Index: common/lib/libprop/prop_object.c
===================================================================
RCS file: /cvsroot/src/common/lib/libprop/prop_object.c,v
retrieving revision 1.12
diff -d -p -u -r1.12 prop_object.c
--- common/lib/libprop/prop_object.c 19 Oct 2006 10:10:35 -0000 1.12
+++ common/lib/libprop/prop_object.c 7 Jun 2007 13:26:52 -0000
@@ -102,130 +102,28 @@ _prop_object_fini(struct _prop_object *p
}
/*
- * _prop_object_externalize_start_tag --
- * Append an XML-style start tag to the externalize buffer.
- */
-boolean_t
-_prop_object_externalize_start_tag(
- struct _prop_object_externalize_context *ctx, const char *tag)
-{
- unsigned int i;
-
- for (i = 0; i < ctx->poec_depth; i++) {
- if (_prop_object_externalize_append_char(ctx, '\t') == FALSE)
- return (FALSE);
- }
- if (_prop_object_externalize_append_char(ctx, '<') == FALSE ||
- _prop_object_externalize_append_cstring(ctx, tag) == FALSE ||
- _prop_object_externalize_append_char(ctx, '>') == FALSE)
- return (FALSE);
-
- return (TRUE);
-}
-
-/*
- * _prop_object_externalize_end_tag --
- * Append an XML-style end tag to the externalize buffer.
- */
-boolean_t
-_prop_object_externalize_end_tag(
- struct _prop_object_externalize_context *ctx, const char *tag)
-{
-
- if (_prop_object_externalize_append_char(ctx, '<') == FALSE ||
- _prop_object_externalize_append_char(ctx, '/') == FALSE ||
- _prop_object_externalize_append_cstring(ctx, tag) == FALSE ||
- _prop_object_externalize_append_char(ctx, '>') == FALSE ||
- _prop_object_externalize_append_char(ctx, '\n') == FALSE)
- return (FALSE);
-
- return (TRUE);
-}
-
-/*
- * _prop_object_externalize_empty_tag --
- * Append an XML-style empty tag to the externalize buffer.
- */
-boolean_t
-_prop_object_externalize_empty_tag(
- struct _prop_object_externalize_context *ctx, const char *tag)
-{
- unsigned int i;
-
- for (i = 0; i < ctx->poec_depth; i++) {
- if (_prop_object_externalize_append_char(ctx, '\t') == FALSE)
- return (FALSE);
- }
-
- if (_prop_object_externalize_append_char(ctx, '<') == FALSE ||
- _prop_object_externalize_append_cstring(ctx, tag) == FALSE ||
- _prop_object_externalize_append_char(ctx, '/') == FALSE ||
- _prop_object_externalize_append_char(ctx, '>') == FALSE ||
- _prop_object_externalize_append_char(ctx, '\n') == FALSE)
- return (FALSE);
-
- return (TRUE);
-}
-
-/*
- * _prop_object_externalize_append_cstring --
- * Append a C string to the externalize buffer.
- */
-boolean_t
-_prop_object_externalize_append_cstring(
- struct _prop_object_externalize_context *ctx, const char *cp)
-{
-
- while (*cp != '\0') {
- if (_prop_object_externalize_append_char(ctx,
- (unsigned char) *cp) == FALSE)
- return (FALSE);
- cp++;
- }
-
- return (TRUE);
-}
-
-/*
- * _prop_object_externalize_append_encoded_cstring --
- * Append an encoded C string to the externalize buffer.
+ * _prop_object_externalize_context_alloc --
+ * Allocate an externalize context.
*/
-boolean_t
-_prop_object_externalize_append_encoded_cstring(
- struct _prop_object_externalize_context *ctx, const char *cp)
+struct _prop_object_externalize_context *
+_prop_object_externalize_context_alloc(void)
{
+ struct _prop_object_externalize_context *ctx;
- while (*cp != '\0') {
- switch (*cp) {
- case '<':
- if (_prop_object_externalize_append_cstring(ctx,
- "<") == FALSE)
- return (FALSE);
- break;
- case '>':
- if (_prop_object_externalize_append_cstring(ctx,
- ">") == FALSE)
- return (FALSE);
- break;
- case '&':
- if (_prop_object_externalize_append_cstring(ctx,
- "&") == FALSE)
- return (FALSE);
- break;
- default:
- if (_prop_object_externalize_append_char(ctx,
- (unsigned char) *cp) == FALSE)
- return (FALSE);
- break;
+ ctx = _PROP_MALLOC(sizeof(*ctx), M_TEMP);
+ if (ctx != NULL) {
+ ctx->poec_buf = _PROP_MALLOC(_PROP_BUF_EXPAND, M_TEMP);
+ if (ctx->poec_buf == NULL) {
+ _PROP_FREE(ctx, M_TEMP);
+ return (NULL);
}
- cp++;
+ ctx->poec_len = 0;
+ ctx->poec_capacity = _PROP_BUF_EXPAND;
+ ctx->poec_depth = 0;
}
-
- return (TRUE);
+ return (ctx);
}
-#define BUF_EXPAND 256
-
/*
* _prop_object_externalize_append_char --
* Append a single character to the externalize buffer.
@@ -241,11 +139,11 @@ _prop_object_externalize_append_char(
if (ctx->poec_len == ctx->poec_capacity) {
char *cp = _PROP_REALLOC(ctx->poec_buf,
- ctx->poec_capacity + BUF_EXPAND,
+ ctx->poec_capacity + _PROP_BUF_EXPAND,
M_TEMP);
if (cp == NULL)
return (FALSE);
- ctx->poec_capacity = ctx->poec_capacity + BUF_EXPAND;
+ ctx->poec_capacity = ctx->poec_capacity + _PROP_BUF_EXPAND;
ctx->poec_buf = cp;
}
@@ -255,66 +153,25 @@ _prop_object_externalize_append_char(
}
/*
- * _prop_object_externalize_header --
- * Append the standard XML header to the externalize buffer.
- */
-boolean_t
-_prop_object_externalize_header(struct _prop_object_externalize_context *ctx)
-{
- static const char _plist_xml_header[] =
-"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
-"<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"
http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n";
-
- if (_prop_object_externalize_append_cstring(ctx,
- _plist_xml_header) == FALSE ||
- _prop_object_externalize_start_tag(ctx,
- "plist version=\"1.0\"") == FALSE ||
- _prop_object_externalize_append_char(ctx, '\n') == FALSE)
- return (FALSE);
-
- return (TRUE);
-}
-
-/*
- * _prop_object_externalize_footer --
- * Append the standard XML footer to the externalize buffer. This
- * also NUL-terminates the buffer.
+ * _prop_object_externalize_append_cstring --
+ * Append a C string to the externalize buffer.
*/
boolean_t
-_prop_object_externalize_footer(struct _prop_object_externalize_context *ctx)
+_prop_object_externalize_append_cstring(
+ struct _prop_object_externalize_context *ctx, const char *cp)
{
- if (_prop_object_externalize_end_tag(ctx, "plist") == FALSE ||
- _prop_object_externalize_append_char(ctx, '\0') == FALSE)
- return (FALSE);
+ while (*cp != '\0') {
+ if (_prop_object_externalize_append_char(ctx,
+ (unsigned char) *cp) == FALSE)
+ return (FALSE);
+ cp++;
+ }
return (TRUE);
}
/*
- * _prop_object_externalize_context_alloc --
- * Allocate an externalize context.
- */
-struct _prop_object_externalize_context *
-_prop_object_externalize_context_alloc(void)
-{
- struct _prop_object_externalize_context *ctx;
-
- ctx = _PROP_MALLOC(sizeof(*ctx), M_TEMP);
- if (ctx != NULL) {
- ctx->poec_buf = _PROP_MALLOC(BUF_EXPAND, M_TEMP);
- if (ctx->poec_buf == NULL) {
- _PROP_FREE(ctx, M_TEMP);
- return (NULL);
- }
- ctx->poec_len = 0;
- ctx->poec_capacity = BUF_EXPAND;
- ctx->poec_depth = 0;
- }
- return (ctx);
-}
-
-/*
* _prop_object_externalize_context_free --
* Free an externalize context.
*/
@@ -327,388 +184,6 @@ _prop_object_externalize_context_free(
_PROP_FREE(ctx, M_TEMP);
}
-/*
- * _prop_object_internalize_skip_comment --
- * Skip the body and end tag of a comment.
- */
-static boolean_t
-_prop_object_internalize_skip_comment(
- struct _prop_object_internalize_context *ctx)
-{
- const char *cp = ctx->poic_cp;
-
- while (!_PROP_EOF(*cp)) {
- if (cp[0] == '-' &&
- cp[1] == '-' &&
- cp[2] == '>') {
- ctx->poic_cp = cp + 3;
- return (TRUE);
- }
- cp++;
- }
-
- return (FALSE); /* ran out of buffer */
-}
-
-/*
- * _prop_object_internalize_find_tag --
- * Find the next tag in an XML stream. Optionally compare the found
- * tag to an expected tag name. State of the context is undefined
- * if this routine returns FALSE. Upon success, the context points
- * to the first octet after the tag.
- */
-boolean_t
-_prop_object_internalize_find_tag(struct _prop_object_internalize_context *ctx,
- const char *tag, _prop_tag_type_t type)
-{
- const char *cp;
- size_t taglen;
-
- if (tag != NULL)
- taglen = strlen(tag);
- else
- taglen = 0;
-
- start_over:
- cp = ctx->poic_cp;
-
- /*
- * Find the start of the tag.
- */
- while (_PROP_ISSPACE(*cp))
- cp++;
- if (_PROP_EOF(*cp))
- return (FALSE);
-
- if (*cp != '<')
- return (FALSE);
-
- ctx->poic_tag_start = cp++;
- if (_PROP_EOF(*cp))
- return (FALSE);
-
- if (*cp == '!') {
- if (cp[1] != '-' || cp[2] != '-')
- return (FALSE);
- /*
- * Comment block -- only allowed if we are allowed to
- * return a start tag.
- */
- if (type == _PROP_TAG_TYPE_END)
- return (FALSE);
- ctx->poic_cp = cp + 3;
- if (_prop_object_internalize_skip_comment(ctx) == FALSE)
- return (FALSE);
- goto start_over;
- }
-
- if (*cp == '/') {
- if (type != _PROP_TAG_TYPE_END &&
- type != _PROP_TAG_TYPE_EITHER)
- return (FALSE);
- cp++;
- if (_PROP_EOF(*cp))
- return (FALSE);
- ctx->poic_tag_type = _PROP_TAG_TYPE_END;
- } else {
- if (type != _PROP_TAG_TYPE_START &&
- type != _PROP_TAG_TYPE_EITHER)
- return (FALSE);
- ctx->poic_tag_type = _PROP_TAG_TYPE_START;
- }
-
- ctx->poic_tagname = cp;
-
- while (!_PROP_ISSPACE(*cp) && *cp != '/' && *cp != '>')
- cp++;
- if (_PROP_EOF(*cp))
- return (FALSE);
-
- ctx->poic_tagname_len = cp - ctx->poic_tagname;
-
- /* Make sure this is the tag we're looking for. */
- if (tag != NULL &&
- (taglen != ctx->poic_tagname_len ||
- memcmp(tag, ctx->poic_tagname, taglen) != 0))
- return (FALSE);
-
- /* Check for empty tag. */
- if (*cp == '/') {
- if (ctx->poic_tag_type != _PROP_TAG_TYPE_START)
- return(FALSE); /* only valid on start tags */
- ctx->poic_is_empty_element = TRUE;
- cp++;
- if (_PROP_EOF(*cp) || *cp != '>')
- return (FALSE);
- } else
- ctx->poic_is_empty_element = FALSE;
-
- /* Easy case of no arguments. */
- if (*cp == '>') {
- ctx->poic_tagattr = NULL;
- ctx->poic_tagattr_len = 0;
- ctx->poic_tagattrval = NULL;
- ctx->poic_tagattrval_len = 0;
- ctx->poic_cp = cp + 1;
- return (TRUE);
- }
-
- _PROP_ASSERT(!_PROP_EOF(*cp));
- cp++;
- if (_PROP_EOF(*cp))
- return (FALSE);
-
- while (_PROP_ISSPACE(*cp))
- cp++;
- if (_PROP_EOF(*cp))
- return (FALSE);
-
- ctx->poic_tagattr = cp;
-
- while (!_PROP_ISSPACE(*cp) && *cp != '=')
- cp++;
- if (_PROP_EOF(*cp))
- return (FALSE);
-
- ctx->poic_tagattr_len = cp - ctx->poic_tagattr;
-
- cp++;
- if (*cp != '\"')
- return (FALSE);
- cp++;
- if (_PROP_EOF(*cp))
- return (FALSE);
-
- ctx->poic_tagattrval = cp;
- while (*cp != '\"')
- cp++;
- if (_PROP_EOF(*cp))
- return (FALSE);
- ctx->poic_tagattrval_len = cp - ctx->poic_tagattrval;
-
- cp++;
- if (*cp != '>')
- return (FALSE);
-
- ctx->poic_cp = cp + 1;
- return (TRUE);
-}
-
-/*
- * _prop_object_internalize_decode_string --
- * Decode an encoded string.
- */
-boolean_t
-_prop_object_internalize_decode_string(
- struct _prop_object_internalize_context *ctx,
- char *target, size_t targsize, size_t *sizep,
- const char **cpp)
-{
- const char *src;
- size_t tarindex;
- char c;
-
- tarindex = 0;
- src = ctx->poic_cp;
-
- for (;;) {
- if (_PROP_EOF(*src))
- return (FALSE);
- if (*src == '<') {
- break;
- }
-
- if ((c = *src) == '&') {
- if (src[1] == 'a' &&
- src[2] == 'm' &&
- src[3] == 'p' &&
- src[4] == ';') {
- c = '&';
- src += 5;
- } else if (src[1] == 'l' &&
- src[2] == 't' &&
- src[3] == ';') {
- c = '<';
- src += 4;
- } else if (src[1] == 'g' &&
- src[2] == 't' &&
- src[3] == ';') {
- c = '>';
- src += 4;
- } else if (src[1] == 'a' &&
- src[2] == 'p' &&
- src[3] == 'o' &&
- src[4] == 's' &&
- src[5] == ';') {
- c = '\'';
- src += 6;
- } else if (src[1] == 'q' &&
- src[2] == 'u' &&
- src[3] == 'o' &&
- src[4] == 't' &&
- src[5] == ';') {
- c = '\"';
- src += 6;
- } else
- return (FALSE);
- } else
- src++;
- if (target) {
- if (tarindex >= targsize)
- return (FALSE);
- target[tarindex] = c;
- }
- tarindex++;
- }
-
- _PROP_ASSERT(*src == '<');
- if (sizep != NULL)
- *sizep = tarindex;
- if (cpp != NULL)
- *cpp = src;
-
- return (TRUE);
-}
-
-/*
- * _prop_object_internalize_match --
- * Returns true if the two character streams match.
- */
-boolean_t
-_prop_object_internalize_match(const char *str1, size_t len1,
- const char *str2, size_t len2)
-{
-
- return (len1 == len2 && memcmp(str1, str2, len1) == 0);
-}
-
-#define INTERNALIZER(t, f) \
-{ t, sizeof(t) - 1, f }
-
-static const struct _prop_object_internalizer {
- const char *poi_tag;
- size_t poi_taglen;
- prop_object_t (*poi_intern)(
- struct _prop_object_internalize_context *);
-} _prop_object_internalizer_table[] = {
- INTERNALIZER("array", _prop_array_internalize),
-
- INTERNALIZER("true", _prop_bool_internalize),
- INTERNALIZER("false", _prop_bool_internalize),
-
- INTERNALIZER("data", _prop_data_internalize),
-
- INTERNALIZER("dict", _prop_dictionary_internalize),
-
- INTERNALIZER("integer", _prop_number_internalize),
-
- INTERNALIZER("string", _prop_string_internalize),
-
- { 0, 0, NULL }
-};
-
-#undef INTERNALIZER
-
-/*
- * _prop_object_internalize_by_tag --
- * Determine the object type from the tag in the context and
- * internalize it.
- */
-prop_object_t
-_prop_object_internalize_by_tag(struct _prop_object_internalize_context *ctx)
-{
- const struct _prop_object_internalizer *poi;
-
- for (poi = _prop_object_internalizer_table;
- poi->poi_tag != NULL; poi++) {
- if (_prop_object_internalize_match(ctx->poic_tagname,
- ctx->poic_tagname_len,
- poi->poi_tag,
- poi->poi_taglen))
- return ((*poi->poi_intern)(ctx));
- }
-
- return (NULL);
-}
-
-/*
- * _prop_object_internalize_context_alloc --
- * Allocate an internalize context.
- */
-struct _prop_object_internalize_context *
-_prop_object_internalize_context_alloc(const char *xml)
-{
- struct _prop_object_internalize_context *ctx;
-
- ctx = _PROP_MALLOC(sizeof(struct _prop_object_internalize_context),
- M_TEMP);
- if (ctx == NULL)
- return (NULL);
-
- ctx->poic_xml = ctx->poic_cp = xml;
-
- /*
- * Skip any whitespace and XML preamble stuff that we don't
- * know about / care about.
- */
- for (;;) {
- while (_PROP_ISSPACE(*xml))
- xml++;
- if (_PROP_EOF(*xml) || *xml != '<')
- goto bad;
-
-#define MATCH(str) (memcmp(&xml[1], str, sizeof(str) - 1) == 0)
-
- /*
- * Skip over the XML preamble that Apple XML property
- * lists usually include at the top of the file.
- */
- if (MATCH("?xml ") ||
- MATCH("!DOCTYPE plist")) {
- while (*xml != '>' && !_PROP_EOF(*xml))
- xml++;
- if (_PROP_EOF(*xml))
- goto bad;
- xml++; /* advance past the '>' */
- continue;
- }
-
- if (MATCH("<!--")) {
- ctx->poic_cp = xml + 4;
- if (_prop_object_internalize_skip_comment(ctx) == FALSE)
- goto bad;
- xml = ctx->poic_cp;
- continue;
- }
-
-#undef MATCH
-
- /*
- * We don't think we should skip it, so let's hope we can
- * parse it.
- */
- break;
- }
-
- ctx->poic_cp = xml;
- return (ctx);
- bad:
- _PROP_FREE(ctx, M_TEMP);
- return (NULL);
-}
-
-/*
- * _prop_object_internalize_context_free --
- * Free an internalize context.
- */
-void
-_prop_object_internalize_context_free(
- struct _prop_object_internalize_context *ctx)
-{
-
- _PROP_FREE(ctx, M_TEMP);
-}
-
#if !defined(_KERNEL) && !defined(_STANDALONE)
/*
* _prop_object_externalize_file_dirname --
Index: common/lib/libprop/prop_object_impl.h
===================================================================
RCS file: /cvsroot/src/common/lib/libprop/prop_object_impl.h,v
retrieving revision 1.12
diff -d -p -u -r1.12 prop_object_impl.h
--- common/lib/libprop/prop_object_impl.h 12 Mar 2007 18:18:39 -0000 1.12
+++ common/lib/libprop/prop_object_impl.h 7 Jun 2007 13:26:54 -0000
@@ -45,6 +45,13 @@
#include <inttypes.h>
#endif
+#include "prop_system_impl.h"
+
+_PROP_MALLOC_DECLARE(M_PROP_ARRAY)
+_PROP_MALLOC_DECLARE(M_PROP_DATA)
+_PROP_MALLOC_DECLARE(M_PROP_DICT)
+_PROP_MALLOC_DECLARE(M_PROP_STRING)
+
struct _prop_object_externalize_context {
char * poec_buf; /* string buffer */
size_t poec_capacity; /* capacity of buffer */
@@ -52,92 +59,18 @@ struct _prop_object_externalize_context
unsigned int poec_depth; /* nesting depth */
};
-boolean_t _prop_object_externalize_start_tag(
- struct _prop_object_externalize_context *,
- const char *);
-boolean_t _prop_object_externalize_end_tag(
- struct _prop_object_externalize_context *,
- const char *);
-boolean_t _prop_object_externalize_empty_tag(
- struct _prop_object_externalize_context *,
- const char *);
boolean_t _prop_object_externalize_append_cstring(
struct _prop_object_externalize_context *,
const char *);
-boolean_t _prop_object_externalize_append_encoded_cstring(
- struct _prop_object_externalize_context *,
- const char *);
boolean_t _prop_object_externalize_append_char(
struct _prop_object_externalize_context *,
unsigned char);
-boolean_t _prop_object_externalize_header(
- struct _prop_object_externalize_context *);
-boolean_t _prop_object_externalize_footer(
- struct _prop_object_externalize_context *);
struct _prop_object_externalize_context *
_prop_object_externalize_context_alloc(void);
void _prop_object_externalize_context_free(
struct _prop_object_externalize_context *);
-typedef enum {
- _PROP_TAG_TYPE_START, /* e.g. <dict> */
- _PROP_TAG_TYPE_END, /* e.g. </dict> */
- _PROP_TAG_TYPE_EITHER
-} _prop_tag_type_t;
-
-struct _prop_object_internalize_context {
- const char *poic_xml;
- const char *poic_cp;
-
- const char *poic_tag_start;
-
- const char *poic_tagname;
- size_t poic_tagname_len;
- const char *poic_tagattr;
- size_t poic_tagattr_len;
- const char *poic_tagattrval;
- size_t poic_tagattrval_len;
-
- boolean_t poic_is_empty_element;
- _prop_tag_type_t poic_tag_type;
-};
-
-#define _PROP_EOF(c) ((c) == '\0')
-#define _PROP_ISSPACE(c) \
- ((c) == ' ' || (c) == '\t' || (c) == '\n' || _PROP_EOF(c))
-
-#define _PROP_TAG_MATCH(ctx, t) \
- _prop_object_internalize_match((ctx)->poic_tagname, \
- (ctx)->poic_tagname_len, \
- (t), strlen(t))
-
-#define _PROP_TAGATTR_MATCH(ctx, a) \
- _prop_object_internalize_match((ctx)->poic_tagattr, \
- (ctx)->poic_tagattr_len, \
- (a), strlen(a))
-
-#define _PROP_TAGATTRVAL_MATCH(ctx, a) \
- _prop_object_internalize_match((ctx)->poic_tagattrval, \
- (ctx)->poic_tagattrval_len,\
- (a), strlen(a))
-
-boolean_t _prop_object_internalize_find_tag(
- struct _prop_object_internalize_context *,
- const char *, _prop_tag_type_t);
-boolean_t _prop_object_internalize_match(const char *, size_t,
- const char *, size_t);
-prop_object_t _prop_object_internalize_by_tag(
- struct _prop_object_internalize_context *);
-boolean_t _prop_object_internalize_decode_string(
- struct _prop_object_internalize_context *,
- char *, size_t, size_t *, const char **);
-
-struct _prop_object_internalize_context *
- _prop_object_internalize_context_alloc(const char *);
-void _prop_object_internalize_context_free(
- struct _prop_object_internalize_context *);
-
#if !defined(_KERNEL) && !defined(_STANDALONE)
boolean_t _prop_object_externalize_write_file(const char *,
const char *, size_t);
@@ -153,26 +86,9 @@ void _prop_object_internalize_unmap_fil
struct _prop_object_internalize_mapped_file *);
#endif /* !_KERNEL && !_STANDALONE */
- /* These are here because they're required by shared code. */
-prop_object_t _prop_array_internalize(
- struct _prop_object_internalize_context *);
-prop_object_t _prop_bool_internalize(
- struct _prop_object_internalize_context *);
-prop_object_t _prop_data_internalize(
- struct _prop_object_internalize_context *);
-prop_object_t _prop_dictionary_internalize(
- struct _prop_object_internalize_context *);
-prop_object_t _prop_number_internalize(
- struct _prop_object_internalize_context *);
-prop_object_t _prop_string_internalize(
- struct _prop_object_internalize_context *);
-
struct _prop_object_type {
uint32_t pot_type; /* type indicator */
void (*pot_free)(void *); /* func to free object */
- boolean_t (*pot_extern) /* func to externalize object */
- (struct _prop_object_externalize_context *,
- void *);
boolean_t (*pot_equals) /* func to test quality */
(void *, void *);
};
@@ -193,166 +109,81 @@ struct _prop_object_iterator {
uint32_t pi_version;
};
-#if defined(_KERNEL)
-
-/*
- * proplib in the kernel...
- */
-
-#include <sys/param.h>
-#include <sys/malloc.h>
-#include <sys/pool.h>
-#include <sys/systm.h>
-#include <sys/lock.h>
-
-#define _PROP_ASSERT(x) KASSERT(x)
-
-#define _PROP_MALLOC(s, t) malloc((s), (t), M_WAITOK)
-#define _PROP_CALLOC(s, t) malloc((s), (t), M_WAITOK | M_ZERO)
-#define _PROP_REALLOC(v, s, t) realloc((v), (s), (t), M_WAITOK)
-#define _PROP_FREE(v, t) free((v), (t))
-
-#define _PROP_POOL_GET(p) pool_get(&(p), PR_WAITOK)
-#define _PROP_POOL_PUT(p, v) pool_put(&(p), (v))
-
-#define _PROP_POOL_INIT(p, s, d) \
- POOL_INIT(p, s, 0, 0, 0, d, &pool_allocator_nointr, IPL_NONE);
-
-#define _PROP_MALLOC_DEFINE(t, s, l) \
- MALLOC_DEFINE(t, s, l);
-
-#define _PROP_MUTEX_DECL_STATIC(x) \
- static struct simplelock x = SIMPLELOCK_INITIALIZER;
-#define _PROP_MUTEX_LOCK(x) simple_lock(&(x))
-#define _PROP_MUTEX_UNLOCK(x) simple_unlock(&(x))
-
-#define _PROP_RWLOCK_DECL(x) struct lock x ;
-#define _PROP_RWLOCK_INIT(x) lockinit(&(x), PZERO, "proprwlk", 0, 0)
-#define _PROP_RWLOCK_RDLOCK(x) lockmgr(&(x), LK_SHARED, NULL)
-#define _PROP_RWLOCK_WRLOCK(x) lockmgr(&(x), LK_EXCLUSIVE, NULL)
-#define _PROP_RWLOCK_UNLOCK(x) lockmgr(&(x), LK_RELEASE, NULL)
-#define _PROP_RWLOCK_DESTROY(x) lockmgr(&(x), LK_DRAIN, NULL)
-
-#elif defined(_STANDALONE)
-
-/*
- * proplib in a standalone environment...
- */
-
-#include <lib/libsa/stand.h>
-
-void * _prop_standalone_calloc(size_t);
-void * _prop_standalone_realloc(void *, size_t);
-
-#define _PROP_ASSERT(x) /* nothing */
-
-#define _PROP_MALLOC(s, t) alloc((s))
-#define _PROP_CALLOC(s, t) _prop_standalone_calloc((s))
-#define _PROP_REALLOC(v, s, t) _prop_standalone_realloc((v), (s))
-#define _PROP_FREE(v, t) dealloc((v), 0) /* XXX */
-
-#define _PROP_POOL_GET(p) alloc((p))
-#define _PROP_POOL_PUT(p, v) dealloc((v), (p))
-
-#define _PROP_POOL_INIT(p, s, d) static const size_t p = s;
-
-#define _PROP_MALLOC_DEFINE(t, s, l) /* nothing */
-
-#define _PROP_MUTEX_DECL_STATIC(x) /* nothing */
-#define _PROP_MUTEX_LOCK(x) /* nothing */
-#define _PROP_MUTEX_UNLOCK(x) /* nothing */
-
-#define _PROP_RWLOCK_DECL(x) /* nothing */
-#define _PROP_RWLOCK_INIT(x) /* nothing */
-#define _PROP_RWLOCK_RDLOCK(x) /* nothing */
-#define _PROP_RWLOCK_WRLOCK(x) /* nothing */
-#define _PROP_RWLOCK_UNLOCK(x) /* nothing */
-#define _PROP_RWLOCK_DESTROY(x) /* nothing */
-
+#ifdef _STANDALONE
+#define _PROP_BUF_EXPAND 32
#else
+#define _PROP_BUF_EXPAND 256
+#endif
-/*
- * proplib in user space...
- */
+#define _PROP_PDK_MAXKEY 128
-#include <assert.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
+struct _prop_array {
+ struct _prop_object pa_obj;
+ _PROP_RWLOCK_DECL(pa_rwlock)
+ prop_object_t * pa_array;
+ unsigned int pa_capacity;
+ unsigned int pa_count;
+ int pa_flags;
-#define _PROP_ASSERT(x) /*LINTED*/assert(x)
+ uint32_t pa_version;
+};
-#define _PROP_MALLOC(s, t) malloc((s))
-#define _PROP_CALLOC(s, t) calloc(1, (s))
-#define _PROP_REALLOC(v, s, t) realloc((v), (s))
-#define _PROP_FREE(v, t) free((v))
+#define PA_F_IMMUTABLE 0x01 /* array is immutable */
-#define _PROP_POOL_GET(p) malloc((p))
-#define _PROP_POOL_PUT(p, v) free((v))
+struct _prop_dictionary {
+ struct _prop_object pd_obj;
+ _PROP_RWLOCK_DECL(pd_rwlock)
+ struct _prop_dict_entry *pd_array;
+ unsigned int pd_capacity;
+ unsigned int pd_count;
+ int pd_flags;
-#define _PROP_POOL_INIT(p, s, d) static const size_t p = s;
+ uint32_t pd_version;
+};
-#define _PROP_MALLOC_DEFINE(t, s, l) /* nothing */
+#define PD_F_IMMUTABLE 0x01 /* dictionary is immutable */
-#if defined(__NetBSD__) && defined(_LIBPROP)
-/*
- * Use the same mechanism as libc; we get pthread mutexes for threaded
- * programs and do-nothing stubs for non-threaded programs.
- */
-#include "reentrant.h"
-#define _PROP_MUTEX_DECL_STATIC(x) static mutex_t x = MUTEX_INITIALIZER;
-#define _PROP_MUTEX_LOCK(x) mutex_lock(&(x))
-#define _PROP_MUTEX_UNLOCK(x) mutex_unlock(&(x))
+struct _prop_data {
+ struct _prop_object pd_obj;
+ union {
+ void * pdu_mutable;
+ const void * pdu_immutable;
+ } pd_un;
+#define pd_mutable pd_un.pdu_mutable
+#define pd_immutable pd_un.pdu_immutable
+ size_t pd_size;
+ int pd_flags;
+};
-#define _PROP_RWLOCK_DECL(x) rwlock_t x ;
-#define _PROP_RWLOCK_INIT(x) rwlock_init(&(x), NULL)
-#define _PROP_RWLOCK_RDLOCK(x) rwlock_rdlock(&(x))
-#define _PROP_RWLOCK_WRLOCK(x) rwlock_wrlock(&(x))
-#define _PROP_RWLOCK_UNLOCK(x) rwlock_unlock(&(x))
-#define _PROP_RWLOCK_DESTROY(x) rwlock_destroy(&(x))
-#elif defined(HAVE_NBTOOL_CONFIG_H)
-/*
- * None of NetBSD's build tools are multi-threaded.
- */
-#define _PROP_MUTEX_DECL_STATIC(x) /* nothing */
-#define _PROP_MUTEX_LOCK(x) /* nothing */
-#define _PROP_MUTEX_UNLOCK(x) /* nothing */
+#define PD_F_NOCOPY 0x01
-#define _PROP_RWLOCK_DECL(x) /* nothing */
-#define _PROP_RWLOCK_INIT(x) /* nothing */
-#define _PROP_RWLOCK_RDLOCK(x) /* nothing */
-#define _PROP_RWLOCK_WRLOCK(x) /* nothing */
-#define _PROP_RWLOCK_UNLOCK(x) /* nothing */
-#define _PROP_RWLOCK_DESTROY(x) /* nothing */
-#else
-/*
- * Use pthread mutexes everywhere else.
- */
-#include <pthread.h>
-#define _PROP_MUTEX_DECL_STATIC(x) \
- static pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER;
-#define _PROP_MUTEX_LOCK(x) pthread_mutex_lock(&(x))
-#define _PROP_MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x))
+struct _prop_number_value {
+ union {
+ int64_t pnu_signed;
+ uint64_t pnu_unsigned;
+ } pnv_un;
+#define pnv_signed pnv_un.pnu_signed
+#define pnv_unsigned pnv_un.pnu_unsigned
+ unsigned int pnv_is_unsigned :1,
+ :31;
+};
-#define _PROP_RWLOCK_DECL(x) pthread_rwlock_t x ;
-#define _PROP_RWLOCK_INIT(x) pthread_rwlock_init(&(x), NULL)
-#define _PROP_RWLOCK_RDLOCK(x) pthread_rwlock_rdlock(&(x))
-#define _PROP_RWLOCK_WRLOCK(x) pthread_rwlock_wrlock(&(x))
-#define _PROP_RWLOCK_UNLOCK(x) pthread_rwlock_unlock(&(x))
-#define _PROP_RWLOCK_DESTROY(x) pthread_rwlock_destroy(&(x))
-#endif
+struct _prop_string {
+ struct _prop_object ps_obj;
+ union {
+ char * psu_mutable;
+ const char * psu_immutable;
+ } ps_un;
+#define ps_mutable ps_un.psu_mutable
+#define ps_immutable ps_un.psu_immutable
+ size_t ps_size; /* not including \0 */
+ int ps_flags;
+};
-#endif /* _KERNEL */
+#define PS_F_NOCOPY 0x01
-/*
- * Language features.
- */
-#if defined(__NetBSD__)
-#include <sys/cdefs.h>
-#define _PROP_ARG_UNUSED __unused
-#else
-#define _PROP_ARG_UNUSED /* delete */
-#endif /* __NetBSD__ */
+struct _prop_data *_prop_data_alloc(void);
+struct _prop_number *_prop_number_alloc(const struct _prop_number_value *);
+struct _prop_string *_prop_string_alloc(void);
#endif /* _PROPLIB_PROP_OBJECT_IMPL_H_ */
Index: common/lib/libprop/prop_scn.c
===================================================================
RCS file: common/lib/libprop/prop_scn.c
diff -N common/lib/libprop/prop_scn.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ common/lib/libprop/prop_scn.c 7 Jun 2007 13:27:02 -0000
@@ -0,0 +1,1672 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 2007 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jachym Holecek <
[email protected]>.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 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.
+ */
+
+#include <sys/queue.h>
+#include <sys/param.h> /* roundup() */
+
+#if defined(_KERNEL)
+#include <sys/systm.h>
+#elif defined(_STANDALONE)
+#include <lib/libkern/libkern.h>
+#else
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#if defined(DEBUG)
+#include <stdarg.h>
+#include <stdio.h>
+#endif
+#include <stdlib.h>
+#endif
+
+#include <prop/proplib.h>
+#include "prop_object_impl.h"
+#include "prop_codec_impl.h"
+
+
+#if defined(_STANDALONE)
+#define BUFINCR 16
+#else
+#define BUFINCR 128
+#endif
+
+#if !defined(__UNCONST)
+#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
+#endif
+
+/*
+ * This needs to go via a macro -- even if verbose()'s body would be empty
+ * ifndef DEBUG, GCC still isn't smart enough to eliminate calls to funcs
+ * that only exist if DEBUG. And we don't want to clutter the code with
+ * preprocessor conditionals.
+ */
+#if defined(DEBUG)
+#define VERBOSE(s, ...) verbose(s "\n", ## __VA_ARGS__)
+#else
+#define VERBOSE(s, ...) /* silence */
+#endif
+
+/* Ewww, depolymerise function names. */
+#define poec _prop_object_externalize_context
+#define poec_create _prop_object_externalize_context_alloc
+#define poec_append _prop_object_externalize_append_cstring
+#define poec_push _prop_object_externalize_append_char
+#define poec_destroy _prop_object_externalize_context_free
+#define prop_keysym_str prop_dictionary_keysym_cstring_nocopy
+
+#define _TK_COMPOUND_VALUES \
+ TK_ARRAYO: \
+ case TK_DICTO
+
+typedef enum {
+ /* Self representing. */
+ TK_FIRST = 0, /* So that memset(0) DTRT. */
+ TK_ARRAYC,
+ TK_ARRAYO,
+ TK_DATA,
+ TK_DICTC,
+ TK_DICTO,
+ TK_WHITE,
+ TK_LAST,
+
+ /* Values. */
+ TK_STRING,
+ TK_SINT64,
+ TK_SYMBOL,
+ TK_UINT64
+} token_type_t;
+
+#define _PA_TOKEN_LAST TK_UINT64
+#define _PA_TOKEN_NAMES \
+ "FIRST", "ARRAYC", "ARRAYO", "DATA", "DICTC", "DICTO", "WHITE", \
+ "LAST", "STRING", "SINT64", "SYMBOL", "UINT64",
+
+typedef enum {
+ SC_FIRST = 0,
+ SC_WHITE,
+ SC_SINT64,
+ SC_UINT64,
+ SC_QUOTED,
+ SC_SYMBOL,
+ SC_TOPLEVEL,
+ SC_ERROR,
+ SC_BASE64_APPEND,
+ SC_BASE64_MAYBE_NEXT,
+ SC_BASE64_NEXT,
+ SC_BASE64_CLOSE,
+ SC_STRING_APPEND,
+ SC_STRING_MAYBE_NEXT,
+ SC_STRING_CONCAT,
+ SC_STRING_CLOSE,
+ SC_COMMENT
+} scan_state_t;
+
+#define _SC_STATE_LAST SC_COMMENT
+#define _SC_STATE_NAMES \
+ "FIRST", "WHITE", "SINT64", "UINT64", "QUOTED", "SYMBOL", "TOPLEVEL", \
+ "ERROR", "BASE64_APPEND", "BASE64_MAYBE_NEXT", "BASE64_NEXT", \
+ "SC_BASE64_CLOSE", "STRING_APPEND", "STRING_MAYBE_NEXT", \
+ "STRING_CONCAT", "STRING_CLOSE", "COMMENT"
+
+typedef enum {
+ PA_TOPLEVEL = 0,
+ PA_ARRAY,
+ PA_DICTIONARY,
+ PA_ERROR,
+ PA_HOME,
+ PA_OBJECT
+} parse_state_t;
+
+#define _PA_STATE_LAST PA_OBJECT
+#define _PA_STATE_NAMES \
+ "TOPLEVEL", "ARRAY", "DICTIONARY", "ERROR", "HOME", "OBJECT"
+
+union value {
+ char *val_string;
+ uint64_t val_unsigned;
+ int64_t val_signed;
+ struct {
+ const u_char *vd_buf;
+ size_t vd_len;
+ } val_data;
+};
+
+/* Scanner constructs tokens and enqueues them to parser. */
+struct token {
+ SIMPLEQ_ENTRY(token) tok_link;
+ token_type_t tok_type;
+
+#if !defined(_STANDALONE)
+ size_t tok_pos_line;
+ size_t tok_pos_col;
+#endif
+ union value tok_value;
+#define tok_string tok_value.val_string
+#define tok_signed tok_value.val_signed
+#define tok_unsigned tok_value.val_unsigned
+#define tok_data_buf tok_value.val_data.vd_buf
+#define tok_data_len tok_value.val_data.vd_len
+};
+
+/* Stack for nested objects, entries relinked to consq on completion. */
+struct frame {
+ SIMPLEQ_ENTRY(frame) se_link; /* Stack entry link. */
+ prop_object_t se_object; /* Compound object. */
+
+ /* Dec: key to parent dict, Enc: next object from parent. */
+ union {
+ const char *un_symbol;
+ prop_object_iterator_t un_iter;
+ } se_un;
+#define se_symbol se_un.un_symbol
+#define se_iter se_un.un_iter
+};
+
+SIMPLEQ_HEAD(stack, frame);
+
+struct parser {
+ /* Incoming tokens, operation stack, list of constructed objects. */
+ SIMPLEQ_HEAD(, token) pa_tokens; /* FIFO */
+ struct stack pa_stack; /* LIFO */
+ struct stack pa_consq; /* FIFO */
+
+ /* Store parser state across calls. */
+ parse_state_t pa_state;
+ parse_state_t pa_prev;
+ parse_state_t pa_last;
+
+ /* Store scanner state across calls. */
+ scan_state_t sc_state; /* Current state. */
+ scan_state_t sc_prev; /* State at start of this cycle. */
+ scan_state_t sc_last; /* Last value of prev != state. */
+
+#if !defined(_STANDALONE)
+ /* Position in input stream. */
+ size_t sc_pos_line;
+ size_t sc_pos_col;
+#endif
+ /* Scanner internalization buffer. */
+ u_char *sc_string;
+ size_t sc_strcur;
+ size_t sc_strlen;
+
+ /* Base64 decoder. */
+ size_t sc_base64_size; /* in bits */
+};
+
+/* Base64 code space (plus '='). */
+static const char base64abc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopq"
+ "rstuvwxyz0123456789+/";
+
+
+
+#if defined(_KERNEL) || defined(_STANDALONE)
+static char *
+strdup(const char *s)
+{
+ char *p;
+ size_t l;
+
+ l = strlen(s) + 1;
+ p = _PROP_MALLOC(l, M_TEMP);
+
+ return (memcpy(p, s, l));
+}
+
+static int
+isprint(int c)
+{
+ return (c >= ' ' && c <= '~');
+}
+#endif /* _KERNEL || _STANDALONE */
+
+static boolean_t
+stroneof(const char *s, const char *t[])
+{
+ int i;
+
+ for (i = 0; t[i]; i++)
+ if (strcasecmp(s, t[i]) == 0)
+ return (TRUE);
+ return (FALSE);
+}
+
+#if defined(DEBUG)
+
+static void
+verbose(const char *fmt, ...)
+{
+ static FILE *tracefile = NULL;
+ char *s;
+ va_list ap;
+
+ /* XXX locking */
+ if (tracefile == NULL) {
+ s = getenv("PROPLIB_SCN_TRACEFILE");
+ if (s == NULL)
+ s = "__prop_scn.out";
+
+ tracefile = fopen(s, "w");
+ if (tracefile == NULL)
+ abort();
+ }
+
+ va_start(ap, fmt);
+ vfprintf(tracefile, fmt, ap);
+ va_end(ap);
+}
+
+static const char *
+scanner_quote_char(u_char c)
+{
+ static char buf[8]; /* 'c', '\n', 0xab */
+ u_char d = 0;
+
+ switch (c) {
+ case '\f': d = 'f'; break;
+ case '\n': d = 'n'; break;
+ case '\r': d = 'r'; break;
+ case '\t': d = 't'; break;
+ case '\v': d = 'v'; break;
+ }
+ if (d) {
+ sprintf(buf, "'\\%c'", d);
+ return (buf);
+ }
+
+ if (isprint(c))
+ sprintf(buf, "'%c'", (char)c);
+ else
+ sprintf(buf, "0x%02x", (u_int)c);
+ return (buf);
+}
+
+static const char *
+scanner_state_name(scan_state_t n)
+{
+ static const char *const names[] = { _SC_STATE_NAMES };
+ static int idx = 0; /* XXX hack, printf */
+ static char buf[5][32];
+
+ if (n < 0 || n > _SC_STATE_LAST) {
+ if (++idx == 5)
+ idx = 0;
+
+ snprintf(buf[idx], 32, "<wrong %d>", n);
+ return (buf[idx]);
+ }
+
+ return (names[n]);
+}
+
+static const char *
+parser_state_name(parse_state_t n)
+{
+ static const char *const names[] = { _PA_STATE_NAMES };
+ static int idx = 0; /* XXX hack, printf */
+ static char buf[5][32];
+
+ if (++idx == 5)
+ idx = 0;
+
+ if (n < 0 || n > _PA_STATE_LAST) {
+ snprintf(buf[idx], 32, "<wrong %d>", n);
+ return (buf[idx]);
+ }
+
+ return (names[n]);
+}
+
+static const char *
+parser_token_name(token_type_t n)
+{
+ static const char *const names[] = { _PA_TOKEN_NAMES };
+
+ if (n < 0 || n > _PA_TOKEN_LAST)
+ return ("<wrong token>");
+ return (names[n]);
+}
+
+static const char *
+parser_token_desc(struct token *t)
+{
+ static char buf[32];
+ static const size_t sof = sizeof(buf);
+ const char *s;
+ int n = t->tok_type;
+
+ s = parser_token_name(n);
+
+ switch (n) {
+ case TK_SYMBOL:
+ snprintf(buf, sof, "%s '%s'", s, t->tok_string);
+ return (buf);
+ case TK_SINT64:
+ snprintf(buf, sof, "%s %"PRId64, s, t->tok_signed);
+ return (buf);
+ case TK_STRING:
+ snprintf(buf, sof, "%s \"%s\"", s, t->tok_string);
+ return (buf);
+ case TK_UINT64:
+ snprintf(buf, sof, "%s #%"PRIx64, s, t->tok_unsigned);
+ return (buf);
+ case TK_DATA:
+ snprintf(buf, sof, "%s %zdB", s, t->tok_data_len);
+ return (buf);
+ }
+ return (s);
+}
+
+#endif /* PROP_SCN_DEBUG */
+
+static prop_string_t
+prop_scn_create_string(struct token *t)
+{
+ prop_string_t ps;
+ char *str = t->tok_string;
+
+ ps = _prop_string_alloc();
+ if (ps == NULL)
+ return (NULL);
+
+ ps->ps_mutable = str;
+ ps->ps_size = strlen(str);
+
+ return (ps);
+}
+
+static prop_number_t
+prop_scn_create_uint(struct token *t)
+{
+ return (prop_number_create_unsigned_integer(t->tok_unsigned));
+}
+
+static prop_number_t
+prop_scn_create_sint(struct token *t)
+{
+ return (prop_number_create_integer(t->tok_signed));
+}
+
+static boolean_t
+scanner_ensure_strlen(struct parser *pa)
+{
+ void *b;
+
+ /* Enough room for <char, '\0'> or base64 triplet. */
+ if ((pa->sc_strlen - pa->sc_strcur) < 3) {
+ b = _PROP_REALLOC(pa->sc_string, pa->sc_strlen + BUFINCR,
+ M_TEMP);
+ if (b == NULL) {
+ VERBOSE("scanner: ENOMEM internalization buffer");
+ return (TRUE);
+ }
+
+ pa->sc_string = b;
+ pa->sc_strlen += BUFINCR;
+ }
+
+ /* No error == success. */
+ return (FALSE);
+}
+
+static struct token *
+parser_token_put(struct parser *pa, token_type_t tok)
+{
+ struct token *t;
+
+ t = _PROP_MALLOC(sizeof(struct token), M_TEMP);
+ if (t == NULL) {
+ VERBOSE(" parser: ENOMEM token %s", parser_token_name(tok));
+ return (NULL);
+ }
+
+ memset(t, 0, sizeof(struct token));
+ t->tok_type = tok;
+
+#if !defined(_STANDALONE)
+ t->tok_pos_line = pa->sc_pos_line;
+ t->tok_pos_col = pa->sc_pos_col;
+#endif
+
+ SIMPLEQ_INSERT_TAIL(&pa->pa_tokens, t, tok_link);
+ return (t);
+}
+
+static void
+parser_token_free(struct token *t, boolean_t force)
+{
+ /* Normally, tok_string is donated upwards, not duplicated. */
+ if (force && (t->tok_type == TK_STRING || t->tok_type == TK_SYMBOL) &&
+ t->tok_string != NULL)
+ _PROP_FREE(t->tok_string, M_TEMP);
+ _PROP_FREE(t, M_TEMP);
+}
+
+#define SC_ARROW_P(src, dst) (pa->sc_prev == (src) && pa->sc_state == (dst))
+#define SC_CYCLE_P(s) SC_ARROW_P(s, s)
+
+static u_char
+scanner_base64_decode(u_char c)
+{
+ const char *s;
+
+ if (c == '=')
+ return (0);
+
+ s = strchr(base64abc, (int)(u_int)c);
+ _PROP_ASSERT(s);
+
+ return ((u_char)(s - base64abc));
+}
+
+static int
+prop_scanner_exec(struct parser *pa, const u_char *input, size_t length)
+{
+ const u_char *p = input;
+ const u_char *pe = input + length;
+ struct token *t;
+ boolean_t keepchar;
+ u_char c;
+
+ if (input == NULL || length == 0) {
+ if (parser_token_put(pa, TK_LAST) == NULL)
+ return (ENOMEM);
+ return (0);
+ }
+
+ advance:
+ if (p == pe)
+ return (0);
+ c = *p++;
+
+ dispatch:
+ keepchar = TRUE; /* for callcc */
+
+ switch (pa->sc_state) {
+ case SC_FIRST:
+ /* Force transition. */
+ pa->sc_state = SC_TOPLEVEL;
+ goto callcc;
+
+ case SC_TOPLEVEL:
+ switch (c) {
+ case '#':
+ pa->sc_state = SC_UINT64;
+ goto callnext;
+ case '{':
+ if (parser_token_put(pa, TK_DICTO) == NULL)
+ return (ENOMEM);
+ goto callnext;
+ case '}':
+ if (parser_token_put(pa, TK_DICTC) == NULL)
+ return (ENOMEM);
+ goto callnext;
+ case '[':
+ if (parser_token_put(pa, TK_ARRAYO) == NULL)
+ return (ENOMEM);
+ goto callnext;
+ case ']':
+ if (parser_token_put(pa, TK_ARRAYC) == NULL)
+ return (ENOMEM);
+ goto callnext;
+ case '"':
+ /* Opening quote, clear from edge action. */
+ pa->sc_state = SC_STRING_APPEND;
+ goto callnext;
+ case ';':
+ pa->sc_state = SC_COMMENT;
+ goto callnext;
+ case ':':
+ pa->sc_state = SC_BASE64_APPEND;
+ goto callnext;
+ }
+
+ if (c == '-' || c == '+' || isdigit(c)) {
+ pa->sc_state = SC_SINT64;
+ goto callnext;
+ } else
+ if (isspace(c)) {
+ pa->sc_state = SC_WHITE;
+ goto callnext;
+ }
+ pa->sc_state = SC_SYMBOL;
+ goto callnext;
+
+ case SC_BASE64_APPEND:
+ if (strchr(base64abc, c) != NULL || c == '=') {
+ char d = scanner_base64_decode(c);
+
+ if (scanner_ensure_strlen(pa))
+ return (ENOMEM);
+
+ switch (pa->sc_base64_size % 24) {
+ case 0:
+ pa->sc_string[pa->sc_strcur] = d << 2;
+ break;
+ case 6:
+ /* LINTED: sc_string & d are u_char */
+ pa->sc_string[pa->sc_strcur] |= d >> 4;
+ pa->sc_strcur++;
+ pa->sc_string[pa->sc_strcur] = d << 4;
+ break;
+ case 12:
+ /* LINTED: sc_string & d are u_char */
+ pa->sc_string[pa->sc_strcur] |= d >> 2;
+ pa->sc_strcur++;
+ pa->sc_string[pa->sc_strcur] = d << 6;
+ break;
+ case 18:
+ pa->sc_string[pa->sc_strcur++] |= d;
+ break;
+ }
+
+ pa->sc_base64_size += 6;
+ } else {
+ pa->sc_state = SC_BASE64_MAYBE_NEXT;
+ goto callcc;
+ }
+ break;
+
+ case SC_BASE64_MAYBE_NEXT:
+ if (pa->sc_base64_size == 0) {
+ VERBOSE("scanner: BASE64 first chunk empty");
+ pa->sc_state = SC_ERROR;
+ goto callcc;
+ }
+ if (c == '.') {
+ pa->sc_state = SC_BASE64_NEXT;
+ goto callnext;
+ }
+ if (! isspace(c)) {
+ pa->sc_state = SC_BASE64_CLOSE;
+ goto callcc;
+ }
+ break;
+
+ case SC_BASE64_NEXT:
+ if (strchr(base64abc, c) != NULL || c == '=') {
+ pa->sc_state = SC_BASE64_APPEND;
+ goto callcc;
+ }
+ if (! isspace(c)) {
+ pa->sc_state = SC_ERROR;
+ goto callcc;
+ }
+ break;
+
+ case SC_BASE64_CLOSE:
+ {
+ u_char *s;
+
+ /* Length must always be multiple of 3 bytes. */
+ if (pa->sc_base64_size % 24) {
+ /* Warrants we're long enough to roundup. */
+ if (scanner_ensure_strlen(pa))
+ return (ENOMEM);
+
+ /* Don't overwrite string[strcur]! */
+ memset(pa->sc_string + pa->sc_strcur + 1, 0,
+ pa->sc_strlen - pa->sc_strcur - 1);
+
+ pa->sc_base64_size =
+ roundup(pa->sc_base64_size, 24);
+ }
+
+ /* Convert length to bytes. */
+ pa->sc_base64_size = roundup(pa->sc_base64_size, 8)/8;
+
+ s = _PROP_MALLOC(pa->sc_base64_size, M_TEMP);
+ if (s == NULL) {
+ VERBOSE("scanner: ENOMEM data");
+ return (ENOMEM);
+ }
+ memcpy(s, pa->sc_string, pa->sc_base64_size);
+
+ if ((t = parser_token_put(pa, TK_DATA)) == NULL)
+ return (ENOMEM);
+ t->tok_data_buf = s;
+ t->tok_data_len = pa->sc_base64_size;
+
+ pa->sc_state = SC_TOPLEVEL;
+ goto callcc;
+ }
+ /* UNREACHED */
+
+ case SC_STRING_APPEND:
+ if (c == '\\') {
+ pa->sc_state = SC_QUOTED;
+ goto callnext;
+ }
+ if (c == '"') {
+ /* Closing quote, see if concatenation follows. */
+ pa->sc_state = SC_STRING_MAYBE_NEXT;
+ goto callnext;
+ }
+ if (! isprint(c)) {
+ pa->sc_state = SC_ERROR;
+ goto callcc;
+ }
+ /* Append from edge action. */
+ break;
+
+ case SC_STRING_MAYBE_NEXT:
+ if (c == '.') {
+ pa->sc_state = SC_STRING_CONCAT;
+ goto callnext;
+ }
+ if (! isspace(c)) {
+ pa->sc_state = SC_STRING_CLOSE;
+ goto callcc;
+ }
+ break;
+
+ case SC_STRING_CONCAT:
+ if (c == '"') {
+ /* Opening quote of concat string. */
+ pa->sc_state = SC_STRING_APPEND;
+ goto callnext;
+ }
+ if (! isspace(c)) {
+ pa->sc_state = SC_ERROR;
+ goto callcc;
+ }
+ break;
+
+ case SC_STRING_CLOSE:
+ {
+ char *s;
+
+ s = strdup((const char *)pa->sc_string);
+ if (s == NULL) {
+ VERBOSE("scanner: ENOMEM string");
+ return (ENOMEM);
+ }
+
+ if ((t = parser_token_put(pa, TK_STRING)) == NULL)
+ return (ENOMEM);
+ t->tok_string = s;
+
+ pa->sc_state = SC_TOPLEVEL;
+ goto callcc;
+ }
+ /* NOTREACHED */
+
+ case SC_QUOTED:
+ {
+ u_char d;
+
+ if (scanner_ensure_strlen(pa))
+ return (ENOMEM);
+
+ switch (d = c) {
+ case '\\': d = '\\'; break;
+ case 'n': d = '\n'; break;
+ case 't': d = '\t'; break;
+ case '"': d = '\"'; break;
+ }
+
+ pa->sc_string[pa->sc_strcur++] = d;
+ pa->sc_string[pa->sc_strcur] = '\0';
+
+ pa->sc_state = SC_STRING_APPEND;
+ goto callnext;
+ }
+ /* NOTREACHED */
+
+ case SC_WHITE:
+ if (! isspace(c)) {
+ if ((t = parser_token_put(pa, TK_WHITE)) == NULL)
+ return (ENOMEM);
+
+ pa->sc_state = SC_TOPLEVEL;
+ goto callcc;
+ }
+ break;
+
+ case SC_SINT64:
+ if (! isdigit(c) && c != '+' && c != '-') {
+ long long n;
+ char *end;
+
+ n = strtoll((const char *)pa->sc_string, &end, 10);
+ if (*end != '\0' || n > INT64_MAX || n < INT64_MIN) {
+ VERBOSE("scanner: wrong SINT64 '%s'",
+ pa->sc_string);
+ return (EINVAL);
+ }
+
+ if ((t = parser_token_put(pa, TK_SINT64)) == NULL)
+ return (ENOMEM);
+ t->tok_unsigned = (int64_t)n;
+
+ pa->sc_state = SC_TOPLEVEL;
+ goto callcc;
+ }
+ break;
+
+ case SC_UINT64:
+ if (! isxdigit(c)) {
+ unsigned long long u;
+ char *end;
+
+ u = strtoull((const char *)pa->sc_string, &end, 16);
+ if (*end != '\0' || u > UINT64_MAX) {
+ VERBOSE("scanner: wrong UINT64 '%s'",
+ pa->sc_string);
+ return (EINVAL);
+ }
+
+ if ((t = parser_token_put(pa, TK_UINT64)) == NULL)
+ return (ENOMEM);
+ t->tok_unsigned = (uint64_t)u;
+
+ pa->sc_state = SC_TOPLEVEL;
+ goto callcc;
+ }
+ break;
+
+ case SC_SYMBOL:
+ if (isspace(c) || c == '\\') {
+ char *s;
+
+ s = strdup((const char *)pa->sc_string);
+ if (s == NULL) {
+ VERBOSE("scanner: ENOMEM symbol");
+ return (ENOMEM);
+ }
+
+ if ((t = parser_token_put(pa, TK_SYMBOL)) == NULL) {
+ _PROP_FREE(s, M_TEMP);
+ return (ENOMEM);
+ }
+ t->tok_string = s;
+
+ pa->sc_state = SC_TOPLEVEL;
+ goto callcc;
+ }
+ if (! isprint(c)) {
+ pa->sc_state = SC_ERROR;
+ goto callcc;
+ }
+ break;
+
+ case SC_COMMENT:
+ if (c == '\n' || c == '\r') {
+ pa->sc_state = SC_TOPLEVEL;
+ goto callnext;
+ }
+ break;
+
+ case SC_ERROR:
+ VERBOSE("scanner: wrong char '%c' (line %zd char %zd) in "
+ "state %s", c, pa->sc_pos_line, pa->sc_pos_col,
+ scanner_state_name(pa->sc_last));
+ return (EINVAL);
+ }
+
+ callnext:
+ keepchar = FALSE;
+
+ callcc:
+ if (pa->sc_state != pa->sc_prev) {
+ VERBOSE("scanner: %-17s --> %-17s %s\t[%d, %d]",
+ ((keepchar && pa->sc_prev != SC_FIRST) ?
+ "" : scanner_state_name(pa->sc_prev)),
+ scanner_state_name(pa->sc_state),
+ scanner_quote_char(c), pa->sc_pos_line, pa->sc_pos_col);
+ } else {
+ VERBOSE("scanner: %-17s ::: %-17s %s\t[%d, %d]", "", "",
+ scanner_quote_char(c), pa->sc_pos_line, pa->sc_pos_col);
+ }
+
+ /* Be specific about transitions, let compiler deal w/redundancy. */
+ if (SC_ARROW_P(SC_TOPLEVEL, SC_BASE64_APPEND)) {
+ pa->sc_base64_size = 0;
+ pa->sc_strcur = 0;
+ }
+ if (SC_ARROW_P(SC_TOPLEVEL, SC_STRING_APPEND) ||
+ SC_ARROW_P(SC_TOPLEVEL, SC_SYMBOL) ||
+ SC_ARROW_P(SC_TOPLEVEL, SC_UINT64) ||
+ SC_ARROW_P(SC_TOPLEVEL, SC_SINT64)) {
+ pa->sc_strcur = 0;
+ }
+ if (SC_CYCLE_P(SC_UINT64) ||
+ SC_CYCLE_P(SC_SINT64) ||
+ SC_CYCLE_P(SC_STRING_APPEND) ||
+ SC_CYCLE_P(SC_SYMBOL) ||
+ SC_ARROW_P(SC_TOPLEVEL, SC_SINT64) ||
+ SC_ARROW_P(SC_TOPLEVEL, SC_SYMBOL)) {
+ if (scanner_ensure_strlen(pa))
+ return (ENOMEM);
+
+ pa->sc_string[pa->sc_strcur++] = c;
+ pa->sc_string[pa->sc_strcur] = '\0';
+ }
+
+#if !defined(_STANDALONE)
+ if (! keepchar) {
+ if (c == '\n') {
+ pa->sc_pos_line++;
+ pa->sc_pos_col = 1;
+ } else {
+ if (c == '\t')
+ pa->sc_pos_col = roundup(pa->sc_pos_col, 8);
+ else
+ pa->sc_pos_col++;
+ }
+ }
+#endif
+
+ /* Commited to new state. */
+ if (pa->sc_state != pa->sc_prev)
+ pa->sc_last = pa->sc_prev;
+ pa->sc_prev = pa->sc_state;
+
+ if (keepchar)
+ goto dispatch;
+ else
+ goto advance;
+
+ /* UNREACHED */
+}
+
+#undef SC_CYCLE_P
+#undef SC_ARROW_P
+
+static void
+parser_frame_free(struct frame *e)
+{
+ if (e->se_symbol)
+ _PROP_FREE(__UNCONST(e->se_symbol), M_TEMP);
+ if (e->se_object != NULL)
+ prop_object_release(e->se_object);
+ _PROP_FREE(e, M_TEMP);
+}
+
+static boolean_t
+parser_frame_enter(struct parser *pa, prop_object_t o)
+{
+ struct frame *e;
+
+ if (o == NULL)
+ return (TRUE);
+
+ e = _PROP_MALLOC(sizeof(struct frame), M_TEMP);
+ if (e == NULL)
+ return (TRUE);
+
+ memset(e, 0, sizeof(struct frame));
+ e->se_object = o;
+
+ SIMPLEQ_INSERT_HEAD(&pa->pa_stack, e, se_link);
+ return (FALSE);
+}
+
+static int
+parser_frame_store(struct parser *pa, prop_object_t o)
+{
+ struct frame *e;
+ prop_object_t the;
+
+ e = SIMPLEQ_FIRST(&pa->pa_stack);
+ if (e == NULL) {
+ VERBOSE(" parser: stack underflow");
+ return (EINVAL);
+ }
+ the = e->se_object;
+
+ switch (prop_object_type(the)) {
+ case PROP_TYPE_ARRAY:
+ _PROP_ASSERT(e->se_symbol == NULL);
+ if (prop_array_add(the, o) == FALSE)
+ return (ENOMEM);
+ break;
+
+ case PROP_TYPE_DICTIONARY:
+ _PROP_ASSERT(e->se_symbol != NULL);
+ if (prop_dictionary_set(the, e->se_symbol, o) == FALSE)
+ return (ENOMEM);
+
+ _PROP_FREE(__UNCONST(e->se_symbol), M_TEMP);
+ e->se_symbol = NULL;
+ break;
+
+ default:
+ VERBOSE(" parser: wrong object on stack, not compound");
+ return (EINVAL);
+ }
+
+ prop_object_release(o);
+ return (0);
+}
+
+static int
+parser_frame_leave(struct parser *pa)
+{
+ struct frame *e;
+ prop_object_t o;
+
+ /* Get hold of the lower object. */
+ if ((e = SIMPLEQ_FIRST(&pa->pa_stack)) == NULL) {
+ VERBOSE(" parser: stack underflow");
+ return (EINVAL);
+ }
+ SIMPLEQ_REMOVE_HEAD(&pa->pa_stack, se_link);
+
+ /* Move it to finished objects if it's toplevel. */
+ if (SIMPLEQ_EMPTY(&pa->pa_stack)) {
+ SIMPLEQ_INSERT_TAIL(&pa->pa_consq, e, se_link);
+ _PROP_ASSERT(e->se_object);
+ return (0);
+ }
+
+ /* Otherwise insert into current compound. */
+ o = e->se_object;
+
+ /* Make sure ${o} isn't released, parser_frame_store() will do it. */
+ e->se_object = NULL;
+ parser_frame_free(e);
+
+ return (parser_frame_store(pa, o));
+}
+
+static int
+prop_scn_parser_create(prop_parser_t *pp)
+{
+ struct parser *pa;
+
+ pa = _PROP_MALLOC(sizeof(struct parser), M_TEMP);
+ if (pa == NULL)
+ return (ENOMEM);
+ memset(pa, 0, sizeof(struct parser));
+
+ SIMPLEQ_INIT(&pa->pa_tokens);
+ SIMPLEQ_INIT(&pa->pa_stack);
+ SIMPLEQ_INIT(&pa->pa_consq);
+
+#if !defined(_STANDALONE)
+ /* Text editors tend to count from 1, be friendly. */
+ pa->sc_pos_line = 1;
+ pa->sc_pos_col = 1;
+#endif
+
+ if (parser_token_put(pa, TK_FIRST) == NULL) {
+ _PROP_FREE(pa, M_TEMP);
+ return (ENOMEM);
+ }
+
+ *pp = pa;
+ return (0);
+}
+
+static void
+prop_scn_parser_destroy(prop_parser_t arg)
+{
+ struct parser *pa = arg;
+ struct token *t;
+ struct frame *e;
+
+ if (pa->sc_string)
+ _PROP_FREE(pa->sc_string, M_TEMP);
+
+ /* Free any pending tokens. */
+ while ((t = SIMPLEQ_FIRST(&pa->pa_tokens)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(&pa->pa_tokens, tok_link);
+ parser_token_free(t, TRUE);
+ }
+
+ /* Free any active stack frames. */
+ while ((e = SIMPLEQ_FIRST(&pa->pa_stack)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(&pa->pa_stack, se_link);
+ parser_frame_free(e);
+ }
+
+ /* Free any finished objects. */
+ while ((e = SIMPLEQ_FIRST(&pa->pa_consq)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(&pa->pa_consq, se_link);
+ parser_frame_free(e);
+ }
+
+ _PROP_FREE(pa, M_TEMP);
+}
+
+static prop_object_t
+prop_scn_parser_yield(prop_parser_t arg)
+{
+ struct parser *pa = arg;
+ struct frame *e;
+ prop_object_t o;
+
+ if ((e = SIMPLEQ_FIRST(&pa->pa_consq)) == NULL)
+ return (NULL);
+ SIMPLEQ_REMOVE_HEAD(&pa->pa_consq, se_link);
+
+ o = e->se_object;
+ e->se_object = NULL;
+
+ _PROP_ASSERT(e);
+ _PROP_ASSERT(o);
+
+ parser_frame_free(e);
+ return (o);
+}
+
+static int
+prop_scn_parser_exec(prop_parser_t arg, const u_char *input, size_t length)
+{
+ static const char *__truths[] = { "true", "yes", "on", NULL };
+ static const char *__lies[] = { "false", "no", "off", NULL };
+ prop_object_t the;
+ struct frame *frame;
+ struct token *t;
+ struct parser *pa = arg;
+ int nexttoken, ret;
+
+ ret = prop_scanner_exec(pa, input, length);
+ if (ret)
+ return (ret);
+
+ advance:
+ if ((t = SIMPLEQ_FIRST(&pa->pa_tokens)) == NULL)
+ return (0);
+
+ dispatch:
+ pa->pa_prev = pa->pa_state;
+ nexttoken = FALSE; /* for callcc */
+
+ switch (pa->pa_state) {
+ case PA_TOPLEVEL:
+ switch (t->tok_type) {
+ case TK_FIRST:
+ /* XXX read version token */
+ goto callnext;
+
+ case TK_DICTO:
+ if (parser_frame_enter(pa,
+ (prop_object_t)prop_dictionary_create())) {
+ VERBOSE(" parser: ENOMEM dictionary");
+ return (ENOMEM);
+ }
+ pa->pa_state = PA_DICTIONARY;
+ goto callnext;
+
+ case TK_ARRAYO:
+ if (parser_frame_enter(pa,
+ (prop_object_t)prop_array_create())) {
+ VERBOSE(" parser: ENOMEM array");
+ return (ENOMEM);
+ }
+ pa->pa_state = PA_ARRAY;
+ goto callnext;
+
+ case TK_LAST:
+ if (SIMPLEQ_NEXT(t, tok_link) != NULL) {
+ VERBOSE(" parser: stack not empty at EOF");
+ return (EINVAL);
+ }
+ return (0);
+
+ default:
+ /* GCC tries to be smart but fails. */
+ break;
+ }
+ if (t->tok_type != TK_WHITE) {
+ pa->pa_state = PA_ERROR;
+ goto callcc;
+ }
+ break;
+
+ case PA_ARRAY:
+ if (t->tok_type == TK_ARRAYC) {
+ if ((ret = parser_frame_leave(pa)) != 0) {
+ if (ret == EINVAL)
+ VERBOSE(" parser: [%d, %d] "
+ "misplaced ']'",
+ t->tok_pos_line, t->tok_pos_col);
+ return (ret);
+ }
+ pa->pa_state = PA_HOME;
+ goto callcc;
+ } else
+ if (t->tok_type != TK_WHITE) {
+ pa->pa_state = PA_OBJECT;
+ goto callcc;
+ }
+ break;
+
+ case PA_DICTIONARY:
+ switch (t->tok_type) {
+ case TK_DICTC:
+ if ((ret = parser_frame_leave(pa)) != 0) {
+ if (ret == EINVAL)
+ VERBOSE(" parser: [%d, %d] "
+ "misplaced '}'",
+ t->tok_pos_line, t->tok_pos_col);
+ return (ret);
+ }
+ pa->pa_state = PA_HOME;
+ goto callcc;
+
+ case TK_SYMBOL:
+ frame = SIMPLEQ_FIRST(&pa->pa_stack);
+ _PROP_ASSERT(frame && frame->se_symbol == NULL);
+ frame->se_symbol = (const char *)t->tok_string;
+
+ pa->pa_state = PA_OBJECT;
+ goto callnext;
+
+ default:
+ /* GCC */
+ break;
+ }
+ /* WHITE or ERROR */
+ break;
+
+ case PA_OBJECT:
+ if (t->tok_type == TK_WHITE)
+ break;
+
+ switch (t->tok_type) {
+ case TK_STRING:
+ the = prop_scn_create_string(t);
+ break;
+
+ case TK_UINT64:
+ the = prop_scn_create_uint(t);
+ break;
+
+ case TK_SINT64:
+ the = prop_scn_create_sint(t);
+ break;
+
+ case TK_DATA:
+ the = prop_data_create_data_nocopy(t->tok_data_buf,
+ t->tok_data_len);
+ break;
+
+ case TK_SYMBOL:
+ /* Coerce SYMBOL to bool at value position. */
+ if (stroneof((const char *)t->tok_string, __truths))
+ the = prop_bool_create(TRUE);
+ else
+ if (stroneof((const char *)t->tok_string, __lies))
+ the = prop_bool_create(FALSE);
+ else {
+ VERBOSE(" parser: [%d, %d] wrong BOOL '%s'",
+ t->tok_pos_line, t->tok_pos_col,
+ t->tok_string);
+ return (EINVAL);
+ }
+ break;
+
+ case _TK_COMPOUND_VALUES:
+ /* Descend one level deeper via TOPLEVEL actions. */
+ pa->pa_state = PA_TOPLEVEL;
+ goto callcc;
+
+ default:
+ pa->pa_state = PA_ERROR;
+ goto callcc;
+ }
+
+ /* We're supposed to have valid simple object now. */
+ if (the == NULL) {
+ VERBOSE(" parser: ENOMEM for %s",
+ parser_token_name(t->tok_type));
+ return (ENOMEM);
+ }
+
+ /* Store it in current container. */
+ if (parser_frame_store(pa, the))
+ return (ENOMEM);
+
+ pa->pa_state = PA_HOME;
+ goto callcc;
+
+ case PA_HOME:
+ /*
+ * We've just finished an object (simple or compound).
+ * Continue where we came from -- at the parent container's
+ * main entry point. We get here through callcc.
+ */
+ frame = SIMPLEQ_FIRST(&pa->pa_stack);
+ if (frame == NULL) {
+ pa->pa_state = PA_TOPLEVEL;
+ break;
+ }
+ _PROP_ASSERT(frame->se_object);
+
+ switch (prop_object_type(frame->se_object)) {
+ case PROP_TYPE_ARRAY:
+ pa->pa_state = PA_ARRAY;
+ break;
+
+ case PROP_TYPE_DICTIONARY:
+ pa->pa_state = PA_DICTIONARY;
+ break;
+
+ default:
+ VERBOSE(" parser: wrong object on stack");
+ return (EINVAL);
+ }
+ break;
+
+ case PA_ERROR:
+ VERBOSE(" parser: [%d, %d] wrong token %s in state %s",
+ t->tok_pos_line, t->tok_pos_col,
+ parser_token_desc(t), parser_state_name(pa->pa_last));
+ return (EINVAL);
+ }
+
+ /* Call to next implies token was accepted, so stay above. */
+ if (pa->pa_prev == pa->pa_state &&
+ (pa->pa_state == PA_TOPLEVEL || pa->pa_state == PA_ARRAY ||
+ pa->pa_state == PA_DICTIONARY))
+ if (t->tok_type != TK_WHITE) {
+ pa->pa_state = PA_ERROR;
+ goto callcc;
+ }
+
+ callnext:
+ nexttoken = TRUE;
+
+ callcc:
+ if (pa->pa_state != pa->pa_last) {
+ VERBOSE(" parser: %-17s --> %-17s %s",
+ (nexttoken ? parser_state_name(pa->pa_prev) : ""),
+ parser_state_name(pa->pa_state),
+ parser_token_desc(t));
+
+ pa->pa_last = pa->pa_prev;
+ } else {
+ VERBOSE(" parser: %-17s ::: %-17s %s", "", "",
+ parser_token_desc(t));
+ }
+
+ if (nexttoken) {
+ SIMPLEQ_REMOVE_HEAD(&pa->pa_tokens, tok_link);
+ parser_token_free(t, FALSE);
+
+ goto advance;
+ } else {
+ goto dispatch;
+ }
+ /* UNREACHED */
+}
+
+static boolean_t
+format_string_quote(struct poec *ec, const char *s)
+{
+ const char *t;
+ boolean_t ret;
+
+ if (! poec_push(ec, '"'))
+ return (TRUE);
+
+ while (*s) {
+ t = NULL;
+
+ switch (*s) {
+ case '\f': t = "\\f"; break;
+ case '\n': t = "\\n"; break;
+ case '\r': t = "\\r"; break;
+ case '\t': t = "\\t"; break;
+ case '\v': t = "\\v"; break;
+ case '"': t = "\\\""; break;
+ }
+
+ if (t)
+ ret = poec_append(ec, t);
+ else
+ ret = poec_push(ec, *s);
+ if (ret == FALSE)
+ return (TRUE);
+
+ s++;
+ }
+
+ if (! poec_push(ec, '"'))
+ return (TRUE);
+ return (FALSE);
+}
+
+static boolean_t
+format_data_base64(struct poec *ec, const char *s, size_t size)
+{
+ const u_char *b = (const u_char *)s;
+ size_t i;
+ u_int n;
+ int ret = 0; /* XXX gcc sux */
+
+ poec_push(ec, ':');
+
+ /* LINTED n & b[] are unsigned */
+ n = b[0] >> 2;
+
+ for (i = 0; i < size; i++) {
+ switch (i % 3) {
+ case 0:
+ /* LINTED: b[] is u_char */
+ ret = poec_push(ec, base64abc[b[i] >> 2]);
+ n = b[i] & 0x03;
+ break;
+ case 1:
+ /* LINTED: b[] is u_char */
+ ret = poec_push(ec,
+ base64abc[(n << 4) | (b[i] >> 4)]);
+ n = b[i] & 0x0f;
+ break;
+ case 2:
+ /* LINTED: b[] is u_char */
+ if (!poec_push(ec, base64abc[(n << 2) | (b[i] >> 6)]) ||
+ !poec_push(ec, base64abc[b[i] & 0x3f]))
+ ret = FALSE;
+ else
+ ret = TRUE;
+ break;
+ }
+ if (ret == FALSE)
+ return (TRUE);
+ }
+
+ /* Finish based on how many bytes of a triplet we already have. */
+ switch (size % 3) {
+ case 1:
+ if (!poec_push(ec, base64abc[n << 4]))
+ return (TRUE);
+ break;
+ case 2:
+ if (!poec_push(ec, base64abc[n << 2]))
+ return (TRUE);
+ break;
+ }
+
+ /* Finally, pad to multiple of four characters of encoded text. */
+ switch (size % 3) {
+ case 1:
+ if (!poec_push(ec, '='))
+ return (TRUE);
+ /* FALLTHROUGH */
+ case 2:
+ if (!poec_push(ec, '='))
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+static boolean_t
+format_indent(struct poec *ec)
+{
+ int i;
+
+#if 0
+ VERBOSE(" format: %zd/%zdB used, nesting depth %d",
+ ec->poec_len, ec->poec_capacity, ec->poec_depth);
+#endif
+
+ for (i = 0; i < ec->poec_depth; i++)
+ if (poec_push(ec, '\t') == FALSE) {
+ VERBOSE(" format: ENOMEM indent");
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+static char *
+prop_scn_externalize(prop_object_t o)
+{
+ char buf[32];
+ struct stack sp;
+ struct frame *e;
+ struct poec *ec;
+ char *s;
+ prop_object_t the;
+ boolean_t ret;
+
+ SIMPLEQ_INIT(&sp);
+ if ((ec = poec_create()) == NULL)
+ return (NULL);
+
+ /*
+ * We only work for compound objects, like XML codec does.
+ * Note that this ensures we'll record ${o} on the stack.
+ */
+ switch (prop_object_type(o)) {
+ case PROP_TYPE_ARRAY:
+ case PROP_TYPE_DICTIONARY:
+ break;
+ default:
+ goto lose;
+ }
+ the = o;
+
+ again:
+ switch (prop_object_type(the)) {
+ case PROP_TYPE_BOOL:
+ VERBOSE(" format: bool [%d]", ec->poec_depth);
+ if (prop_bool_true(the))
+ ret = poec_append(ec, "True");
+ else
+ ret = poec_append(ec, "False");
+ if (ret == FALSE)
+ goto lose;
+ break;
+
+ case PROP_TYPE_NUMBER:
+ VERBOSE(" format: number [%d]", ec->poec_depth);
+ if (prop_number_unsigned(the))
+ snprintf(buf, sizeof(buf), "#%" PRIx64,
+ prop_number_unsigned_integer_value(the));
+ else
+ snprintf(buf, sizeof(buf), "%" PRId64,
+ prop_number_integer_value(the));
+ if (poec_append(ec, buf) == FALSE)
+ goto lose;
+ break;
+
+ case PROP_TYPE_STRING:
+ VERBOSE(" format: string [%d]", ec->poec_depth);
+ if (format_string_quote(ec, prop_string_cstring_nocopy(the)))
+ goto lose;
+ break;
+
+ case PROP_TYPE_DATA:
+ VERBOSE(" format: data [%d]", ec->poec_depth);
+ if (format_data_base64(ec, prop_data_data_nocopy(the),
+ prop_data_size(the)))
+ goto lose;
+ break;
+
+ case PROP_TYPE_ARRAY:
+ VERBOSE(" format: array [%d]", ec->poec_depth);
+ if (!poec_append(ec, "["))
+ goto lose;
+ ec->poec_depth++;
+
+ if ((e = _PROP_MALLOC(sizeof(struct frame), M_TEMP)) == NULL)
+ goto lose;
+ memset(e, 0, sizeof(struct frame));
+ SIMPLEQ_INSERT_HEAD(&sp, e, se_link);
+
+ e->se_object = the;
+ e->se_iter = prop_array_iterator(the);
+ if (e->se_iter == NULL)
+ goto lose;
+ break;
+
+ case PROP_TYPE_DICTIONARY:
+ VERBOSE(" format: dictionary [%d]", ec->poec_depth);
+ if (!poec_append(ec, "{")) {
+ VERBOSE(" format: ENOMEM dictionary open");
+ goto lose;
+ }
+ ec->poec_depth++;
+
+ if ((e = _PROP_MALLOC(sizeof(struct frame), M_TEMP)) == NULL) {
+ VERBOSE(" format: ENOMEM stack frame");
+ goto lose;
+ }
+ memset(e, 0, sizeof(struct frame));
+ SIMPLEQ_INSERT_HEAD(&sp, e, se_link);
+
+ e->se_object = the;
+ e->se_iter = prop_dictionary_iterator(the);
+ if (e->se_iter == NULL) {
+ VERBOSE(" format: ENOMEM dictionary iterator");
+ goto lose;
+ }
+ break;
+
+ default:
+ VERBOSE(" format: object %p wrong type %d", the,
+ prop_object_type(the));
+ goto lose;
+ }
+ if (! poec_append(ec, "\n")) {
+ VERBOSE(" format: ENOMEM newline after object");
+ goto lose;
+ }
+
+ pop:
+ e = SIMPLEQ_FIRST(&sp);
+ if (e == NULL) {
+ _PROP_ASSERT(ec->poec_depth == 0);
+ printf("DONE\n"); /* XXX done */
+ }
+ _PROP_ASSERT(e->se_iter != NULL);
+
+ /* Grab next object. */
+ o = prop_object_iterator_next(e->se_iter);
+ if (o == NULL) {
+ SIMPLEQ_REMOVE_HEAD(&sp, se_link);
+
+ _PROP_ASSERT(ec->poec_depth != 0);
+ ec->poec_depth --;
+
+ if (format_indent(ec)) {
+ VERBOSE(" format: ENOMEM close indent");
+ goto lose;
+ }
+ if (prop_object_type(e->se_object) == PROP_TYPE_DICTIONARY)
+ ret = poec_append(ec, "}\n");
+ else
+ ret = poec_append(ec, "]\n");
+ if (ret == FALSE) {
+ VERBOSE(" format: ENOMEM close compound");
+ goto lose;
+ }
+
+ prop_object_iterator_release(e->se_iter);
+ _PROP_FREE(e, M_TEMP);
+
+ if (SIMPLEQ_EMPTY(&sp))
+ goto done;
+ else
+ goto pop;
+ }
+
+ /* Lookup the real object if we got indirect reference. */
+ if (prop_object_type(o) == PROP_TYPE_DICT_KEYSYM) {
+ const char *r;
+ prop_object_t p;
+
+ p = prop_dictionary_get_keysym((prop_dictionary_t)e->se_object,
+ (prop_dictionary_keysym_t)o);
+ _PROP_ASSERT(p != NULL);
+
+ r = prop_keysym_str((prop_dictionary_keysym_t)o);
+ if (r == NULL) {
+ VERBOSE(" format: EINVAL dictionary key");
+ goto lose;
+ }
+
+ if (format_indent(ec) || poec_append(ec, r) == FALSE ||
+ poec_push(ec, '\t') == FALSE) {
+ VERBOSE(" format: ENOMEM dictionary key");
+ goto lose;
+ }
+
+ the = p;
+ } else {
+ if (format_indent(ec)) {
+ VERBOSE(" format: ENOMEM array indent");
+ goto lose;
+ }
+ the = o;
+ }
+
+ /* We've got a fresh object from the compound, analyse it. */
+ goto again;
+
+ done:
+ /* Prepare the result for caller. */
+ ec->poec_buf[ec->poec_len] = '\0';
+ s = ec->poec_buf;
+
+ /* The stack is empty at this point, just free externalize context. */
+ poec_destroy(ec);
+
+ return (s);
+ /*NOTREACHED*/
+
+ lose:
+ VERBOSE(" format: LOST");
+ while ((e = SIMPLEQ_FIRST(&sp)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(&sp, se_link);
+ if (e->se_iter)
+ prop_object_iterator_release(e->se_iter);
+ _PROP_FREE(e, M_TEMP);
+ }
+
+ if (ec->poec_buf)
+ _PROP_FREE(ec->poec_buf, M_TEMP);
+ poec_destroy(ec);
+
+ return (NULL);
+}
+
+const struct _prop_codec prop_codec_scn = {
+ .codec_name = "scn",
+ .codec_sense = (const u_char *)".{[;",
+ .codec_externalize_compound = prop_scn_externalize,
+ .codec_parser_create = prop_scn_parser_create,
+ .codec_parser_exec = prop_scn_parser_exec,
+ .codec_parser_yield = prop_scn_parser_yield,
+ .codec_parser_destroy = prop_scn_parser_destroy,
+};
Index: common/lib/libprop/prop_string.c
===================================================================
RCS file: /cvsroot/src/common/lib/libprop/prop_string.c,v
retrieving revision 1.6
diff -d -p -u -r1.6 prop_string.c
--- common/lib/libprop/prop_string.c 18 Oct 2006 19:15:46 -0000 1.6
+++ common/lib/libprop/prop_string.c 7 Jun 2007 13:27:02 -0000
@@ -39,35 +39,17 @@
#include <prop/prop_string.h>
#include "prop_object_impl.h"
-struct _prop_string {
- struct _prop_object ps_obj;
- union {
- char * psu_mutable;
- const char * psu_immutable;
- } ps_un;
-#define ps_mutable ps_un.psu_mutable
-#define ps_immutable ps_un.psu_immutable
- size_t ps_size; /* not including \0 */
- int ps_flags;
-};
-
-#define PS_F_NOCOPY 0x01
-
_PROP_POOL_INIT(_prop_string_pool, sizeof(struct _prop_string), "propstng")
_PROP_MALLOC_DEFINE(M_PROP_STRING, "prop string",
"property string container object")
static void _prop_string_free(void *);
-static boolean_t _prop_string_externalize(
- struct _prop_object_externalize_context *,
- void *);
static boolean_t _prop_string_equals(void *, void *);
static const struct _prop_object_type _prop_object_type_string = {
.pot_type = PROP_TYPE_STRING,
.pot_free = _prop_string_free,
- .pot_extern = _prop_string_externalize,
.pot_equals = _prop_string_equals,
};
@@ -86,24 +68,6 @@ _prop_string_free(void *v)
}
static boolean_t
-_prop_string_externalize(struct _prop_object_externalize_context *ctx,
- void *v)
-{
- prop_string_t ps = v;
-
- if (ps->ps_size == 0)
- return (_prop_object_externalize_empty_tag(ctx, "string"));
-
- if (_prop_object_externalize_start_tag(ctx, "string") == FALSE ||
- _prop_object_externalize_append_encoded_cstring(ctx,
- ps->ps_immutable) == FALSE ||
- _prop_object_externalize_end_tag(ctx, "string") == FALSE)
- return (FALSE);
-
- return (TRUE);
-}
-
-static boolean_t
_prop_string_equals(void *v1, void *v2)
{
prop_string_t str1 = v1;
@@ -121,7 +85,7 @@ _prop_string_equals(void *v1, void *v2)
prop_string_contents(str2)) == 0);
}
-static prop_string_t
+prop_string_t
_prop_string_alloc(void)
{
prop_string_t ps;
@@ -407,57 +371,3 @@ prop_string_equals_cstring(prop_string_t
return (strcmp(prop_string_contents(ps), cp) == 0);
}
-
-/*
- * _prop_string_internalize --
- * Parse a <string>...</string> and return the object created from the
- * external representation.
- */
-prop_object_t
-_prop_string_internalize(struct _prop_object_internalize_context *ctx)
-{
- prop_string_t string;
- char *str;
- size_t len, alen;
-
- if (ctx->poic_is_empty_element)
- return (prop_string_create());
-
- /* No attributes recognized here. */
- if (ctx->poic_tagattr != NULL)
- return (NULL);
-
- /* Compute the length of the result. */
- if (_prop_object_internalize_decode_string(ctx, NULL, 0, &len,
- NULL) == FALSE)
- return (NULL);
-
- str = _PROP_MALLOC(len + 1, M_PROP_STRING);
- if (str == NULL)
- return (NULL);
-
- if (_prop_object_internalize_decode_string(ctx, str, len, &alen,
- &ctx->poic_cp) == FALSE ||
- alen != len) {
- _PROP_FREE(str, M_PROP_STRING);
- return (NULL);
- }
- str[len] = '\0';
-
- if (_prop_object_internalize_find_tag(ctx, "string",
- _PROP_TAG_TYPE_END) == FALSE) {
- _PROP_FREE(str, M_PROP_STRING);
- return (NULL);
- }
-
- string = _prop_string_alloc();
- if (string == NULL) {
- _PROP_FREE(str, M_PROP_STRING);
- return (NULL);
- }
-
- string->ps_mutable = str;
- string->ps_size = len;
-
- return (string);
-}
Index: common/lib/libprop/prop_system_impl.h
===================================================================
RCS file: common/lib/libprop/prop_system_impl.h
diff -N common/lib/libprop/prop_system_impl.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ common/lib/libprop/prop_system_impl.h 7 Jun 2007 13:27:02 -0000
@@ -0,0 +1,208 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 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 _PROPLIB_PROP_SYSTEM_IMPL_H_
+#define _PROPLIB_PROP_SYSTEM_IMPL_H_
+
+#if defined(_KERNEL)
+
+/*
+ * proplib in the kernel...
+ */
+
+#include <sys/param.h>
+#include <sys/malloc.h>
+#include <sys/pool.h>
+#include <sys/systm.h>
+#include <sys/lock.h>
+
+#define _PROP_ASSERT(x) KASSERT(x)
+
+#define _PROP_MALLOC(s, t) malloc((s), (t), M_WAITOK)
+#define _PROP_CALLOC(s, t) malloc((s), (t), M_WAITOK | M_ZERO)
+#define _PROP_REALLOC(v, s, t) realloc((v), (s), (t), M_WAITOK)
+#define _PROP_FREE(v, t) free((v), (t))
+
+#define _PROP_POOL_GET(p) pool_get(&(p), PR_WAITOK)
+#define _PROP_POOL_PUT(p, v) pool_put(&(p), (v))
+
+#define _PROP_POOL_INIT(p, s, d) \
+ POOL_INIT(p, s, 0, 0, 0, d, &pool_allocator_nointr, IPL_NONE);
+
+#define _PROP_MALLOC_DEFINE(t, s, l) \
+ MALLOC_DEFINE(t, s, l);
+#define _PROP_MALLOC_DECLARE(t) \
+ MALLOC_DECLARE(t);
+
+#define _PROP_MUTEX_DECL_STATIC(x) \
+ static struct simplelock x = SIMPLELOCK_INITIALIZER;
+#define _PROP_MUTEX_LOCK(x) simple_lock(&(x))
+#define _PROP_MUTEX_UNLOCK(x) simple_unlock(&(x))
+
+#define _PROP_RWLOCK_DECL(x) struct lock x ;
+#define _PROP_RWLOCK_INIT(x) lockinit(&(x), PZERO, "proprwlk", 0, 0)
+#define _PROP_RWLOCK_RDLOCK(x) lockmgr(&(x), LK_SHARED, NULL)
+#define _PROP_RWLOCK_WRLOCK(x) lockmgr(&(x), LK_EXCLUSIVE, NULL)
+#define _PROP_RWLOCK_UNLOCK(x) lockmgr(&(x), LK_RELEASE, NULL)
+#define _PROP_RWLOCK_DESTROY(x) lockmgr(&(x), LK_DRAIN, NULL)
+
+#elif defined(_STANDALONE)
+
+/*
+ * proplib in a standalone environment...
+ */
+
+#include <lib/libsa/stand.h>
+
+void * _prop_standalone_calloc(size_t);
+void * _prop_standalone_realloc(void *, size_t);
+
+#define _PROP_ASSERT(x) /* nothing */
+
+#define _PROP_MALLOC(s, t) alloc((s))
+#define _PROP_CALLOC(s, t) _prop_standalone_calloc((s))
+#define _PROP_REALLOC(v, s, t) _prop_standalone_realloc((v), (s))
+#define _PROP_FREE(v, t) dealloc((v), 0) /* XXX */
+
+#define _PROP_POOL_GET(p) alloc((p))
+#define _PROP_POOL_PUT(p, v) dealloc((v), (p))
+
+#define _PROP_POOL_INIT(p, s, d) static const size_t p = s;
+
+#define _PROP_MALLOC_DEFINE(t, s, l) /* nothing */
+#define _PROP_MALLOC_DECLARE(t) /* nothing */
+
+#define _PROP_MUTEX_DECL_STATIC(x) /* nothing */
+#define _PROP_MUTEX_LOCK(x) /* nothing */
+#define _PROP_MUTEX_UNLOCK(x) /* nothing */
+
+#define _PROP_RWLOCK_DECL(x) /* nothing */
+#define _PROP_RWLOCK_INIT(x) /* nothing */
+#define _PROP_RWLOCK_RDLOCK(x) /* nothing */
+#define _PROP_RWLOCK_WRLOCK(x) /* nothing */
+#define _PROP_RWLOCK_UNLOCK(x) /* nothing */
+#define _PROP_RWLOCK_DESTROY(x) /* nothing */
+
+#else
+
+/*
+ * proplib in user space...
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+#define _PROP_ASSERT(x) /*LINTED*/assert(x)
+
+#define _PROP_MALLOC(s, t) malloc((s))
+#define _PROP_CALLOC(s, t) calloc(1, (s))
+#define _PROP_REALLOC(v, s, t) realloc((v), (s))
+#define _PROP_FREE(v, t) free((v))
+
+#define _PROP_POOL_GET(p) malloc((p))
+#define _PROP_POOL_PUT(p, v) free((v))
+
+#define _PROP_POOL_INIT(p, s, d) static const size_t p = s;
+
+#define _PROP_MALLOC_DEFINE(t, s, l) /* nothing */
+#define _PROP_MALLOC_DECLARE(t) /* nothing */
+
+#if defined(__NetBSD__) && defined(_LIBPROP)
+/*
+ * Use the same mechanism as libc; we get pthread mutexes for threaded
+ * programs and do-nothing stubs for non-threaded programs.
+ */
+#include "reentrant.h"
+#define _PROP_MUTEX_DECL_STATIC(x) static mutex_t x = MUTEX_INITIALIZER;
+#define _PROP_MUTEX_LOCK(x) mutex_lock(&(x))
+#define _PROP_MUTEX_UNLOCK(x) mutex_unlock(&(x))
+
+#define _PROP_RWLOCK_DECL(x) rwlock_t x ;
+#define _PROP_RWLOCK_INIT(x) rwlock_init(&(x), NULL)
+#define _PROP_RWLOCK_RDLOCK(x) rwlock_rdlock(&(x))
+#define _PROP_RWLOCK_WRLOCK(x) rwlock_wrlock(&(x))
+#define _PROP_RWLOCK_UNLOCK(x) rwlock_unlock(&(x))
+#define _PROP_RWLOCK_DESTROY(x) rwlock_destroy(&(x))
+#elif defined(HAVE_NBTOOL_CONFIG_H)
+/*
+ * None of NetBSD's build tools are multi-threaded.
+ */
+#define _PROP_MUTEX_DECL_STATIC(x) /* nothing */
+#define _PROP_MUTEX_LOCK(x) /* nothing */
+#define _PROP_MUTEX_UNLOCK(x) /* nothing */
+
+#define _PROP_RWLOCK_DECL(x) /* nothing */
+#define _PROP_RWLOCK_INIT(x) /* nothing */
+#define _PROP_RWLOCK_RDLOCK(x) /* nothing */
+#define _PROP_RWLOCK_WRLOCK(x) /* nothing */
+#define _PROP_RWLOCK_UNLOCK(x) /* nothing */
+#define _PROP_RWLOCK_DESTROY(x) /* nothing */
+#else
+/*
+ * Use pthread mutexes everywhere else.
+ */
+#include <pthread.h>
+#define _PROP_MUTEX_DECL_STATIC(x) \
+ static pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER;
+#define _PROP_MUTEX_LOCK(x) pthread_mutex_lock(&(x))
+#define _PROP_MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x))
+
+#define _PROP_RWLOCK_DECL(x) pthread_rwlock_t x ;
+#define _PROP_RWLOCK_INIT(x) pthread_rwlock_init(&(x), NULL)
+#define _PROP_RWLOCK_RDLOCK(x) pthread_rwlock_rdlock(&(x))
+#define _PROP_RWLOCK_WRLOCK(x) pthread_rwlock_wrlock(&(x))
+#define _PROP_RWLOCK_UNLOCK(x) pthread_rwlock_unlock(&(x))
+#define _PROP_RWLOCK_DESTROY(x) pthread_rwlock_destroy(&(x))
+#endif
+
+#endif /* _KERNEL */
+
+/*
+ * Language features.
+ */
+#if defined(__NetBSD__)
+#include <sys/cdefs.h>
+#define _PROP_ARG_UNUSED __unused
+#else
+#define _PROP_ARG_UNUSED /* delete */
+#endif /* __NetBSD__ */
+
+#endif /* _PROPLIB_PROP_SYSTEM_IMPL_H_ */
Index: common/lib/libprop/prop_xml.c
===================================================================
RCS file: common/lib/libprop/prop_xml.c
diff -N common/lib/libprop/prop_xml.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ common/lib/libprop/prop_xml.c 7 Jun 2007 13:27:09 -0000
@@ -0,0 +1,1663 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 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.
+ */
+
+#include <prop/proplib.h>
+#include "prop_object_impl.h"
+#include "prop_codec_impl.h"
+
+#if defined(_KERNEL)
+#include <sys/systm.h>
+#elif defined(_STANDALONE)
+#include <sys/param.h>
+#include <lib/libkern/libkern.h>
+#else
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#endif
+
+boolean_t _prop_object_externalize_start_tag(
+ struct _prop_object_externalize_context *,
+ const char *);
+boolean_t _prop_object_externalize_end_tag(
+ struct _prop_object_externalize_context *,
+ const char *);
+boolean_t _prop_object_externalize_empty_tag(
+ struct _prop_object_externalize_context *,
+ const char *);
+boolean_t _prop_object_externalize_append_encoded_cstring(
+ struct _prop_object_externalize_context *,
+ const char *);
+boolean_t _prop_object_externalize_header(
+ struct _prop_object_externalize_context *);
+boolean_t _prop_object_externalize_footer(
+ struct _prop_object_externalize_context *);
+
+static boolean_t _prop_object_externalize(
+ struct _prop_object_externalize_context *,
+ prop_object_t);
+
+typedef enum {
+ _PROP_TAG_TYPE_START, /* e.g. <dict> */
+ _PROP_TAG_TYPE_END, /* e.g. </dict> */
+ _PROP_TAG_TYPE_EITHER
+} _prop_tag_type_t;
+
+struct _prop_object_internalize_context {
+ const char *poic_xml;
+ const char *poic_cp;
+
+ const char *poic_tag_start;
+
+ const char *poic_tagname;
+ size_t poic_tagname_len;
+ const char *poic_tagattr;
+ size_t poic_tagattr_len;
+ const char *poic_tagattrval;
+ size_t poic_tagattrval_len;
+
+ boolean_t poic_is_empty_element;
+ _prop_tag_type_t poic_tag_type;
+};
+
+#define _PROP_EOF(c) ((c) == '\0')
+#define _PROP_ISSPACE(c) \
+ ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' || \
+ _PROP_EOF(c))
+
+#define _PROP_TAG_MATCH(ctx, t) \
+ _prop_object_internalize_match((ctx)->poic_tagname, \
+ (ctx)->poic_tagname_len, \
+ (t), strlen(t))
+
+#define _PROP_TAGATTR_MATCH(ctx, a) \
+ _prop_object_internalize_match((ctx)->poic_tagattr, \
+ (ctx)->poic_tagattr_len, \
+ (a), strlen(a))
+
+#define _PROP_TAGATTRVAL_MATCH(ctx, a) \
+ _prop_object_internalize_match((ctx)->poic_tagattrval, \
+ (ctx)->poic_tagattrval_len,\
+ (a), strlen(a))
+
+boolean_t _prop_object_internalize_find_tag(
+ struct _prop_object_internalize_context *,
+ const char *, _prop_tag_type_t);
+boolean_t _prop_object_internalize_match(const char *, size_t,
+ const char *, size_t);
+prop_object_t _prop_object_internalize_by_tag(
+ struct _prop_object_internalize_context *);
+boolean_t _prop_object_internalize_decode_string(
+ struct _prop_object_internalize_context *,
+ char *, size_t, size_t *, const char **);
+
+struct _prop_object_internalize_context *
+ _prop_object_internalize_context_alloc(const char *);
+void _prop_object_internalize_context_free(
+ struct _prop_object_internalize_context *);
+
+prop_object_t _prop_array_internalize(
+ struct _prop_object_internalize_context *);
+prop_object_t _prop_bool_internalize(
+ struct _prop_object_internalize_context *);
+prop_object_t _prop_data_internalize(
+ struct _prop_object_internalize_context *);
+prop_object_t _prop_dictionary_internalize(
+ struct _prop_object_internalize_context *);
+prop_object_t _prop_number_internalize(
+ struct _prop_object_internalize_context *);
+prop_object_t _prop_string_internalize(
+ struct _prop_object_internalize_context *);
+
+static char *prop_dictionary_externalize_xml(prop_dictionary_t);
+static char *prop_array_externalize_xml(prop_array_t);
+static prop_dictionary_t prop_dictionary_internalize_xml(const char *);
+static prop_array_t prop_array_internalize_xml(const char *);
+
+const struct _prop_codec prop_codec_xml = {
+ .codec_name = "xml",
+ .codec_sense = (const u_char *)"<",
+ .codec_dictionary_externalize = prop_dictionary_externalize_xml,
+ .codec_array_externalize = prop_array_externalize_xml,
+ .codec_dictionary_internalize = prop_dictionary_internalize_xml,
+ .codec_array_internalize = prop_array_internalize_xml,
+};
+
+static boolean_t
+_prop_array_externalize(struct _prop_object_externalize_context *ctx,
+ void *v)
+{
+ prop_array_t pa = v;
+ struct _prop_object *po;
+ prop_object_iterator_t pi;
+ unsigned int i;
+ boolean_t rv = FALSE;
+
+ _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
+
+ if (pa->pa_count == 0) {
+ _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
+ return (_prop_object_externalize_empty_tag(ctx, "array"));
+ }
+
+ /* XXXJRT Hint "count" for the internalize step? */
+ if (_prop_object_externalize_start_tag(ctx, "array") == FALSE ||
+ _prop_object_externalize_append_char(ctx, '\n') == FALSE)
+ goto out;
+
+ pi = prop_array_iterator(pa);
+ if (pi == NULL)
+ goto out;
+
+ ctx->poec_depth++;
+ _PROP_ASSERT(ctx->poec_depth != 0);
+
+ while ((po = prop_object_iterator_next(pi)) != NULL) {
+ if (_prop_object_externalize(ctx, po) == FALSE) {
+ prop_object_iterator_release(pi);
+ goto out;
+ }
+ }
+
+ prop_object_iterator_release(pi);
+
+ ctx->poec_depth--;
+ for (i = 0; i < ctx->poec_depth; i++) {
+ if (_prop_object_externalize_append_char(ctx, '\t') == FALSE)
+ goto out;
+ }
+ if (_prop_object_externalize_end_tag(ctx, "array") == FALSE)
+ goto out;
+
+ rv = TRUE;
+
+ out:
+ _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
+ return (rv);
+}
+
+/*
+ * prop_array_externalize --
+ * Externalize an array, return a NUL-terminated buffer
+ * containing the XML-style representation. The buffer is allocated
+ * with the M_TEMP memory type.
+ */
+static char *
+prop_array_externalize_xml(prop_array_t pa)
+{
+ struct _prop_object_externalize_context *ctx;
+ char *cp;
+
+ ctx = _prop_object_externalize_context_alloc();
+ if (ctx == NULL)
+ return (NULL);
+
+ if (_prop_object_externalize_header(ctx) == FALSE ||
+ _prop_object_externalize(ctx, &pa->pa_obj) == FALSE ||
+ _prop_object_externalize_footer(ctx) == FALSE) {
+ /* We are responsible for releasing the buffer. */
+ _PROP_FREE(ctx->poec_buf, M_TEMP);
+ _prop_object_externalize_context_free(ctx);
+ return (NULL);
+ }
+
+ cp = ctx->poec_buf;
+ _prop_object_externalize_context_free(ctx);
+
+ return (cp);
+}
+
+/*
+ * _prop_array_internalize --
+ * Parse an <array>...</array> and return the object created from the
+ * external representation.
+ */
+prop_object_t
+_prop_array_internalize(struct _prop_object_internalize_context *ctx)
+{
+ prop_array_t array;
+ prop_object_t obj;
+
+ /* We don't currently understand any attributes. */
+ if (ctx->poic_tagattr != NULL)
+ return (NULL);
+
+ array = prop_array_create();
+ if (array == NULL)
+ return (NULL);
+
+ if (ctx->poic_is_empty_element)
+ return (array);
+
+ for (;;) {
+ /* Fetch the next tag. */
+ if (_prop_object_internalize_find_tag(ctx, NULL,
+ _PROP_TAG_TYPE_EITHER) == FALSE)
+ goto bad;
+
+ /* Check to see if this is the end of the array. */
+ if (_PROP_TAG_MATCH(ctx, "array") &&
+ ctx->poic_tag_type == _PROP_TAG_TYPE_END)
+ break;
+
+ /* Fetch the object. */
+ obj = _prop_object_internalize_by_tag(ctx);
+ if (obj == NULL)
+ goto bad;
+
+ if (prop_array_add(array, obj) == FALSE) {
+ prop_object_release(obj);
+ goto bad;
+ }
+ prop_object_release(obj);
+ }
+
+ return (array);
+
+ bad:
+ prop_object_release(array);
+ return (NULL);
+}
+
+/*
+ * prop_array_internalize --
+ * Create an array by parsing the XML-style representation.
+ */
+static prop_array_t
+prop_array_internalize_xml(const char *xml)
+{
+ prop_array_t array = NULL;
+ struct _prop_object_internalize_context *ctx;
+
+ ctx = _prop_object_internalize_context_alloc(xml);
+ if (ctx == NULL)
+ return (NULL);
+
+ /* We start with a <plist> tag. */
+ if (_prop_object_internalize_find_tag(ctx, "plist",
+ _PROP_TAG_TYPE_START) == FALSE)
+ goto out;
+
+ /* Plist elements cannot be empty. */
+ if (ctx->poic_is_empty_element)
+ goto out;
+
+ /*
+ * We don't understand any plist attributes, but Apple XML
+ * property lists often have a "version" attribute. If we
+ * see that one, we simply ignore it.
+ */
+ if (ctx->poic_tagattr != NULL &&
+ !_PROP_TAGATTR_MATCH(ctx, "version"))
+ goto out;
+
+ /* Next we expect to see <array>. */
+ if (_prop_object_internalize_find_tag(ctx, "array",
+ _PROP_TAG_TYPE_START) == FALSE)
+ goto out;
+
+ array = _prop_array_internalize(ctx);
+ if (array == NULL)
+ goto out;
+
+ /* We've advanced past </array>. Now we want </plist>. */
+ if (_prop_object_internalize_find_tag(ctx, "plist",
+ _PROP_TAG_TYPE_END) == FALSE) {
+ prop_object_release(array);
+ array = NULL;
+ }
+
+ out:
+ _prop_object_internalize_context_free(ctx);
+ return (array);
+}
+
+static boolean_t
+_prop_bool_externalize(struct _prop_object_externalize_context *ctx,
+ void *v)
+{
+ prop_bool_t pb = v;
+
+ return (_prop_object_externalize_empty_tag(ctx,
+ prop_bool_true(pb) ? "true" : "false"));
+}
+
+
+/*
+ * _prop_bool_internalize --
+ * Parse a <true/> or <false/> and return the object created from
+ * the external representation.
+ */
+prop_object_t
+_prop_bool_internalize(struct _prop_object_internalize_context *ctx)
+{
+ boolean_t val;
+
+ /* No attributes, and it must be an empty element. */
+ if (ctx->poic_tagattr != NULL ||
+ ctx->poic_is_empty_element == FALSE)
+ return (NULL);
+
+ if (_PROP_TAG_MATCH(ctx, "true"))
+ val = TRUE;
+ else {
+ _PROP_ASSERT(_PROP_TAG_MATCH(ctx, "false"));
+ val = FALSE;
+ }
+
+ return (prop_bool_create(val));
+}
+static const char _prop_data_base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char _prop_data_pad64 = '=';
+
+static boolean_t
+_prop_data_externalize(struct _prop_object_externalize_context *ctx, void *v)
+{
+ prop_data_t pd = v;
+ size_t i, srclen;
+ const uint8_t *src;
+ uint8_t output[4];
+ uint8_t input[3];
+
+ if (pd->pd_size == 0)
+ return (_prop_object_externalize_empty_tag(ctx, "data"));
+
+ if (_prop_object_externalize_start_tag(ctx, "data") == FALSE)
+ return (FALSE);
+
+ for (src = pd->pd_immutable, srclen = pd->pd_size;
+ srclen > 2; srclen -= 3) {
+ input[0] = *src++;
+ input[1] = *src++;
+ input[2] = *src++;
+
+ output[0] = (uint32_t)input[0] >> 2;
+ output[1] = ((uint32_t)(input[0] & 0x03) << 4) +
+ ((uint32_t)input[1] >> 4);
+ output[2] = ((u_int32_t)(input[1] & 0x0f) << 2) +
+ ((uint32_t)input[2] >> 6);
+ output[3] = input[2] & 0x3f;
+ _PROP_ASSERT(output[0] < 64);
+ _PROP_ASSERT(output[1] < 64);
+ _PROP_ASSERT(output[2] < 64);
+ _PROP_ASSERT(output[3] < 64);
+
+ if (_prop_object_externalize_append_char(ctx,
+ _prop_data_base64[output[0]]) == FALSE ||
+ _prop_object_externalize_append_char(ctx,
+ _prop_data_base64[output[1]]) == FALSE ||
+ _prop_object_externalize_append_char(ctx,
+ _prop_data_base64[output[2]]) == FALSE ||
+ _prop_object_externalize_append_char(ctx,
+ _prop_data_base64[output[3]]) == FALSE)
+ return (FALSE);
+ }
+
+ if (srclen != 0) {
+ input[0] = input[1] = input[2] = '\0';
+ for (i = 0; i < srclen; i++)
+ input[i] = *src++;
+
+ output[0] = (uint32_t)input[0] >> 2;
+ output[1] = ((uint32_t)(input[0] & 0x03) << 4) +
+ ((uint32_t)input[1] >> 4);
+ output[2] = ((u_int32_t)(input[1] & 0x0f) << 2) +
+ ((uint32_t)input[2] >> 6);
+ _PROP_ASSERT(output[0] < 64);
+ _PROP_ASSERT(output[1] < 64);
+ _PROP_ASSERT(output[2] < 64);
+
+ if (_prop_object_externalize_append_char(ctx,
+ _prop_data_base64[output[0]]) == FALSE ||
+ _prop_object_externalize_append_char(ctx,
+ _prop_data_base64[output[1]]) == FALSE ||
+ _prop_object_externalize_append_char(ctx,
+ srclen == 1 ? _prop_data_pad64
+ : _prop_data_base64[output[2]]) == FALSE ||
+ _prop_object_externalize_append_char(ctx,
+ _prop_data_pad64) == FALSE)
+ return (FALSE);
+ }
+
+ if (_prop_object_externalize_end_tag(ctx, "data") == FALSE)
+ return (FALSE);
+
+ return (TRUE);
+}
+
+static boolean_t
+_prop_data_internalize_decode(struct _prop_object_internalize_context *ctx,
+ uint8_t *target, size_t targsize, size_t *sizep,
+ const char **cpp)
+{
+ const char *src;
+ size_t tarindex;
+ int state, ch;
+ const char *pos;
+
+ state = 0;
+ tarindex = 0;
+ src = ctx->poic_cp;
+
+ for (;;) {
+ ch = (unsigned char) *src++;
+ if (_PROP_EOF(ch))
+ return (FALSE);
+ if (_PROP_ISSPACE(ch))
+ continue;
+ if (ch == '<') {
+ src--;
+ break;
+ }
+ if (ch == _prop_data_pad64)
+ break;
+
+ pos = strchr(_prop_data_base64, ch);
+ if (pos == NULL)
+ return (FALSE);
+
+ switch (state) {
+ case 0:
+ if (target) {
+ if (tarindex >= targsize)
+ return (FALSE);
+ target[tarindex] =
+ (uint8_t)((pos - _prop_data_base64) << 2);
+ }
+ state = 1;
+ break;
+
+ case 1:
+ if (target) {
+ if (tarindex + 1 >= targsize)
+ return (FALSE);
+ target[tarindex] |=
+ (uint32_t)(pos - _prop_data_base64) >> 4;
+ target[tarindex + 1] =
+ (uint8_t)(((pos - _prop_data_base64) & 0xf)
+ << 4);
+ }
+ tarindex++;
+ state = 2;
+ break;
+
+ case 2:
+ if (target) {
+ if (tarindex + 1 >= targsize)
+ return (FALSE);
+ target[tarindex] |=
+ (uint32_t)(pos - _prop_data_base64) >> 2;
+ target[tarindex + 1] =
+ (uint8_t)(((pos - _prop_data_base64)
+ & 0x3) << 6);
+ }
+ tarindex++;
+ state = 3;
+ break;
+
+ case 3:
+ if (target) {
+ if (tarindex >= targsize)
+ return (FALSE);
+ target[tarindex] |= (uint8_t)
+ (pos - _prop_data_base64);
+ }
+ tarindex++;
+ state = 0;
+ break;
+
+ default:
+ _PROP_ASSERT(/*CONSTCOND*/0);
+ }
+ }
+
+ /*
+ * We are done decoding the Base64 characters. Let's see if we
+ * ended up on a byte boundary and/or with unrecognized trailing
+ * characters.
+ */
+ if (ch == _prop_data_pad64) {
+ ch = (unsigned char) *src; /* src already advanced */
+ if (_PROP_EOF(ch))
+ return (FALSE);
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return (FALSE);
+
+ case 2: /* Valid, one byte of info */
+ /* Skip whitespace */
+ for (ch = (unsigned char) *src++;
+ ch != '<'; ch = (unsigned char) *src++) {
+ if (_PROP_EOF(ch))
+ return (FALSE);
+ if (!_PROP_ISSPACE(ch))
+ break;
+ }
+ /* Make sure there is another trailing = */
+ if (ch != _prop_data_pad64)
+ return (FALSE);
+ ch = (unsigned char) *src;
+ /* FALLTHROUGH */
+
+ case 3: /* Valid, two bytes of info */
+ /*
+ * We know this char is a =. Is there anything but
+ * whitespace after it?
+ */
+ for (; ch != '<'; ch = (unsigned char) *src++) {
+ if (_PROP_EOF(ch))
+ return (FALSE);
+ if (!_PROP_ISSPACE(ch))
+ return (FALSE);
+ }
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the Base64 string. Make
+ * sure there are no partial bytes lying around.
+ */
+ if (state != 0)
+ return (FALSE);
+ }
+
+ _PROP_ASSERT(*src == '<');
+ if (sizep != NULL)
+ *sizep = tarindex;
+ if (cpp != NULL)
+ *cpp = src;
+
+ return (TRUE);
+}
+
+/*
+ * _prop_data_internalize --
+ * Parse a <data>...</data> and return the object created from the
+ * external representation.
+ */
+prop_object_t
+_prop_data_internalize(struct _prop_object_internalize_context *ctx)
+{
+ prop_data_t data;
+ uint8_t *buf;
+ size_t len, alen;
+
+ /* We don't accept empty elements. */
+ if (ctx->poic_is_empty_element)
+ return (NULL);
+
+ /*
+ * If we got a "size" attribute, get the size of the data blob
+ * from that. Otherwise, we have to figure it out from the base64.
+ */
+ if (ctx->poic_tagattr != NULL) {
+ char *cp;
+
+ if (!_PROP_TAGATTR_MATCH(ctx, "size") ||
+ ctx->poic_tagattrval_len == 0)
+ return (NULL);
+
+#ifndef _KERNEL
+ errno = 0;
+#endif
+ /* XXX Assumes size_t and unsigned long are the same size. */
+ len = strtoul(ctx->poic_tagattrval, &cp, 0);
+#ifndef _KERNEL /* XXX can't check for ERANGE in the kernel */
+ if (len == ULONG_MAX && errno == ERANGE)
+ return (NULL);
+#endif
+ if (cp != ctx->poic_tagattrval + ctx->poic_tagattrval_len)
+ return (NULL);
+ _PROP_ASSERT(*cp == '\"');
+ } else if (_prop_data_internalize_decode(ctx, NULL, 0, &len,
+ NULL) == FALSE)
+ return (NULL);
+
+ /*
+ * Always allocate one extra in case we don't land on an even byte
+ * boundary during the decode.
+ */
+ buf = _PROP_MALLOC(len + 1, M_PROP_DATA);
+ if (buf == NULL)
+ return (NULL);
+
+ if (_prop_data_internalize_decode(ctx, buf, len + 1, &alen,
+ &ctx->poic_cp) == FALSE) {
+ _PROP_FREE(buf, M_PROP_DATA);
+ return (NULL);
+ }
+ if (alen != len) {
+ _PROP_FREE(buf, M_PROP_DATA);
+ return (NULL);
+ }
+
+ if (_prop_object_internalize_find_tag(ctx, "data",
+ _PROP_TAG_TYPE_END) == FALSE) {
+ _PROP_FREE(buf, M_PROP_DATA);
+ return (NULL);
+ }
+
+ data = _prop_data_alloc();
+ if (data == NULL) {
+ _PROP_FREE(buf, M_PROP_DATA);
+ return (NULL);
+ }
+
+ data->pd_mutable = buf;
+ data->pd_size = len;
+
+ return (data);
+}
+static boolean_t
+_prop_dict_keysym_externalize(struct _prop_object_externalize_context *ctx,
+ void *v)
+{
+ prop_dictionary_keysym_t pdk = v;
+ const char *s = prop_dictionary_keysym_cstring_nocopy(pdk);
+
+ /* We externalize these as strings, and they're never empty. */
+
+ _PROP_ASSERT(s[0] != '\0');
+
+ if (_prop_object_externalize_start_tag(ctx, "string") == FALSE ||
+ _prop_object_externalize_append_encoded_cstring(ctx, s) == FALSE ||
+ _prop_object_externalize_end_tag(ctx, "string") == FALSE)
+ return (FALSE);
+
+ return (TRUE);
+}
+
+static boolean_t
+_prop_dictionary_externalize(struct _prop_object_externalize_context *ctx,
+ void *v)
+{
+ prop_dictionary_t pd = v;
+ prop_dictionary_keysym_t pdk;
+ struct _prop_object *po;
+ prop_object_iterator_t pi;
+ unsigned int i;
+ boolean_t rv = FALSE;
+
+ _PROP_RWLOCK_RDLOCK(pd->pd_rwlock);
+
+ if (pd->pd_count == 0) {
+ _PROP_RWLOCK_UNLOCK(pd->pd_rwlock);
+ return (_prop_object_externalize_empty_tag(ctx, "dict"));
+ }
+
+ if (_prop_object_externalize_start_tag(ctx, "dict") == FALSE ||
+ _prop_object_externalize_append_char(ctx, '\n') == FALSE)
+ goto out;
+
+ pi = prop_dictionary_iterator(pd);
+ if (pi == NULL)
+ goto out;
+
+ ctx->poec_depth++;
+ _PROP_ASSERT(ctx->poec_depth != 0);
+
+ while ((pdk = prop_object_iterator_next(pi)) != NULL) {
+ po = prop_dictionary_get_keysym(pd, pdk);
+ if (po == NULL ||
+ _prop_object_externalize_start_tag(ctx, "key") == FALSE ||
+ _prop_object_externalize_append_encoded_cstring(ctx,
+ prop_dictionary_keysym_cstring_nocopy(pdk)) == FALSE ||
+ _prop_object_externalize_end_tag(ctx, "key") == FALSE ||
+ _prop_object_externalize(ctx, po) == FALSE) {
+ prop_object_iterator_release(pi);
+ goto out;
+ }
+ }
+
+ prop_object_iterator_release(pi);
+
+ ctx->poec_depth--;
+ for (i = 0; i < ctx->poec_depth; i++) {
+ if (_prop_object_externalize_append_char(ctx, '\t') == FALSE)
+ goto out;
+ }
+ if (_prop_object_externalize_end_tag(ctx, "dict") == FALSE)
+ goto out;
+
+ rv = TRUE;
+
+ out:
+ _PROP_RWLOCK_UNLOCK(pd->pd_rwlock);
+ return (rv);
+}
+
+/*
+ * prop_dictionary_externalize --
+ * Externalize a dictionary, returning a NUL-terminated buffer
+ * containing the XML-style representation. The buffer is allocated
+ * with the M_TEMP memory type.
+ */
+static char *
+prop_dictionary_externalize_xml(prop_dictionary_t pd)
+{
+ struct _prop_object_externalize_context *ctx;
+ char *cp;
+
+ ctx = _prop_object_externalize_context_alloc();
+ if (ctx == NULL)
+ return (NULL);
+
+ if (_prop_object_externalize_header(ctx) == FALSE ||
+ _prop_object_externalize(ctx, &pd->pd_obj) == FALSE ||
+ _prop_object_externalize_footer(ctx) == FALSE) {
+ /* We are responsible for releasing the buffer. */
+ _PROP_FREE(ctx->poec_buf, M_TEMP);
+ _prop_object_externalize_context_free(ctx);
+ return (NULL);
+ }
+
+ cp = ctx->poec_buf;
+ _prop_object_externalize_context_free(ctx);
+
+ return (cp);
+}
+
+/*
+ * _prop_dictionary_internalize --
+ * Parse a <dict>...</dict> and return the object created from the
+ * external representation.
+ */
+prop_object_t
+_prop_dictionary_internalize(struct _prop_object_internalize_context *ctx)
+{
+ prop_dictionary_t dict;
+ prop_object_t val;
+ size_t keylen;
+ char *tmpkey;
+
+ /* We don't currently understand any attributes. */
+ if (ctx->poic_tagattr != NULL)
+ return (NULL);
+
+ dict = prop_dictionary_create();
+ if (dict == NULL)
+ return (NULL);
+
+ if (ctx->poic_is_empty_element)
+ return (dict);
+
+ tmpkey = _PROP_MALLOC(_PROP_PDK_MAXKEY + 1, M_TEMP);
+ if (tmpkey == NULL)
+ goto bad;
+
+ for (;;) {
+ /* Fetch the next tag. */
+ if (_prop_object_internalize_find_tag(ctx, NULL,
+ _PROP_TAG_TYPE_EITHER) == FALSE)
+ goto bad;
+
+ /* Check to see if this is the end of the dictionary. */
+ if (_PROP_TAG_MATCH(ctx, "dict") &&
+ ctx->poic_tag_type == _PROP_TAG_TYPE_END)
+ break;
+
+ /* Ok, it must be a non-empty key start tag. */
+ if (!_PROP_TAG_MATCH(ctx, "key") ||
+ ctx->poic_tag_type != _PROP_TAG_TYPE_START ||
+ ctx->poic_is_empty_element)
+ goto bad;
+
+ if (_prop_object_internalize_decode_string(ctx,
+ tmpkey, _PROP_PDK_MAXKEY,
+ &keylen, &ctx->poic_cp) ==
+ FALSE)
+ goto bad;
+
+ _PROP_ASSERT(keylen <= _PROP_PDK_MAXKEY);
+ tmpkey[keylen] = '\0';
+
+ if (_prop_object_internalize_find_tag(ctx, "key",
+ _PROP_TAG_TYPE_END) == FALSE)
+ goto bad;
+
+ /* ..and now the beginning of the value. */
+ if (_prop_object_internalize_find_tag(ctx, NULL,
+ _PROP_TAG_TYPE_START) == FALSE)
+ goto bad;
+
+ val = _prop_object_internalize_by_tag(ctx);
+ if (val == NULL)
+ goto bad;
+
+ if (prop_dictionary_set(dict, tmpkey, val) == FALSE) {
+ prop_object_release(val);
+ goto bad;
+ }
+ prop_object_release(val);
+ }
+
+ _PROP_FREE(tmpkey, M_TEMP);
+ return (dict);
+
+ bad:
+ if (tmpkey != NULL)
+ _PROP_FREE(tmpkey, M_TEMP);
+ prop_object_release(dict);
+ return (NULL);
+}
+
+/*
+ * prop_dictionary_internalize --
+ * Create a dictionary by parsing the NUL-terminated XML-style
+ * representation.
+ */
+static prop_dictionary_t
+prop_dictionary_internalize_xml(const char *xml)
+{
+ prop_dictionary_t dict = NULL;
+ struct _prop_object_internalize_context *ctx;
+
+ ctx = _prop_object_internalize_context_alloc(xml);
+ if (ctx == NULL)
+ return (NULL);
+
+ /* We start with a <plist> tag. */
+ if (_prop_object_internalize_find_tag(ctx, "plist",
+ _PROP_TAG_TYPE_START) == FALSE)
+ goto out;
+
+ /* Plist elements cannot be empty. */
+ if (ctx->poic_is_empty_element)
+ goto out;
+
+ /*
+ * We don't understand any plist attributes, but Apple XML
+ * property lists often have a "version" attribute. If we
+ * see that one, we simply ignore it.
+ */
+ if (ctx->poic_tagattr != NULL &&
+ !_PROP_TAGATTR_MATCH(ctx, "version"))
+ goto out;
+
+ /* Next we expect to see <dict>. */
+ if (_prop_object_internalize_find_tag(ctx, "dict",
+ _PROP_TAG_TYPE_START) == FALSE)
+ goto out;
+
+ dict = _prop_dictionary_internalize(ctx);
+ if (dict == NULL)
+ goto out;
+
+ /* We've advanced past </dict>. Now we want </plist>. */
+ if (_prop_object_internalize_find_tag(ctx, "plist",
+ _PROP_TAG_TYPE_END) == FALSE) {
+ prop_object_release(dict);
+ dict = NULL;
+ }
+
+ out:
+ _prop_object_internalize_context_free(ctx);
+ return (dict);
+}
+
+static boolean_t
+_prop_number_externalize(struct _prop_object_externalize_context *ctx,
+ void *v)
+{
+ prop_number_t pn = v;
+ char tmpstr[32];
+
+ /*
+ * For unsigned numbers, we output in hex. For signed numbers,
+ * we output in decimal.
+ */
+ if (prop_number_unsigned(pn))
+ sprintf(tmpstr, "0x%" PRIx64,
+ prop_number_unsigned_integer_value(pn));
+ else
+ sprintf(tmpstr, "%" PRIi64, prop_number_integer_value(pn));
+
+ if (_prop_object_externalize_start_tag(ctx, "integer") == FALSE ||
+ _prop_object_externalize_append_cstring(ctx, tmpstr) == FALSE ||
+ _prop_object_externalize_end_tag(ctx, "integer") == FALSE)
+ return (FALSE);
+
+ return (TRUE);
+}
+
+static boolean_t
+_prop_number_internalize_unsigned(struct _prop_object_internalize_context *ctx,
+ struct _prop_number_value *pnv)
+{
+ char *cp;
+
+ _PROP_ASSERT(/*CONSTCOND*/sizeof(unsigned long long) ==
+ sizeof(uint64_t));
+
+#ifndef _KERNEL
+ errno = 0;
+#endif
+ pnv->pnv_unsigned = (uint64_t) strtoull(ctx->poic_cp, &cp, 0);
+#ifndef _KERNEL /* XXX can't check for ERANGE in the kernel */
+ if (pnv->pnv_unsigned == UINT64_MAX && errno == ERANGE)
+ return (FALSE);
+#endif
+ pnv->pnv_is_unsigned = TRUE;
+ ctx->poic_cp = cp;
+
+ return (TRUE);
+}
+
+static boolean_t
+_prop_number_internalize_signed(struct _prop_object_internalize_context *ctx,
+ struct _prop_number_value *pnv)
+{
+ char *cp;
+
+ _PROP_ASSERT(/*CONSTCOND*/sizeof(long long) == sizeof(int64_t));
+
+#ifndef _KERNEL
+ errno = 0;
+#endif
+ pnv->pnv_signed = (int64_t) strtoll(ctx->poic_cp, &cp, 0);
+#ifndef _KERNEL /* XXX can't check for ERANGE in the kernel */
+ if ((pnv->pnv_signed == INT64_MAX || pnv->pnv_signed == INT64_MIN) &&
+ errno == ERANGE)
+ return (FALSE);
+#endif
+ pnv->pnv_is_unsigned = FALSE;
+ ctx->poic_cp = cp;
+
+ return (TRUE);
+}
+
+/*
+ * _prop_number_internalize --
+ * Parse a <number>...</number> and return the object created from
+ * the external representation.
+ */
+prop_object_t
+_prop_number_internalize(struct _prop_object_internalize_context *ctx)
+{
+ struct _prop_number_value pnv;
+
+ memset(&pnv, 0, sizeof(pnv));
+
+ /* No attributes, no empty elements. */
+ if (ctx->poic_tagattr != NULL || ctx->poic_is_empty_element)
+ return (NULL);
+
+ /*
+ * If the first character is '-', then we treat as signed.
+ * If the first two characters are "0x" (i.e. the number is
+ * in hex), then we treat as unsigned. Otherwise, we try
+ * signed first, and if that fails (presumably due to ERANGE),
+ * then we switch to unsigned.
+ */
+ if (ctx->poic_cp[0] == '-') {
+ if (_prop_number_internalize_signed(ctx, &pnv) == FALSE)
+ return (NULL);
+ } else if (ctx->poic_cp[0] == '0' && ctx->poic_cp[1] == 'x') {
+ if (_prop_number_internalize_unsigned(ctx, &pnv) == FALSE)
+ return (NULL);
+ } else {
+ if (_prop_number_internalize_signed(ctx, &pnv) == FALSE &&
+ _prop_number_internalize_unsigned(ctx, &pnv) == FALSE)
+ return (NULL);
+ }
+
+ if (_prop_object_internalize_find_tag(ctx, "integer",
+ _PROP_TAG_TYPE_END) == FALSE)
+ return (NULL);
+
+ return (_prop_number_alloc(&pnv));
+}
+/*
+ * _prop_object_externalize_start_tag --
+ * Append an XML-style start tag to the externalize buffer.
+ */
+boolean_t
+_prop_object_externalize_start_tag(
+ struct _prop_object_externalize_context *ctx, const char *tag)
+{
+ unsigned int i;
+
+ for (i = 0; i < ctx->poec_depth; i++) {
+ if (_prop_object_externalize_append_char(ctx, '\t') == FALSE)
+ return (FALSE);
+ }
+ if (_prop_object_externalize_append_char(ctx, '<') == FALSE ||
+ _prop_object_externalize_append_cstring(ctx, tag) == FALSE ||
+ _prop_object_externalize_append_char(ctx, '>') == FALSE)
+ return (FALSE);
+
+ return (TRUE);
+}
+
+/*
+ * _prop_object_externalize_end_tag --
+ * Append an XML-style end tag to the externalize buffer.
+ */
+boolean_t
+_prop_object_externalize_end_tag(
+ struct _prop_object_externalize_context *ctx, const char *tag)
+{
+
+ if (_prop_object_externalize_append_char(ctx, '<') == FALSE ||
+ _prop_object_externalize_append_char(ctx, '/') == FALSE ||
+ _prop_object_externalize_append_cstring(ctx, tag) == FALSE ||
+ _prop_object_externalize_append_char(ctx, '>') == FALSE ||
+ _prop_object_externalize_append_char(ctx, '\n') == FALSE)
+ return (FALSE);
+
+ return (TRUE);
+}
+
+/*
+ * _prop_object_externalize_empty_tag --
+ * Append an XML-style empty tag to the externalize buffer.
+ */
+boolean_t
+_prop_object_externalize_empty_tag(
+ struct _prop_object_externalize_context *ctx, const char *tag)
+{
+ unsigned int i;
+
+ for (i = 0; i < ctx->poec_depth; i++) {
+ if (_prop_object_externalize_append_char(ctx, '\t') == FALSE)
+ return (FALSE);
+ }
+
+ if (_prop_object_externalize_append_char(ctx, '<') == FALSE ||
+ _prop_object_externalize_append_cstring(ctx, tag) == FALSE ||
+ _prop_object_externalize_append_char(ctx, '/') == FALSE ||
+ _prop_object_externalize_append_char(ctx, '>') == FALSE ||
+ _prop_object_externalize_append_char(ctx, '\n') == FALSE)
+ return (FALSE);
+
+ return (TRUE);
+}
+
+/*
+ * _prop_object_externalize_append_encoded_cstring --
+ * Append an encoded C string to the externalize buffer.
+ */
+boolean_t
+_prop_object_externalize_append_encoded_cstring(
+ struct _prop_object_externalize_context *ctx, const char *cp)
+{
+
+ while (*cp != '\0') {
+ switch (*cp) {
+ case '<':
+ if (_prop_object_externalize_append_cstring(ctx,
+ "<") == FALSE)
+ return (FALSE);
+ break;
+ case '>':
+ if (_prop_object_externalize_append_cstring(ctx,
+ ">") == FALSE)
+ return (FALSE);
+ break;
+ case '&':
+ if (_prop_object_externalize_append_cstring(ctx,
+ "&") == FALSE)
+ return (FALSE);
+ break;
+ default:
+ if (_prop_object_externalize_append_char(ctx,
+ (unsigned char) *cp) == FALSE)
+ return (FALSE);
+ break;
+ }
+ cp++;
+ }
+
+ return (TRUE);
+}
+
+/*
+ * _prop_object_externalize_header --
+ * Append the standard XML header to the externalize buffer.
+ */
+boolean_t
+_prop_object_externalize_header(struct _prop_object_externalize_context *ctx)
+{
+ static const char _plist_xml_header[] =
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+"<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"
http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n";
+
+ if (_prop_object_externalize_append_cstring(ctx,
+ _plist_xml_header) == FALSE ||
+ _prop_object_externalize_start_tag(ctx,
+ "plist version=\"1.0\"") == FALSE ||
+ _prop_object_externalize_append_char(ctx, '\n') == FALSE)
+ return (FALSE);
+
+ return (TRUE);
+}
+
+/*
+ * _prop_object_externalize_footer --
+ * Append the standard XML footer to the externalize buffer. This
+ * also NUL-terminates the buffer.
+ */
+boolean_t
+_prop_object_externalize_footer(struct _prop_object_externalize_context *ctx)
+{
+
+ if (_prop_object_externalize_end_tag(ctx, "plist") == FALSE ||
+ _prop_object_externalize_append_char(ctx, '\0') == FALSE)
+ return (FALSE);
+
+ return (TRUE);
+}
+
+/*
+ * _prop_object_internalize_skip_comment --
+ * Skip the body and end tag of a comment.
+ */
+static boolean_t
+_prop_object_internalize_skip_comment(
+ struct _prop_object_internalize_context *ctx)
+{
+ const char *cp = ctx->poic_cp;
+
+ while (!_PROP_EOF(*cp)) {
+ if (cp[0] == '-' &&
+ cp[1] == '-' &&
+ cp[2] == '>') {
+ ctx->poic_cp = cp + 3;
+ return (TRUE);
+ }
+ cp++;
+ }
+
+ return (FALSE); /* ran out of buffer */
+}
+
+/*
+ * _prop_object_internalize_find_tag --
+ * Find the next tag in an XML stream. Optionally compare the found
+ * tag to an expected tag name. State of the context is undefined
+ * if this routine returns FALSE. Upon success, the context points
+ * to the first octet after the tag.
+ */
+boolean_t
+_prop_object_internalize_find_tag(struct _prop_object_internalize_context *ctx,
+ const char *tag, _prop_tag_type_t type)
+{
+ const char *cp;
+ size_t taglen;
+
+ if (tag != NULL)
+ taglen = strlen(tag);
+ else
+ taglen = 0;
+
+ start_over:
+ cp = ctx->poic_cp;
+
+ /*
+ * Find the start of the tag.
+ */
+ while (_PROP_ISSPACE(*cp))
+ cp++;
+ if (_PROP_EOF(*cp))
+ return (FALSE);
+
+ if (*cp != '<')
+ return (FALSE);
+
+ ctx->poic_tag_start = cp++;
+ if (_PROP_EOF(*cp))
+ return (FALSE);
+
+ if (*cp == '!') {
+ if (cp[1] != '-' || cp[2] != '-')
+ return (FALSE);
+ /*
+ * Comment block -- only allowed if we are allowed to
+ * return a start tag.
+ */
+ if (type == _PROP_TAG_TYPE_END)
+ return (FALSE);
+ ctx->poic_cp = cp + 3;
+ if (_prop_object_internalize_skip_comment(ctx) == FALSE)
+ return (FALSE);
+ goto start_over;
+ }
+
+ if (*cp == '/') {
+ if (type != _PROP_TAG_TYPE_END &&
+ type != _PROP_TAG_TYPE_EITHER)
+ return (FALSE);
+ cp++;
+ if (_PROP_EOF(*cp))
+ return (FALSE);
+ ctx->poic_tag_type = _PROP_TAG_TYPE_END;
+ } else {
+ if (type != _PROP_TAG_TYPE_START &&
+ type != _PROP_TAG_TYPE_EITHER)
+ return (FALSE);
+ ctx->poic_tag_type = _PROP_TAG_TYPE_START;
+ }
+
+ ctx->poic_tagname = cp;
+
+ while (!_PROP_ISSPACE(*cp) && *cp != '/' && *cp != '>')
+ cp++;
+ if (_PROP_EOF(*cp))
+ return (FALSE);
+
+ ctx->poic_tagname_len = cp - ctx->poic_tagname;
+
+ /* Make sure this is the tag we're looking for. */
+ if (tag != NULL &&
+ (taglen != ctx->poic_tagname_len ||
+ memcmp(tag, ctx->poic_tagname, taglen) != 0))
+ return (FALSE);
+
+ /* Check for empty tag. */
+ if (*cp == '/') {
+ if (ctx->poic_tag_type != _PROP_TAG_TYPE_START)
+ return(FALSE); /* only valid on start tags */
+ ctx->poic_is_empty_element = TRUE;
+ cp++;
+ if (_PROP_EOF(*cp) || *cp != '>')
+ return (FALSE);
+ } else
+ ctx->poic_is_empty_element = FALSE;
+
+ /* Easy case of no arguments. */
+ if (*cp == '>') {
+ ctx->poic_tagattr = NULL;
+ ctx->poic_tagattr_len = 0;
+ ctx->poic_tagattrval = NULL;
+ ctx->poic_tagattrval_len = 0;
+ ctx->poic_cp = cp + 1;
+ return (TRUE);
+ }
+
+ _PROP_ASSERT(!_PROP_EOF(*cp));
+ cp++;
+ if (_PROP_EOF(*cp))
+ return (FALSE);
+
+ while (_PROP_ISSPACE(*cp))
+ cp++;
+ if (_PROP_EOF(*cp))
+ return (FALSE);
+
+ ctx->poic_tagattr = cp;
+
+ while (!_PROP_ISSPACE(*cp) && *cp != '=')
+ cp++;
+ if (_PROP_EOF(*cp))
+ return (FALSE);
+
+ ctx->poic_tagattr_len = cp - ctx->poic_tagattr;
+
+ cp++;
+ if (*cp != '\"')
+ return (FALSE);
+ cp++;
+ if (_PROP_EOF(*cp))
+ return (FALSE);
+
+ ctx->poic_tagattrval = cp;
+ while (*cp != '\"')
+ cp++;
+ if (_PROP_EOF(*cp))
+ return (FALSE);
+ ctx->poic_tagattrval_len = cp - ctx->poic_tagattrval;
+
+ cp++;
+ if (*cp != '>')
+ return (FALSE);
+
+ ctx->poic_cp = cp + 1;
+ return (TRUE);
+}
+
+/*
+ * _prop_object_internalize_decode_string --
+ * Decode an encoded string.
+ */
+boolean_t
+_prop_object_internalize_decode_string(
+ struct _prop_object_internalize_context *ctx,
+ char *target, size_t targsize, size_t *sizep,
+ const char **cpp)
+{
+ const char *src;
+ size_t tarindex;
+ char c;
+
+ tarindex = 0;
+ src = ctx->poic_cp;
+
+ for (;;) {
+ if (_PROP_EOF(*src))
+ return (FALSE);
+ if (*src == '<') {
+ break;
+ }
+
+ if ((c = *src) == '&') {
+ if (src[1] == 'a' &&
+ src[2] == 'm' &&
+ src[3] == 'p' &&
+ src[4] == ';') {
+ c = '&';
+ src += 5;
+ } else if (src[1] == 'l' &&
+ src[2] == 't' &&
+ src[3] == ';') {
+ c = '<';
+ src += 4;
+ } else if (src[1] == 'g' &&
+ src[2] == 't' &&
+ src[3] == ';') {
+ c = '>';
+ src += 4;
+ } else if (src[1] == 'a' &&
+ src[2] == 'p' &&
+ src[3] == 'o' &&
+ src[4] == 's' &&
+ src[5] == ';') {
+ c = '\'';
+ src += 6;
+ } else if (src[1] == 'q' &&
+ src[2] == 'u' &&
+ src[3] == 'o' &&
+ src[4] == 't' &&
+ src[5] == ';') {
+ c = '\"';
+ src += 6;
+ } else
+ return (FALSE);
+ } else
+ src++;
+ if (target) {
+ if (tarindex >= targsize)
+ return (FALSE);
+ target[tarindex] = c;
+ }
+ tarindex++;
+ }
+
+ _PROP_ASSERT(*src == '<');
+ if (sizep != NULL)
+ *sizep = tarindex;
+ if (cpp != NULL)
+ *cpp = src;
+
+ return (TRUE);
+}
+
+/*
+ * _prop_object_internalize_match --
+ * Returns true if the two character streams match.
+ */
+boolean_t
+_prop_object_internalize_match(const char *str1, size_t len1,
+ const char *str2, size_t len2)
+{
+
+ return (len1 == len2 && memcmp(str1, str2, len1) == 0);
+}
+
+#define INTERNALIZER(t, f) \
+{ t, sizeof(t) - 1, f }
+
+static const struct _prop_object_internalizer {
+ const char *poi_tag;
+ size_t poi_taglen;
+ prop_object_t (*poi_intern)(
+ struct _prop_object_internalize_context *);
+} _prop_object_internalizer_table[] = {
+ INTERNALIZER("array", _prop_array_internalize),
+
+ INTERNALIZER("true", _prop_bool_internalize),
+ INTERNALIZER("false", _prop_bool_internalize),
+
+ INTERNALIZER("data", _prop_data_internalize),
+
+ INTERNALIZER("dict", _prop_dictionary_internalize),
+
+ INTERNALIZER("integer", _prop_number_internalize),
+
+ INTERNALIZER("string", _prop_string_internalize),
+
+ { 0, 0, NULL }
+};
+
+#undef INTERNALIZER
+
+/*
+ * _prop_object_internalize_by_tag --
+ * Determine the object type from the tag in the context and
+ * internalize it.
+ */
+prop_object_t
+_prop_object_internalize_by_tag(struct _prop_object_internalize_context *ctx)
+{
+ const struct _prop_object_internalizer *poi;
+
+ for (poi = _prop_object_internalizer_table;
+ poi->poi_tag != NULL; poi++) {
+ if (_prop_object_internalize_match(ctx->poic_tagname,
+ ctx->poic_tagname_len,
+ poi->poi_tag,
+ poi->poi_taglen))
+ return ((*poi->poi_intern)(ctx));
+ }
+
+ return (NULL);
+}
+
+/*
+ * _prop_object_internalize_context_alloc --
+ * Allocate an internalize context.
+ */
+struct _prop_object_internalize_context *
+_prop_object_internalize_context_alloc(const char *xml)
+{
+ struct _prop_object_internalize_context *ctx;
+
+ ctx = _PROP_MALLOC(sizeof(struct _prop_object_internalize_context),
+ M_TEMP);
+ if (ctx == NULL)
+ return (NULL);
+
+ ctx->poic_xml = ctx->poic_cp = xml;
+
+ /*
+ * Skip any whitespace and XML preamble stuff that we don't
+ * know about / care about.
+ */
+ for (;;) {
+ while (_PROP_ISSPACE(*xml))
+ xml++;
+ if (_PROP_EOF(*xml) || *xml != '<')
+ goto bad;
+
+#define MATCH(str) (memcmp(&xml[1], str, sizeof(str) - 1) == 0)
+
+ /*
+ * Skip over the XML preamble that Apple XML property
+ * lists usually include at the top of the file.
+ */
+ if (MATCH("?xml ") ||
+ MATCH("!DOCTYPE plist")) {
+ while (*xml != '>' && !_PROP_EOF(*xml))
+ xml++;
+ if (_PROP_EOF(*xml))
+ goto bad;
+ xml++; /* advance past the '>' */
+ continue;
+ }
+
+ if (MATCH("<!--")) {
+ ctx->poic_cp = xml + 4;
+ if (_prop_object_internalize_skip_comment(ctx) == FALSE)
+ goto bad;
+ xml = ctx->poic_cp;
+ continue;
+ }
+
+#undef MATCH
+
+ /*
+ * We don't think we should skip it, so let's hope we can
+ * parse it.
+ */
+ break;
+ }
+
+ ctx->poic_cp = xml;
+ return (ctx);
+ bad:
+ _PROP_FREE(ctx, M_TEMP);
+ return (NULL);
+}
+
+/*
+ * _prop_object_internalize_context_free --
+ * Free an internalize context.
+ */
+void
+_prop_object_internalize_context_free(
+ struct _prop_object_internalize_context *ctx)
+{
+
+ _PROP_FREE(ctx, M_TEMP);
+}
+
+static boolean_t
+_prop_string_externalize(struct _prop_object_externalize_context *ctx,
+ void *v)
+{
+ prop_string_t ps = v;
+
+ if (ps->ps_size == 0)
+ return (_prop_object_externalize_empty_tag(ctx, "string"));
+
+ if (_prop_object_externalize_start_tag(ctx, "string") == FALSE ||
+ _prop_object_externalize_append_encoded_cstring(ctx,
+ ps->ps_immutable) == FALSE ||
+ _prop_object_externalize_end_tag(ctx, "string") == FALSE)
+ return (FALSE);
+
+ return (TRUE);
+}
+
+/*
+ * _prop_string_internalize --
+ * Parse a <string>...</string> and return the object created from the
+ * external representation.
+ */
+prop_object_t
+_prop_string_internalize(struct _prop_object_internalize_context *ctx)
+{
+ prop_string_t string;
+ char *str;
+ size_t len, alen;
+
+ if (ctx->poic_is_empty_element)
+ return (prop_string_create());
+
+ /* No attributes recognized here. */
+ if (ctx->poic_tagattr != NULL)
+ return (NULL);
+
+ /* Compute the length of the result. */
+ if (_prop_object_internalize_decode_string(ctx, NULL, 0, &len,
+ NULL) == FALSE)
+ return (NULL);
+
+ str = _PROP_MALLOC(len + 1, M_PROP_STRING);
+ if (str == NULL)
+ return (NULL);
+
+ if (_prop_object_internalize_decode_string(ctx, str, len, &alen,
+ &ctx->poic_cp) == FALSE ||
+ alen != len) {
+ _PROP_FREE(str, M_PROP_STRING);
+ return (NULL);
+ }
+ str[len] = '\0';
+
+ if (_prop_object_internalize_find_tag(ctx, "string",
+ _PROP_TAG_TYPE_END) == FALSE) {
+ _PROP_FREE(str, M_PROP_STRING);
+ return (NULL);
+ }
+
+ string = _prop_string_alloc();
+ if (string == NULL) {
+ _PROP_FREE(str, M_PROP_STRING);
+ return (NULL);
+ }
+
+ string->ps_mutable = str;
+ string->ps_size = len;
+
+ return (string);
+}
+
+static boolean_t
+_prop_object_externalize(struct _prop_object_externalize_context *ctx,
+ prop_object_t o)
+{
+ switch (prop_object_type(o)) {
+ case PROP_TYPE_BOOL:
+ return _prop_bool_externalize(ctx, o);
+ case PROP_TYPE_NUMBER:
+ return _prop_number_externalize(ctx, o);
+ case PROP_TYPE_STRING:
+ return _prop_string_externalize(ctx, o);
+ case PROP_TYPE_DATA:
+ return _prop_data_externalize(ctx, o);
+ case PROP_TYPE_ARRAY:
+ return _prop_array_externalize(ctx, o);
+ case PROP_TYPE_DICTIONARY:
+ return _prop_dictionary_externalize(ctx, o);
+ case PROP_TYPE_DICT_KEYSYM:
+ return _prop_dict_keysym_externalize(ctx, o);
+ default:
+ return (FALSE);
+ }
+}
Index: distrib/sets/lists/comp/mi
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/comp/mi,v
retrieving revision 1.1032
diff -d -p -u -r1.1032 mi
--- distrib/sets/lists/comp/mi 1 Jun 2007 22:54:52 -0000 1.1032
+++ distrib/sets/lists/comp/mi 7 Jun 2007 13:30:30 -0000
@@ -1619,6 +1619,7 @@
./usr/include/poll.h comp-c-include
./usr/include/prop/prop_array.h comp-c-include
./usr/include/prop/prop_bool.h comp-c-include
+./usr/include/prop/prop_codec.h comp-c-include
./usr/include/prop/prop_data.h comp-c-include
./usr/include/prop/prop_dictionary.h comp-c-include
./usr/include/prop/prop_ingest.h comp-c-include