summaryrefslogtreecommitdiff
path: root/te-parser.c
blob: 53b690fb1ad42f04489eb73232ca4bea4c5e20a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
#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;
}