gnss-sdr/src/core/libs/supl/asn-rrlp/xer_support.c

275 lines
10 KiB
C

/*
* SPDX-FileCopyrightText: (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
* SPDX-License-Identifier: BSD-1-Clause
*/
#include <asn_system.h>
#include <xer_support.h>
/* Parser states */
typedef enum
{
ST_TEXT,
ST_TAG_START,
ST_TAG_BODY,
ST_TAG_QUOTE_WAIT,
ST_TAG_QUOTED_STRING,
ST_TAG_UNQUOTED_STRING,
ST_COMMENT_WAIT_DASH1, /* "<!--"[1] */
ST_COMMENT_WAIT_DASH2, /* "<!--"[2] */
ST_COMMENT,
ST_COMMENT_CLO_DASH2, /* "-->"[0] */
ST_COMMENT_CLO_RT /* "-->"[1] */
} pstate_e;
static pxml_chunk_type_e final_chunk_type[] = {
PXML_TEXT,
PXML_TAG_END,
PXML_COMMENT_END,
PXML_TAG_END,
PXML_COMMENT_END,
};
static int _charclass[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, /* 01234567 89
*/
0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* ABCDEFG HIJKLMNO */
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, /* PQRSTUVW XYZ */
0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* abcdefg hijklmno */
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0 /* pqrstuvw xyz */
};
#define WHITESPACE(c) (_charclass[(unsigned char)(c)] == 1)
#define ALNUM(c) (_charclass[(unsigned char)(c)] >= 2)
#define ALPHA(c) (_charclass[(unsigned char)(c)] == 3)
/* Aliases for characters, ASCII/UTF-8 */
// clang-format off
#define EXCLAM 0x21 /* '!' */
#define CQUOTE 0x22 /* '"' */
#define CDASH 0x2d /* '-' */
#define CSLASH 0x2f /* '/' */
#define LANGLE 0x3c /* '<' */
#define CEQUAL 0x3d /* '=' */
#define RANGLE 0x3e /* '>' */
#define CQUEST 0x3f /* '?' */
// clang-format on
/* Invoke token callback */
#define TOKEN_CB_CALL(type, _ns, _current_too, _final) \
do \
{ \
int _ret; \
pstate_e ns = _ns; \
ssize_t _sz = (p - chunk_start) + (_current_too); \
if (!_sz) \
{ \
/* Shortcut */ \
state = _ns; \
break; \
} \
_ret = cb(type, chunk_start, _sz, key); \
if (_ret < _sz) \
{ \
if ((_current_too) && _ret == -1) state = ns; \
goto finish; \
} \
chunk_start = p + (_current_too); \
state = ns; \
} \
while (0)
#define TOKEN_CB(_type, _ns, _current_too) \
TOKEN_CB_CALL(_type, _ns, _current_too, 0)
#define TOKEN_CB_FINAL(_type, _ns, _current_too) \
TOKEN_CB_CALL(final_chunk_type[_type], _ns, _current_too, 1)
/*
* Parser itself
*/
ssize_t pxml_parse(int *stateContext, const void *xmlbuf, size_t size,
pxml_callback_f *cb, void *key)
{
pstate_e state = (pstate_e)*stateContext;
const char *chunk_start = (const char *)xmlbuf;
const char *p = chunk_start;
const char *end = p + size;
for (; p < end; p++)
{
int C = *(const unsigned char *)p;
switch (state)
{
case ST_TEXT:
/*
* Initial state: we're in the middle of some text,
* or just have started.
*/
if (C == LANGLE)
{ /* We're now in the tag, probably */
TOKEN_CB(PXML_TEXT, ST_TAG_START, 0);
}
break;
case ST_TAG_START:
if (ALPHA(C) || (C == CSLASH))
{
state = ST_TAG_BODY;
}
else if (C == EXCLAM)
{
state = ST_COMMENT_WAIT_DASH1;
}
else
{
/*
* Not characters and not whitespace.
* Must be something like "3 < 4".
*/
TOKEN_CB(PXML_TEXT, ST_TEXT, 1); /* Flush as data */
}
break;
case ST_TAG_BODY:
switch (C)
{
case RANGLE:
/* End of the tag */
TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1);
break;
case LANGLE:
/*
* The previous tag wasn't completed, but
* still recognized as valid.
* (Mozilla-compatible)
*/
TOKEN_CB_FINAL(PXML_TAG, ST_TAG_START, 0);
break;
case CEQUAL:
state = ST_TAG_QUOTE_WAIT;
break;
}
break;
case ST_TAG_QUOTE_WAIT:
/*
* State after the equal sign ("=") in the tag.
*/
switch (C)
{
case CQUOTE:
state = ST_TAG_QUOTED_STRING;
break;
case RANGLE:
/* End of the tag */
TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1);
break;
default:
if (!WHITESPACE(
C))
{ /* Unquoted string value */
state = ST_TAG_UNQUOTED_STRING;
}
}
break;
case ST_TAG_QUOTED_STRING:
/*
* Tag attribute's string value in quotes.
*/
if (C == CQUOTE)
{
/* Return back to the tag state */
state = ST_TAG_BODY;
}
break;
case ST_TAG_UNQUOTED_STRING:
if (C == RANGLE)
{
/* End of the tag */
TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1);
}
else if (WHITESPACE(C))
{
/* Return back to the tag state */
state = ST_TAG_BODY;
}
break;
case ST_COMMENT_WAIT_DASH1:
if (C == CDASH)
{
state = ST_COMMENT_WAIT_DASH2;
}
else
{
/* Some ordinary tag. */
state = ST_TAG_BODY;
}
break;
case ST_COMMENT_WAIT_DASH2:
if (C == CDASH)
{
/* Seen "<--" */
state = ST_COMMENT;
}
else
{
/* Some ordinary tag */
state = ST_TAG_BODY;
}
break;
case ST_COMMENT:
if (C == CDASH)
{
state = ST_COMMENT_CLO_DASH2;
}
break;
case ST_COMMENT_CLO_DASH2:
if (C == CDASH)
{
state = ST_COMMENT_CLO_RT;
}
else
{
/* This is not an end of a comment */
state = ST_COMMENT;
}
break;
case ST_COMMENT_CLO_RT:
if (C == RANGLE)
{
TOKEN_CB_FINAL(PXML_COMMENT, ST_TEXT, 1);
}
else if (C == CDASH)
{
/* Maintain current state, still waiting for '>'
*/
}
else
{
state = ST_COMMENT;
}
break;
} /* switch(*ptr) */
} /* for() */
/*
* Flush the partially processed chunk, state permitting.
*/
if (p - chunk_start)
{
switch (state)
{
case ST_COMMENT:
TOKEN_CB(PXML_COMMENT, state, 0);
break;
case ST_TEXT:
TOKEN_CB(PXML_TEXT, state, 0);
break;
default:
break; /* a no-op */
}
}
finish:
*stateContext = (int)state;
return chunk_start - (const char *)xmlbuf;
}