#include "internal.h" // // transfer encoding buffer functions // static void fhp_te_parser_buf_flush(fhp_te_parser_t * const te) { te->buf_hash = fhp_lc_hash_push(te->buf_hash, te->buf, te->len); te->len = 0; } static void fhp_te_parser_buf_push( fhp_te_parser_t * const te, uint8_t byte ) { // flush buffer (if necessary) if (te->len + 1 >= FHP_TE_MAX_BUF_SIZE) fhp_te_parser_buf_flush(te); // push to buffer te->buf[te->len] = byte; te->len++; } // // transfer encoding parser functions // static const fhp_te_parser_t FHP_DEFAULT_TE_PARSER = { .state = FHP_TE_STATE_INIT, .len = 0, .num_tes = 0, .err = FHP_OK, }; fhp_err_t fhp_te_parser_init(fhp_te_parser_t * const te) { // init parser *te = FHP_DEFAULT_TE_PARSER; // return succes return FHP_OK; } static fhp_err_t fhp_te_parser_push_te( fhp_te_parser_t * const te, uint32_t hash ) { // check number of transfer encodings if (te->num_tes + 1 >= FHP_TE_MAX_TES) return FHP_ERR_TOO_MANY_TES; // add to list of transfer encodings te->tes[te->num_tes] = hash; te->num_tes++; // return success return FHP_OK; } static fhp_err_t fhp_te_parser_push_byte( fhp_te_parser_t * const te, uint8_t byte ) { fhp_err_t err; retry: switch (te->state) { case FHP_TE_STATE_INIT: // set state te->state = FHP_TE_STATE_SPACE; goto retry; break; case FHP_TE_STATE_NAME: switch (byte) { CASE_TE_CHARS // add to buffer fhp_te_parser_buf_push(te, byte); break; CASE_OWS_CHARS // flush buffer (if necessary) if (te->len > 0) fhp_te_parser_buf_flush(te); // push te if ((err = fhp_te_parser_push_te(te, te->buf_hash)) != FHP_OK) return err; // set state te->state = FHP_TE_STATE_IGNORE_UNTIL_COMMA; break; case ',': // flush buffer (if necessary) if (te->len > 0) fhp_te_parser_buf_flush(te); // push te if ((err = fhp_te_parser_push_te(te, te->buf_hash)) != FHP_OK) return err; // set state te->state = FHP_TE_STATE_SPACE; break; default: // invalid transfer encoding character return FHP_ERR_INVALID_CHAR_IN_TE_NAME; } break; case FHP_TE_STATE_IGNORE_UNTIL_COMMA: switch (byte) { case ',': // set state te->state = FHP_TE_STATE_SPACE; break; default: // do nothing (ignore) break; } break; case FHP_TE_STATE_SPACE: switch (byte) { CASE_OWS_CHARS // ignore leading spaces break; CASE_TE_CHARS // clear buffer, init hash te->len = 0; te->buf_hash = fhp_hash_init(); // set state te->state = FHP_TE_STATE_NAME; goto retry; break; default: // return error return FHP_ERR_INVALID_CHAR_IN_TE; } break; case FHP_TE_STATE_ERROR: // return last error return te->err; break; case FHP_TE_STATE_DONE: // shouldn't be reached return FHP_ERR_TE_PARSER_DONE; break; default: // never reached return FHP_ERR_BAD_TE_STATE; } // return succes return FHP_OK; } fhp_err_t fhp_te_parser_push( fhp_te_parser_t *te, uint8_t * const buf, size_t len ) { for (size_t i = 0; i < len; i++) { // debug // fprintf(stderr, "fhp_te_parser_push(): i = %lu, byte = %u\n", i, buf[i]); // push byte fhp_err_t err = fhp_te_parser_push_byte(te, buf[i]); // check error if (err != FHP_OK) { // cache error te->err = err; // set state te->state = FHP_TE_STATE_ERROR; // return error return err; } } // return succes return FHP_OK; } fhp_err_t fhp_te_parser_done( fhp_te_parser_t * const te, size_t * const ret_num_tes ) { uint8_t buf[1] = { ' ' }; // flush data, check for error fhp_err_t err = fhp_te_parser_push(te, buf, 1); if (err != FHP_OK) return err; // set state te->state = FHP_TE_STATE_DONE; // save number of tes if (ret_num_tes) *ret_num_tes = te->num_tes; // return success return FHP_OK; } fhp_err_t fhp_te_parser_get_tes( fhp_te_parser_t * const te, uint32_t * const hashes, size_t hashes_len ) { // check buffer if (!hashes) return FHP_ERR_NULL_TE_BUF; // check size if (hashes_len < te->num_tes) return FHP_ERR_SMALL_TE_BUF; // copy data memcpy(hashes, te->tes, te->num_tes * sizeof(uint32_t)); // return success return FHP_OK; }