diff --git a/include/psyc/parser.h b/include/psyc/parser.h index a81ba36..ffac7d9 100644 --- a/include/psyc/parser.h +++ b/include/psyc/parser.h @@ -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? diff --git a/src/parser.c b/src/parser.c index 6785514..c90dd03 100644 --- a/src/parser.c +++ b/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