mirror of
git://git.psyc.eu/libpsyc
synced 2024-08-15 03:19:02 +00:00
fixes for parsing partial packets
This commit is contained in:
parent
f8d95ce640
commit
ac60e2b4f0
2 changed files with 89 additions and 36 deletions
|
@ -30,11 +30,13 @@ typedef enum
|
|||
*/
|
||||
typedef enum
|
||||
{
|
||||
PSYC_PARSE_ERROR_END = -7,
|
||||
PSYC_PARSE_ERROR_METHOD = -6,
|
||||
PSYC_PARSE_ERROR_VAR_LEN = -5,
|
||||
PSYC_PARSE_ERROR_VAR_TAB = -4,
|
||||
PSYC_PARSE_ERROR_VAR_NAME = -3,
|
||||
PSYC_PARSE_ERROR_END = -9,
|
||||
PSYC_PARSE_ERROR_BODY = -8,
|
||||
PSYC_PARSE_ERROR_METHOD = -7,
|
||||
PSYC_PARSE_ERROR_MOD_NL = -6,
|
||||
PSYC_PARSE_ERROR_MOD_LEN = -5,
|
||||
PSYC_PARSE_ERROR_MOD_TAB = -4,
|
||||
PSYC_PARSE_ERROR_MOD_NAME = -3,
|
||||
PSYC_PARSE_ERROR_LENGTH = -2,
|
||||
PSYC_PARSE_ERROR = -1,
|
||||
PSYC_PARSE_SUCCESS = 0,
|
||||
|
@ -42,13 +44,13 @@ typedef enum
|
|||
/// Fill another buffer and concatenate it with the end of the current buffer,
|
||||
/// from the cursor position to the end.
|
||||
PSYC_PARSE_INSUFFICIENT = 1,
|
||||
/// Routing variable parsing done.
|
||||
/// Routing modifier parsing done.
|
||||
/// Operator, name & value contains the respective parts.
|
||||
PSYC_PARSE_ROUTING = 2,
|
||||
/// Entity variable parsing done.
|
||||
/// Entity modifier parsing done.
|
||||
/// Operator, name & value contains the respective parts.
|
||||
PSYC_PARSE_ENTITY = 3,
|
||||
/// Entity variable parsing is incomplete.
|
||||
/// Entity modifier parsing is incomplete.
|
||||
/// Operator & name are complete, value is incomplete.
|
||||
PSYC_PARSE_ENTITY_INCOMPLETE = 4,
|
||||
/// Body parsing done, name contains method, value contains body.
|
||||
|
@ -91,6 +93,7 @@ typedef struct
|
|||
uint8_t flags; ///< flags for the parser, see psycParseFlag
|
||||
psycPart part; ///< part of the packet being parsed currently
|
||||
|
||||
size_t routingLength; ///< length of routing part parsed so far
|
||||
size_t contentParsed; ///< number of bytes parsed from the content so far
|
||||
size_t contentLength; ///< expected length of the content
|
||||
psycBool contentLengthFound; ///< is there a length given for this packet?
|
||||
|
|
106
src/parser.c
106
src/parser.c
|
@ -133,13 +133,15 @@ inline psycParseRC psyc_parseBinaryValue(psycParseState* state, psycString* valu
|
|||
if (state->cursor + remaining > state->buffer.length) // is the length larger than this buffer?
|
||||
{
|
||||
value->length = state->buffer.length - state->cursor;
|
||||
state->cursor += value->length;
|
||||
*parsed += value->length;
|
||||
return PSYC_PARSE_INCOMPLETE;
|
||||
}
|
||||
|
||||
value->length += remaining;
|
||||
value->length = remaining;
|
||||
state->cursor += remaining;
|
||||
*parsed += value->length;
|
||||
*parsed += remaining;
|
||||
assert(*parsed == *length);
|
||||
|
||||
return PSYC_PARSE_COMPLETE;
|
||||
}
|
||||
|
@ -153,9 +155,13 @@ inline psycParseRC psyc_parseModifier(psycParseState* state, char* oper, psycStr
|
|||
*oper = *(state->buffer.ptr + state->cursor);
|
||||
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
||||
|
||||
if (psyc_parseName(state, name) != PSYC_PARSE_SUCCESS)
|
||||
return PSYC_PARSE_ERROR_VAR_NAME;
|
||||
psycParseRC ret = psyc_parseName(state, name);
|
||||
if (ret == PSYC_PARSE_ERROR)
|
||||
return PSYC_PARSE_ERROR_MOD_NAME;
|
||||
else if (ret != PSYC_PARSE_SUCCESS)
|
||||
return ret;
|
||||
|
||||
size_t length = 0;
|
||||
value->length = 0;
|
||||
state->valueLength = 0;
|
||||
state->valueParsed = 0;
|
||||
|
@ -170,25 +176,25 @@ inline psycParseRC psyc_parseModifier(psycParseState* state, char* oper, psycStr
|
|||
{
|
||||
do
|
||||
{
|
||||
state->valueLength = 10 * state->valueLength + state->buffer.ptr[state->cursor] - '0';
|
||||
length = 10 * length + state->buffer.ptr[state->cursor] - '0';
|
||||
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
||||
}
|
||||
while (isNumeric(state->buffer.ptr[state->cursor]));
|
||||
state->valueLength = length;
|
||||
}
|
||||
else
|
||||
return PSYC_PARSE_ERROR_VAR_LEN;
|
||||
return PSYC_PARSE_ERROR_MOD_LEN;
|
||||
|
||||
// After the length a TAB follows.
|
||||
if (state->buffer.ptr[state->cursor] != '\t')
|
||||
return PSYC_PARSE_ERROR_VAR_TAB;
|
||||
return PSYC_PARSE_ERROR_MOD_TAB;
|
||||
|
||||
if (state->buffer.length <= ++(state->cursor)) // Incremented cursor inside length?
|
||||
return PSYC_PARSE_ENTITY_INCOMPLETE;
|
||||
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INCOMPLETE);
|
||||
|
||||
if (psyc_parseBinaryValue(state, value, &(state->valueLength), &(state->valueParsed)) == PSYC_PARSE_INCOMPLETE)
|
||||
return PSYC_PARSE_ENTITY_INCOMPLETE;
|
||||
ret = psyc_parseBinaryValue(state, value, &(state->valueLength), &(state->valueParsed));
|
||||
if (ret == PSYC_PARSE_INCOMPLETE)
|
||||
return ret;
|
||||
|
||||
state->cursor++;
|
||||
return PSYC_PARSE_SUCCESS;
|
||||
}
|
||||
else if (state->buffer.ptr[state->cursor] == '\t') // simple arg
|
||||
|
@ -201,11 +207,11 @@ inline psycParseRC psyc_parseModifier(psycParseState* state, char* oper, psycStr
|
|||
value->length++;
|
||||
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
||||
}
|
||||
state->cursor++;
|
||||
|
||||
return PSYC_PARSE_SUCCESS;
|
||||
}
|
||||
else
|
||||
return PSYC_PARSE_ERROR_VAR_TAB;
|
||||
return PSYC_PARSE_ERROR_MOD_TAB;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -214,7 +220,7 @@ inline psycParseRC psyc_parseModifier(psycParseState* state, char* oper, psycStr
|
|||
*/
|
||||
psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psycString* value)
|
||||
{
|
||||
int ret; // a return value
|
||||
psycParseRC ret; // a return value
|
||||
size_t pos; // a cursor position
|
||||
|
||||
// Start position of the current line in the buffer
|
||||
|
@ -230,6 +236,7 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
|
|||
case PSYC_PART_RESET: // New packet starts here, reset state.
|
||||
state->valueParsed = 0;
|
||||
state->valueLength = 0;
|
||||
state->routingLength = 0;
|
||||
state->contentParsed = 0;
|
||||
state->contentLength = 0;
|
||||
state->contentLengthFound = 0;
|
||||
|
@ -237,12 +244,21 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
|
|||
// fall thru
|
||||
|
||||
case PSYC_PART_ROUTING:
|
||||
pos = state->cursor;
|
||||
if (state->routingLength > 0)
|
||||
{
|
||||
if (state->buffer.ptr[state->cursor] != '\n')
|
||||
return PSYC_PARSE_ERROR_MOD_NL;
|
||||
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
||||
}
|
||||
|
||||
// Each line of the header starts with a glyph,
|
||||
// i.e. :_name, -_name +_name etc,
|
||||
// so just test if the first char is a glyph.
|
||||
if (isGlyph(state->buffer.ptr[state->cursor])) // is the first char a glyph?
|
||||
{ // it is a glyph, so a variable starts here
|
||||
ret = psyc_parseModifier(state, oper, name, value);
|
||||
state->routingLength += state->cursor - pos;
|
||||
return ret == PSYC_PARSE_SUCCESS ? PSYC_PARSE_ROUTING : ret;
|
||||
}
|
||||
else // not a glyph
|
||||
|
@ -293,7 +309,20 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
|
|||
if (state->valueParsed < state->valueLength) {
|
||||
ret = psyc_parseBinaryValue(state, value, &(state->valueLength), &(state->valueParsed));
|
||||
state->contentParsed += value->length;
|
||||
return ret == PSYC_PARSE_COMPLETE ? PSYC_PARSE_ENTITY : PSYC_PARSE_ENTITY_INCOMPLETE;
|
||||
|
||||
if (ret == PSYC_PARSE_INCOMPLETE)
|
||||
return PSYC_PARSE_ENTITY_INCOMPLETE;
|
||||
|
||||
return PSYC_PARSE_ENTITY;
|
||||
}
|
||||
|
||||
pos = state->cursor;
|
||||
|
||||
if (state->contentParsed > 0)
|
||||
{
|
||||
if (state->buffer.ptr[state->cursor] != '\n')
|
||||
return PSYC_PARSE_ERROR_MOD_NL;
|
||||
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
||||
}
|
||||
|
||||
// Each line of the header starts with a glyph,
|
||||
|
@ -303,31 +332,45 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
|
|||
// method does not start with a glyph.
|
||||
if (isGlyph(state->buffer.ptr[state->cursor]))
|
||||
{
|
||||
pos = state->cursor;
|
||||
ret = psyc_parseModifier(state, oper, name, value);
|
||||
state->contentParsed += state->cursor - pos;
|
||||
return ret == PSYC_PARSE_SUCCESS ? PSYC_PARSE_ENTITY : ret;
|
||||
|
||||
if (ret == PSYC_PARSE_INCOMPLETE)
|
||||
return PSYC_PARSE_ENTITY_INCOMPLETE;
|
||||
else if (ret == PSYC_PARSE_SUCCESS)
|
||||
return PSYC_PARSE_ENTITY;
|
||||
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->part = PSYC_PART_METHOD;
|
||||
state->contentParsed += state->cursor - pos;
|
||||
state->startc = state->cursor;
|
||||
state->part = PSYC_PART_METHOD;
|
||||
// fall thru
|
||||
}
|
||||
|
||||
case PSYC_PART_METHOD:
|
||||
pos = state->cursor;
|
||||
if (psyc_parseName(state, name) == PSYC_PARSE_SUCCESS)
|
||||
ret = psyc_parseName(state, name);
|
||||
|
||||
if (ret == PSYC_PARSE_INSUFFICIENT)
|
||||
return ret;
|
||||
else if (ret == PSYC_PARSE_SUCCESS)
|
||||
{ // the method ends with a \n then the data follows
|
||||
if (state->buffer.ptr[state->cursor] != '\n')
|
||||
return PSYC_PARSE_ERROR_METHOD;
|
||||
|
||||
state->cursor++;
|
||||
state->startc = state->cursor;
|
||||
if (state->contentLengthFound)
|
||||
{ // if length was found set start position to the beginning of data
|
||||
state->cursor++;
|
||||
state->startc = state->cursor;
|
||||
state->part = PSYC_PART_DATA;
|
||||
}
|
||||
else // otherwise keep it at the beginning of method
|
||||
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
||||
|
||||
state->contentParsed += state->cursor - pos;
|
||||
state->part = PSYC_PART_DATA;
|
||||
if (state->cursor >= state->buffer.length)
|
||||
return PSYC_PARSE_INSUFFICIENT;
|
||||
// fall thru
|
||||
}
|
||||
else // No method, which means the packet should end now.
|
||||
|
@ -343,9 +386,16 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
|
|||
|
||||
if (state->contentLengthFound) // We know the length of the packet.
|
||||
{
|
||||
if (psyc_parseBinaryValue(state, value, &(state->contentLength), &(state->contentParsed)) == PSYC_PARSE_INCOMPLETE)
|
||||
if (state->contentParsed < state->contentLength &&
|
||||
psyc_parseBinaryValue(state, value, &(state->contentLength), &(state->contentParsed)) == PSYC_PARSE_INCOMPLETE)
|
||||
return PSYC_PARSE_BODY_INCOMPLETE;
|
||||
|
||||
if (state->cursor >= state->buffer.length)
|
||||
return PSYC_PARSE_BODY;
|
||||
|
||||
if (state->buffer.ptr[state->cursor] != '\n')
|
||||
return PSYC_PARSE_ERROR_BODY;
|
||||
|
||||
state->cursor++;
|
||||
state->part = PSYC_PART_END;
|
||||
return PSYC_PARSE_BODY;
|
||||
|
@ -385,7 +435,7 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
|
|||
return PSYC_PARSE_INSUFFICIENT;
|
||||
|
||||
if (state->buffer.ptr[state->cursor] == '|' &&
|
||||
state->buffer.ptr[state->cursor+1] == '\n') // packet ends here
|
||||
state->buffer.ptr[state->cursor+1] == '\n') // packet ends here
|
||||
{
|
||||
state->cursor += 2;
|
||||
state->part = PSYC_PART_RESET;
|
||||
|
@ -414,7 +464,7 @@ psycParseListRC psyc_parseList(psycParseListState* state, psycString *name, psyc
|
|||
if (!state->type) // If type is not set we're at the start
|
||||
{
|
||||
if (name->length < 5 || memcmp(name->ptr, "_list", 5) != 0 ||
|
||||
(name->length > 5 && name->ptr[5] != '_')) // name should be _list or should start with _list_
|
||||
(name->length > 5 && name->ptr[5] != '_')) // name should be _list or should start with _list_
|
||||
return PSYC_PARSE_LIST_ERROR_NAME;
|
||||
|
||||
// First character is either | for text lists, or a number for binary lists
|
||||
|
|
Loading…
Reference in a new issue