/* $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);
}