Coverage Report

Created: 2025-08-24 06:26

/src/mhd2/src/mhd2/mhd_str.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
  This file is part of libmicrohttpd
3
  Copyright (C) 2015-2024 Evgeny Grin (Karlson2k)
4
5
  GNU libmicrohttpd is free software; you can redistribute it and/or
6
  modify it under the terms of the GNU Lesser General Public
7
  License as published by the Free Software Foundation; either
8
  version 2.1 of the License, or (at your option) any later version.
9
10
  GNU libmicrohttpd is distributed in the hope that it will be useful,
11
  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
  Lesser General Public License for more details.
14
15
  You should have received a copy of the GNU Lesser General Public
16
  License along with this library; if not, write to the Free Software
17
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18
*/
19
20
/**
21
 * @file microhttpd/mhd_str.c
22
 * @brief  Functions implementations for string manipulating
23
 * @author Karlson2k (Evgeny Grin)
24
 */
25
26
#include "mhd_sys_options.h"
27
28
#include "mhd_str.h"
29
30
#include <string.h>
31
32
#include "mhd_assert.h"
33
#include "mhd_limits.h"
34
35
#ifdef MHD_FAVOR_SMALL_CODE
36
#  ifdef MHD_static_inline_
37
#    undef MHD_static_inline_
38
#  endif /* MHD_static_inline_ */
39
/* Do not force inlining and do not use macro functions, use normal static
40
   functions instead.
41
   This may give more flexibility for size optimizations. */
42
#  define MHD_static_inline_ static
43
#  ifndef HAVE_INLINE_FUNCS
44
#    define HAVE_INLINE_FUNCS 1
45
#  endif /* !HAVE_INLINE_FUNCS */
46
#endif /* MHD_FAVOR_SMALL_CODE */
47
48
/*
49
 * Block of functions/macros that use US-ASCII charset as required by HTTP
50
 * standards. Not affected by current locale settings.
51
 */
52
53
#ifdef HAVE_INLINE_FUNCS
54
55
#if 0 /* Disable unused functions. */
56
/**
57
 * Check whether character is lower case letter in US-ASCII
58
 *
59
 * @param c character to check
60
 * @return non-zero if character is lower case letter, zero otherwise
61
 */
62
MHD_static_inline_ MHD_FN_CONST_ bool
63
isasciilower (char c)
64
{
65
  return (c >= 'a') && (c <= 'z');
66
}
67
68
69
#endif /* Disable unused functions. */
70
71
72
/**
73
 * Check whether character is upper case letter in US-ASCII
74
 *
75
 * @param c character to check
76
 * @return non-zero if character is upper case letter, zero otherwise
77
 */
78
MHD_static_inline_ MHD_FN_CONST_ bool
79
isasciiupper (char c)
80
2.15k
{
81
2.15k
  return (c <= 'Z') && (c >= 'A');
82
2.15k
}
83
84
85
#if 0 /* Disable unused functions. */
86
/**
87
 * Check whether character is letter in US-ASCII
88
 *
89
 * @param c character to check
90
 * @return non-zero if character is letter in US-ASCII, zero otherwise
91
 */
92
MHD_static_inline_ MHD_FN_CONST_ bool
93
isasciialpha (char c)
94
{
95
  return isasciilower (c) || isasciiupper (c);
96
}
97
98
99
#endif /* Disable unused functions. */
100
101
102
/**
103
 * Check whether character is decimal digit in US-ASCII
104
 *
105
 * @param c character to check
106
 * @return non-zero if character is decimal digit, zero otherwise
107
 */
108
MHD_static_inline_ MHD_FN_CONST_ bool
109
isasciidigit (char c)
110
17.5k
{
111
17.5k
  return (c <= '9') && (c >= '0');
112
17.5k
}
113
114
115
#if 0 /* Disable unused functions. */
116
/**
117
 * Check whether character is hexadecimal digit in US-ASCII
118
 *
119
 * @param c character to check
120
 * @return non-zero if character is decimal digit, zero otherwise
121
 */
122
MHD_static_inline_ MHD_FN_CONST_ bool
123
isasciixdigit (char c)
124
{
125
  return isasciidigit (c) ||
126
         ( (c <= 'F') && (c >= 'A') ) ||
127
         ( (c <= 'f') && (c >= 'a') );
128
}
129
130
131
/**
132
 * Check whether character is decimal digit or letter in US-ASCII
133
 *
134
 * @param c character to check
135
 * @return non-zero if character is decimal digit or letter, zero otherwise
136
 */
137
MHD_static_inline_ MHD_FN_CONST_ bool
138
isasciialnum (char c)
139
{
140
  return isasciialpha (c) || isasciidigit (c);
141
}
142
143
144
#endif /* Disable unused functions. */
145
146
147
#if 0 /* Disable unused functions. */
148
/**
149
 * Convert US-ASCII character to lower case.
150
 * If character is upper case letter in US-ASCII than it's converted to lower
151
 * case analog. If character is NOT upper case letter than it's returned
152
 * unmodified.
153
 *
154
 * @param c character to convert
155
 * @return converted to lower case character
156
 */
157
MHD_static_inline_ MHD_FN_CONST_ char
158
toasciilower (char c)
159
{
160
  return isasciiupper (c) ? (char) (0x20u | (unsigned char) c) : c;
161
}
162
163
164
/**
165
 * Convert US-ASCII character to upper case.
166
 * If character is lower case letter in US-ASCII than it's converted to upper
167
 * case analog. If character is NOT lower case letter than it's returned
168
 * unmodified.
169
 *
170
 * @param c character to convert
171
 * @return converted to upper case character
172
 */
173
MHD_static_inline_ MHD_FN_CONST_ char
174
toasciiupper (char c)
175
{
176
  return isasciilower (c) ? (char) ((~0x20u) & (unsigned char) c) : c;
177
}
178
179
180
#endif /* Disable unused functions. */
181
182
183
#if defined(MHD_FAVOR_SMALL_CODE) /* Used only in mhd_str_to_uvalue_n() */
184
/**
185
 * Convert US-ASCII decimal digit to its value.
186
 *
187
 * @param c character to convert
188
 * @return value of decimal digit or -1 if @ c is not decimal digit
189
 */
190
MHD_static_inline_ MHD_FN_CONST_ int
191
todigitvalue (char c)
192
{
193
  if (isasciidigit (c))
194
    return (unsigned char) (c - '0');
195
196
  return -1;
197
}
198
199
200
#endif /* MHD_FAVOR_SMALL_CODE */
201
202
203
/**
204
 * Convert US-ASCII hexadecimal digit to its value.
205
 *
206
 * @param c character to convert
207
 * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit
208
 */
209
MHD_static_inline_ MHD_FN_CONST_ int
210
xdigittovalue (char c)
211
52.5k
{
212
52.5k
  const unsigned char uc = (unsigned char) c; /* Force unsigned value */
213
52.5k
#if ! defined(MHD_FAVOR_SMALL_CODE)
214
52.5k
  static const signed char map_xdigit_to_value[256] = {
215
52.5k
    -1 /* 0x00 (NUL) */,
216
52.5k
    -1 /* 0x01 (SOH) */,
217
52.5k
    -1 /* 0x02 (STX) */,
218
52.5k
    -1 /* 0x03 (ETX) */,
219
52.5k
    -1 /* 0x04 (EOT) */,
220
52.5k
    -1 /* 0x05 (ENQ) */,
221
52.5k
    -1 /* 0x06 (ACK) */,
222
52.5k
    -1 /* 0x07 (BEL) */,
223
52.5k
    -1 /* 0x08 (BS)  */,
224
52.5k
    -1 /* 0x09 (HT)  */,
225
52.5k
    -1 /* 0x0A (LF)  */,
226
52.5k
    -1 /* 0x0B (VT)  */,
227
52.5k
    -1 /* 0x0C (FF)  */,
228
52.5k
    -1 /* 0x0D (CR)  */,
229
52.5k
    -1 /* 0x0E (SO)  */,
230
52.5k
    -1 /* 0x0F (SI)  */,
231
52.5k
    -1 /* 0x10 (DLE) */,
232
52.5k
    -1 /* 0x11 (DC1) */,
233
52.5k
    -1 /* 0x12 (DC2) */,
234
52.5k
    -1 /* 0x13 (DC3) */,
235
52.5k
    -1 /* 0x14 (DC4) */,
236
52.5k
    -1 /* 0x15 (NAK) */,
237
52.5k
    -1 /* 0x16 (SYN) */,
238
52.5k
    -1 /* 0x17 (ETB) */,
239
52.5k
    -1 /* 0x18 (CAN) */,
240
52.5k
    -1 /* 0x19 (EM)  */,
241
52.5k
    -1 /* 0x1A (SUB) */,
242
52.5k
    -1 /* 0x1B (ESC) */,
243
52.5k
    -1 /* 0x1C (FS)  */,
244
52.5k
    -1 /* 0x1D (GS)  */,
245
52.5k
    -1 /* 0x1E (RS)  */,
246
52.5k
    -1 /* 0x1F (US)  */,
247
52.5k
    -1 /* 0x20 (' ') */,
248
52.5k
    -1 /* 0x21 ('!') */,
249
52.5k
    -1 /* 0x22 ('"') */,
250
52.5k
    -1 /* 0x23 ('#') */,
251
52.5k
    -1 /* 0x24 ('$') */,
252
52.5k
    -1 /* 0x25 ('%') */,
253
52.5k
    -1 /* 0x26 ('&') */,
254
52.5k
    -1 /* 0x27 ('\'') */,
255
52.5k
    -1 /* 0x28 ('(') */,
256
52.5k
    -1 /* 0x29 (')') */,
257
52.5k
    -1 /* 0x2A ('*') */,
258
52.5k
    -1 /* 0x2B ('+') */,
259
52.5k
    -1 /* 0x2C (',') */,
260
52.5k
    -1 /* 0x2D ('-') */,
261
52.5k
    -1 /* 0x2E ('.') */,
262
52.5k
    -1 /* 0x2F ('/') */,
263
52.5k
    0 /*  0x30 ('0') */,
264
52.5k
    1 /*  0x31 ('1') */,
265
52.5k
    2 /*  0x32 ('2') */,
266
52.5k
    3 /*  0x33 ('3') */,
267
52.5k
    4 /*  0x34 ('4') */,
268
52.5k
    5 /*  0x35 ('5') */,
269
52.5k
    6 /*  0x36 ('6') */,
270
52.5k
    7 /*  0x37 ('7') */,
271
52.5k
    8 /*  0x38 ('8') */,
272
52.5k
    9 /*  0x39 ('9') */,
273
52.5k
    -1 /* 0x3A (':') */,
274
52.5k
    -1 /* 0x3B (';') */,
275
52.5k
    -1 /* 0x3C ('<') */,
276
52.5k
    -1 /* 0x3D ('=') */,
277
52.5k
    -1 /* 0x3E ('>') */,
278
52.5k
    -1 /* 0x3F ('?') */,
279
52.5k
    -1 /* 0x40 ('@') */,
280
52.5k
    10 /* 0x41 ('A') */,
281
52.5k
    11 /* 0x42 ('B') */,
282
52.5k
    12 /* 0x43 ('C') */,
283
52.5k
    13 /* 0x44 ('D') */,
284
52.5k
    14 /* 0x45 ('E') */,
285
52.5k
    15 /* 0x46 ('F') */,
286
52.5k
    -1 /* 0x47 ('G') */,
287
52.5k
    -1 /* 0x48 ('H') */,
288
52.5k
    -1 /* 0x49 ('I') */,
289
52.5k
    -1 /* 0x4A ('J') */,
290
52.5k
    -1 /* 0x4B ('K') */,
291
52.5k
    -1 /* 0x4C ('L') */,
292
52.5k
    -1 /* 0x4D ('M') */,
293
52.5k
    -1 /* 0x4E ('N') */,
294
52.5k
    -1 /* 0x4F ('O') */,
295
52.5k
    -1 /* 0x50 ('P') */,
296
52.5k
    -1 /* 0x51 ('Q') */,
297
52.5k
    -1 /* 0x52 ('R') */,
298
52.5k
    -1 /* 0x53 ('S') */,
299
52.5k
    -1 /* 0x54 ('T') */,
300
52.5k
    -1 /* 0x55 ('U') */,
301
52.5k
    -1 /* 0x56 ('V') */,
302
52.5k
    -1 /* 0x57 ('W') */,
303
52.5k
    -1 /* 0x58 ('X') */,
304
52.5k
    -1 /* 0x59 ('Y') */,
305
52.5k
    -1 /* 0x5A ('Z') */,
306
52.5k
    -1 /* 0x5B ('[') */,
307
52.5k
    -1 /* 0x5C ('\') */,
308
52.5k
    -1 /* 0x5D (']') */,
309
52.5k
    -1 /* 0x5E ('^') */,
310
52.5k
    -1 /* 0x5F ('_') */,
311
52.5k
    -1 /* 0x60 ('`') */,
312
52.5k
    10 /* 0x61 ('a') */,
313
52.5k
    11 /* 0x62 ('b') */,
314
52.5k
    12 /* 0x63 ('c') */,
315
52.5k
    13 /* 0x64 ('d') */,
316
52.5k
    14 /* 0x65 ('e') */,
317
52.5k
    15 /* 0x66 ('f') */,
318
52.5k
    -1 /* 0x67 ('g') */,
319
52.5k
    -1 /* 0x68 ('h') */,
320
52.5k
    -1 /* 0x69 ('i') */,
321
52.5k
    -1 /* 0x6A ('j') */,
322
52.5k
    -1 /* 0x6B ('k') */,
323
52.5k
    -1 /* 0x6C ('l') */,
324
52.5k
    -1 /* 0x6D ('m') */,
325
52.5k
    -1 /* 0x6E ('n') */,
326
52.5k
    -1 /* 0x6F ('o') */,
327
52.5k
    -1 /* 0x70 ('p') */,
328
52.5k
    -1 /* 0x71 ('q') */,
329
52.5k
    -1 /* 0x72 ('r') */,
330
52.5k
    -1 /* 0x73 ('s') */,
331
52.5k
    -1 /* 0x74 ('t') */,
332
52.5k
    -1 /* 0x75 ('u') */,
333
52.5k
    -1 /* 0x76 ('v') */,
334
52.5k
    -1 /* 0x77 ('w') */,
335
52.5k
    -1 /* 0x78 ('x') */,
336
52.5k
    -1 /* 0x79 ('y') */,
337
52.5k
    -1 /* 0x7A ('z') */,
338
52.5k
    -1 /* 0x7B ('{') */,
339
52.5k
    -1 /* 0x7C ('|') */,
340
52.5k
    -1 /* 0x7D ('}') */,
341
52.5k
    -1 /* 0x7E ('~') */,
342
52.5k
    -1 /* 0x7F (DEL) */,
343
52.5k
    -1 /* 0x80 (EXT) */,
344
52.5k
    -1 /* 0x81 (EXT) */,
345
52.5k
    -1 /* 0x82 (EXT) */,
346
52.5k
    -1 /* 0x83 (EXT) */,
347
52.5k
    -1 /* 0x84 (EXT) */,
348
52.5k
    -1 /* 0x85 (EXT) */,
349
52.5k
    -1 /* 0x86 (EXT) */,
350
52.5k
    -1 /* 0x87 (EXT) */,
351
52.5k
    -1 /* 0x88 (EXT) */,
352
52.5k
    -1 /* 0x89 (EXT) */,
353
52.5k
    -1 /* 0x8A (EXT) */,
354
52.5k
    -1 /* 0x8B (EXT) */,
355
52.5k
    -1 /* 0x8C (EXT) */,
356
52.5k
    -1 /* 0x8D (EXT) */,
357
52.5k
    -1 /* 0x8E (EXT) */,
358
52.5k
    -1 /* 0x8F (EXT) */,
359
52.5k
    -1 /* 0x90 (EXT) */,
360
52.5k
    -1 /* 0x91 (EXT) */,
361
52.5k
    -1 /* 0x92 (EXT) */,
362
52.5k
    -1 /* 0x93 (EXT) */,
363
52.5k
    -1 /* 0x94 (EXT) */,
364
52.5k
    -1 /* 0x95 (EXT) */,
365
52.5k
    -1 /* 0x96 (EXT) */,
366
52.5k
    -1 /* 0x97 (EXT) */,
367
52.5k
    -1 /* 0x98 (EXT) */,
368
52.5k
    -1 /* 0x99 (EXT) */,
369
52.5k
    -1 /* 0x9A (EXT) */,
370
52.5k
    -1 /* 0x9B (EXT) */,
371
52.5k
    -1 /* 0x9C (EXT) */,
372
52.5k
    -1 /* 0x9D (EXT) */,
373
52.5k
    -1 /* 0x9E (EXT) */,
374
52.5k
    -1 /* 0x9F (EXT) */,
375
52.5k
    -1 /* 0xA0 (EXT) */,
376
52.5k
    -1 /* 0xA1 (EXT) */,
377
52.5k
    -1 /* 0xA2 (EXT) */,
378
52.5k
    -1 /* 0xA3 (EXT) */,
379
52.5k
    -1 /* 0xA4 (EXT) */,
380
52.5k
    -1 /* 0xA5 (EXT) */,
381
52.5k
    -1 /* 0xA6 (EXT) */,
382
52.5k
    -1 /* 0xA7 (EXT) */,
383
52.5k
    -1 /* 0xA8 (EXT) */,
384
52.5k
    -1 /* 0xA9 (EXT) */,
385
52.5k
    -1 /* 0xAA (EXT) */,
386
52.5k
    -1 /* 0xAB (EXT) */,
387
52.5k
    -1 /* 0xAC (EXT) */,
388
52.5k
    -1 /* 0xAD (EXT) */,
389
52.5k
    -1 /* 0xAE (EXT) */,
390
52.5k
    -1 /* 0xAF (EXT) */,
391
52.5k
    -1 /* 0xB0 (EXT) */,
392
52.5k
    -1 /* 0xB1 (EXT) */,
393
52.5k
    -1 /* 0xB2 (EXT) */,
394
52.5k
    -1 /* 0xB3 (EXT) */,
395
52.5k
    -1 /* 0xB4 (EXT) */,
396
52.5k
    -1 /* 0xB5 (EXT) */,
397
52.5k
    -1 /* 0xB6 (EXT) */,
398
52.5k
    -1 /* 0xB7 (EXT) */,
399
52.5k
    -1 /* 0xB8 (EXT) */,
400
52.5k
    -1 /* 0xB9 (EXT) */,
401
52.5k
    -1 /* 0xBA (EXT) */,
402
52.5k
    -1 /* 0xBB (EXT) */,
403
52.5k
    -1 /* 0xBC (EXT) */,
404
52.5k
    -1 /* 0xBD (EXT) */,
405
52.5k
    -1 /* 0xBE (EXT) */,
406
52.5k
    -1 /* 0xBF (EXT) */,
407
52.5k
    -1 /* 0xC0 (EXT) */,
408
52.5k
    -1 /* 0xC1 (EXT) */,
409
52.5k
    -1 /* 0xC2 (EXT) */,
410
52.5k
    -1 /* 0xC3 (EXT) */,
411
52.5k
    -1 /* 0xC4 (EXT) */,
412
52.5k
    -1 /* 0xC5 (EXT) */,
413
52.5k
    -1 /* 0xC6 (EXT) */,
414
52.5k
    -1 /* 0xC7 (EXT) */,
415
52.5k
    -1 /* 0xC8 (EXT) */,
416
52.5k
    -1 /* 0xC9 (EXT) */,
417
52.5k
    -1 /* 0xCA (EXT) */,
418
52.5k
    -1 /* 0xCB (EXT) */,
419
52.5k
    -1 /* 0xCC (EXT) */,
420
52.5k
    -1 /* 0xCD (EXT) */,
421
52.5k
    -1 /* 0xCE (EXT) */,
422
52.5k
    -1 /* 0xCF (EXT) */,
423
52.5k
    -1 /* 0xD0 (EXT) */,
424
52.5k
    -1 /* 0xD1 (EXT) */,
425
52.5k
    -1 /* 0xD2 (EXT) */,
426
52.5k
    -1 /* 0xD3 (EXT) */,
427
52.5k
    -1 /* 0xD4 (EXT) */,
428
52.5k
    -1 /* 0xD5 (EXT) */,
429
52.5k
    -1 /* 0xD6 (EXT) */,
430
52.5k
    -1 /* 0xD7 (EXT) */,
431
52.5k
    -1 /* 0xD8 (EXT) */,
432
52.5k
    -1 /* 0xD9 (EXT) */,
433
52.5k
    -1 /* 0xDA (EXT) */,
434
52.5k
    -1 /* 0xDB (EXT) */,
435
52.5k
    -1 /* 0xDC (EXT) */,
436
52.5k
    -1 /* 0xDD (EXT) */,
437
52.5k
    -1 /* 0xDE (EXT) */,
438
52.5k
    -1 /* 0xDF (EXT) */,
439
52.5k
    -1 /* 0xE0 (EXT) */,
440
52.5k
    -1 /* 0xE1 (EXT) */,
441
52.5k
    -1 /* 0xE2 (EXT) */,
442
52.5k
    -1 /* 0xE3 (EXT) */,
443
52.5k
    -1 /* 0xE4 (EXT) */,
444
52.5k
    -1 /* 0xE5 (EXT) */,
445
52.5k
    -1 /* 0xE6 (EXT) */,
446
52.5k
    -1 /* 0xE7 (EXT) */,
447
52.5k
    -1 /* 0xE8 (EXT) */,
448
52.5k
    -1 /* 0xE9 (EXT) */,
449
52.5k
    -1 /* 0xEA (EXT) */,
450
52.5k
    -1 /* 0xEB (EXT) */,
451
52.5k
    -1 /* 0xEC (EXT) */,
452
52.5k
    -1 /* 0xED (EXT) */,
453
52.5k
    -1 /* 0xEE (EXT) */,
454
52.5k
    -1 /* 0xEF (EXT) */,
455
52.5k
    -1 /* 0xF0 (EXT) */,
456
52.5k
    -1 /* 0xF1 (EXT) */,
457
52.5k
    -1 /* 0xF2 (EXT) */,
458
52.5k
    -1 /* 0xF3 (EXT) */,
459
52.5k
    -1 /* 0xF4 (EXT) */,
460
52.5k
    -1 /* 0xF5 (EXT) */,
461
52.5k
    -1 /* 0xF6 (EXT) */,
462
52.5k
    -1 /* 0xF7 (EXT) */,
463
52.5k
    -1 /* 0xF8 (EXT) */,
464
52.5k
    -1 /* 0xF9 (EXT) */,
465
52.5k
    -1 /* 0xFA (EXT) */,
466
52.5k
    -1 /* 0xFB (EXT) */,
467
52.5k
    -1 /* 0xFC (EXT) */,
468
52.5k
    -1 /* 0xFD (EXT) */,
469
52.5k
    -1 /* 0xFE (EXT) */,
470
52.5k
    -1   /* 0xFF (EXT) */
471
52.5k
  };
472
52.5k
  return map_xdigit_to_value[uc];
473
#else  /* MHD_FAVOR_SMALL_CODE */
474
  unsigned int try_val;
475
476
  try_val = uc - (unsigned char) '0';
477
  if (9 >= try_val)
478
    return (int) (unsigned int) try_val;
479
  try_val = (uc | 0x20u /* fold case */) - (unsigned char) 'a';
480
  if (5 >= try_val)
481
    return (int) (unsigned int) (try_val + 10u);
482
483
  return -1;
484
#endif /* MHD_FAVOR_SMALL_CODE */
485
52.5k
}
486
487
488
/**
489
 * Convert 4 bit value to US-ASCII hexadecimal digit.
490
 *
491
 * @param v the value to convert, must be less then 16
492
 * @return hexadecimal digit
493
 */
494
MHD_static_inline_ MHD_FN_CONST_ char
495
valuetoxdigit (unsigned int v)
496
0
{
497
0
#if ! defined(MHD_FAVOR_SMALL_CODE)
498
0
  static const char map_value_to_xdigit[16] =
499
0
  { '0', '1', '2', '3', '4', '5', '6', '7',
500
0
    '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
501
502
0
  mhd_assert (16 > v);
503
504
0
  return map_value_to_xdigit[v];
505
#else  /* MHD_FAVOR_SMALL_CODE */
506
507
  mhd_assert (16 > v);
508
509
  if (v <= 9)
510
    return '0' + (char) (v);
511
  return 'a' + (char) (v - 10);
512
#endif /* MHD_FAVOR_SMALL_CODE */
513
0
}
514
515
516
#if ! defined(MHD_FAVOR_SMALL_CODE)
517
/**
518
 * Convert 8 bit value to two US-ASCII hexadecimal digits.
519
 *
520
 * @param v the value to convert
521
 * @return pointer to char[2] with two hexadecimal digits
522
 */
523
MHD_static_inline_ MHD_FN_CONST_ MHD_FN_RETURNS_NONNULL_ const char*
524
uint8totwoxdigits (uint8_t v)
525
36.8k
{
526
36.8k
  static const char map_uint8_to_two_xdigits[][2] =
527
36.8k
  { { '0', '0' },
528
36.8k
    { '0', '1' },
529
36.8k
    { '0', '2' },
530
36.8k
    { '0', '3' },
531
36.8k
    { '0', '4' },
532
36.8k
    { '0', '5' },
533
36.8k
    { '0', '6' },
534
36.8k
    { '0', '7' },
535
36.8k
    { '0', '8' },
536
36.8k
    { '0', '9' },
537
36.8k
    { '0', 'a' },
538
36.8k
    { '0', 'b' },
539
36.8k
    { '0', 'c' },
540
36.8k
    { '0', 'd' },
541
36.8k
    { '0', 'e' },
542
36.8k
    { '0', 'f' },
543
36.8k
    { '1', '0' },
544
36.8k
    { '1', '1' },
545
36.8k
    { '1', '2' },
546
36.8k
    { '1', '3' },
547
36.8k
    { '1', '4' },
548
36.8k
    { '1', '5' },
549
36.8k
    { '1', '6' },
550
36.8k
    { '1', '7' },
551
36.8k
    { '1', '8' },
552
36.8k
    { '1', '9' },
553
36.8k
    { '1', 'a' },
554
36.8k
    { '1', 'b' },
555
36.8k
    { '1', 'c' },
556
36.8k
    { '1', 'd' },
557
36.8k
    { '1', 'e' },
558
36.8k
    { '1', 'f' },
559
36.8k
    { '2', '0' },
560
36.8k
    { '2', '1' },
561
36.8k
    { '2', '2' },
562
36.8k
    { '2', '3' },
563
36.8k
    { '2', '4' },
564
36.8k
    { '2', '5' },
565
36.8k
    { '2', '6' },
566
36.8k
    { '2', '7' },
567
36.8k
    { '2', '8' },
568
36.8k
    { '2', '9' },
569
36.8k
    { '2', 'a' },
570
36.8k
    { '2', 'b' },
571
36.8k
    { '2', 'c' },
572
36.8k
    { '2', 'd' },
573
36.8k
    { '2', 'e' },
574
36.8k
    { '2', 'f' },
575
36.8k
    { '3', '0' },
576
36.8k
    { '3', '1' },
577
36.8k
    { '3', '2' },
578
36.8k
    { '3', '3' },
579
36.8k
    { '3', '4' },
580
36.8k
    { '3', '5' },
581
36.8k
    { '3', '6' },
582
36.8k
    { '3', '7' },
583
36.8k
    { '3', '8' },
584
36.8k
    { '3', '9' },
585
36.8k
    { '3', 'a' },
586
36.8k
    { '3', 'b' },
587
36.8k
    { '3', 'c' },
588
36.8k
    { '3', 'd' },
589
36.8k
    { '3', 'e' },
590
36.8k
    { '3', 'f' },
591
36.8k
    { '4', '0' },
592
36.8k
    { '4', '1' },
593
36.8k
    { '4', '2' },
594
36.8k
    { '4', '3' },
595
36.8k
    { '4', '4' },
596
36.8k
    { '4', '5' },
597
36.8k
    { '4', '6' },
598
36.8k
    { '4', '7' },
599
36.8k
    { '4', '8' },
600
36.8k
    { '4', '9' },
601
36.8k
    { '4', 'a' },
602
36.8k
    { '4', 'b' },
603
36.8k
    { '4', 'c' },
604
36.8k
    { '4', 'd' },
605
36.8k
    { '4', 'e' },
606
36.8k
    { '4', 'f' },
607
36.8k
    { '5', '0' },
608
36.8k
    { '5', '1' },
609
36.8k
    { '5', '2' },
610
36.8k
    { '5', '3' },
611
36.8k
    { '5', '4' },
612
36.8k
    { '5', '5' },
613
36.8k
    { '5', '6' },
614
36.8k
    { '5', '7' },
615
36.8k
    { '5', '8' },
616
36.8k
    { '5', '9' },
617
36.8k
    { '5', 'a' },
618
36.8k
    { '5', 'b' },
619
36.8k
    { '5', 'c' },
620
36.8k
    { '5', 'd' },
621
36.8k
    { '5', 'e' },
622
36.8k
    { '5', 'f' },
623
36.8k
    { '6', '0' },
624
36.8k
    { '6', '1' },
625
36.8k
    { '6', '2' },
626
36.8k
    { '6', '3' },
627
36.8k
    { '6', '4' },
628
36.8k
    { '6', '5' },
629
36.8k
    { '6', '6' },
630
36.8k
    { '6', '7' },
631
36.8k
    { '6', '8' },
632
36.8k
    { '6', '9' },
633
36.8k
    { '6', 'a' },
634
36.8k
    { '6', 'b' },
635
36.8k
    { '6', 'c' },
636
36.8k
    { '6', 'd' },
637
36.8k
    { '6', 'e' },
638
36.8k
    { '6', 'f' },
639
36.8k
    { '7', '0' },
640
36.8k
    { '7', '1' },
641
36.8k
    { '7', '2' },
642
36.8k
    { '7', '3' },
643
36.8k
    { '7', '4' },
644
36.8k
    { '7', '5' },
645
36.8k
    { '7', '6' },
646
36.8k
    { '7', '7' },
647
36.8k
    { '7', '8' },
648
36.8k
    { '7', '9' },
649
36.8k
    { '7', 'a' },
650
36.8k
    { '7', 'b' },
651
36.8k
    { '7', 'c' },
652
36.8k
    { '7', 'd' },
653
36.8k
    { '7', 'e' },
654
36.8k
    { '7', 'f' },
655
36.8k
    { '8', '0' },
656
36.8k
    { '8', '1' },
657
36.8k
    { '8', '2' },
658
36.8k
    { '8', '3' },
659
36.8k
    { '8', '4' },
660
36.8k
    { '8', '5' },
661
36.8k
    { '8', '6' },
662
36.8k
    { '8', '7' },
663
36.8k
    { '8', '8' },
664
36.8k
    { '8', '9' },
665
36.8k
    { '8', 'a' },
666
36.8k
    { '8', 'b' },
667
36.8k
    { '8', 'c' },
668
36.8k
    { '8', 'd' },
669
36.8k
    { '8', 'e' },
670
36.8k
    { '8', 'f' },
671
36.8k
    { '9', '0' },
672
36.8k
    { '9', '1' },
673
36.8k
    { '9', '2' },
674
36.8k
    { '9', '3' },
675
36.8k
    { '9', '4' },
676
36.8k
    { '9', '5' },
677
36.8k
    { '9', '6' },
678
36.8k
    { '9', '7' },
679
36.8k
    { '9', '8' },
680
36.8k
    { '9', '9' },
681
36.8k
    { '9', 'a' },
682
36.8k
    { '9', 'b' },
683
36.8k
    { '9', 'c' },
684
36.8k
    { '9', 'd' },
685
36.8k
    { '9', 'e' },
686
36.8k
    { '9', 'f' },
687
36.8k
    { 'a', '0' },
688
36.8k
    { 'a', '1' },
689
36.8k
    { 'a', '2' },
690
36.8k
    { 'a', '3' },
691
36.8k
    { 'a', '4' },
692
36.8k
    { 'a', '5' },
693
36.8k
    { 'a', '6' },
694
36.8k
    { 'a', '7' },
695
36.8k
    { 'a', '8' },
696
36.8k
    { 'a', '9' },
697
36.8k
    { 'a', 'a' },
698
36.8k
    { 'a', 'b' },
699
36.8k
    { 'a', 'c' },
700
36.8k
    { 'a', 'd' },
701
36.8k
    { 'a', 'e' },
702
36.8k
    { 'a', 'f' },
703
36.8k
    { 'b', '0' },
704
36.8k
    { 'b', '1' },
705
36.8k
    { 'b', '2' },
706
36.8k
    { 'b', '3' },
707
36.8k
    { 'b', '4' },
708
36.8k
    { 'b', '5' },
709
36.8k
    { 'b', '6' },
710
36.8k
    { 'b', '7' },
711
36.8k
    { 'b', '8' },
712
36.8k
    { 'b', '9' },
713
36.8k
    { 'b', 'a' },
714
36.8k
    { 'b', 'b' },
715
36.8k
    { 'b', 'c' },
716
36.8k
    { 'b', 'd' },
717
36.8k
    { 'b', 'e' },
718
36.8k
    { 'b', 'f' },
719
36.8k
    { 'c', '0' },
720
36.8k
    { 'c', '1' },
721
36.8k
    { 'c', '2' },
722
36.8k
    { 'c', '3' },
723
36.8k
    { 'c', '4' },
724
36.8k
    { 'c', '5' },
725
36.8k
    { 'c', '6' },
726
36.8k
    { 'c', '7' },
727
36.8k
    { 'c', '8' },
728
36.8k
    { 'c', '9' },
729
36.8k
    { 'c', 'a' },
730
36.8k
    { 'c', 'b' },
731
36.8k
    { 'c', 'c' },
732
36.8k
    { 'c', 'd' },
733
36.8k
    { 'c', 'e' },
734
36.8k
    { 'c', 'f' },
735
36.8k
    { 'd', '0' },
736
36.8k
    { 'd', '1' },
737
36.8k
    { 'd', '2' },
738
36.8k
    { 'd', '3' },
739
36.8k
    { 'd', '4' },
740
36.8k
    { 'd', '5' },
741
36.8k
    { 'd', '6' },
742
36.8k
    { 'd', '7' },
743
36.8k
    { 'd', '8' },
744
36.8k
    { 'd', '9' },
745
36.8k
    { 'd', 'a' },
746
36.8k
    { 'd', 'b' },
747
36.8k
    { 'd', 'c' },
748
36.8k
    { 'd', 'd' },
749
36.8k
    { 'd', 'e' },
750
36.8k
    { 'd', 'f' },
751
36.8k
    { 'e', '0' },
752
36.8k
    { 'e', '1' },
753
36.8k
    { 'e', '2' },
754
36.8k
    { 'e', '3' },
755
36.8k
    { 'e', '4' },
756
36.8k
    { 'e', '5' },
757
36.8k
    { 'e', '6' },
758
36.8k
    { 'e', '7' },
759
36.8k
    { 'e', '8' },
760
36.8k
    { 'e', '9' },
761
36.8k
    { 'e', 'a' },
762
36.8k
    { 'e', 'b' },
763
36.8k
    { 'e', 'c' },
764
36.8k
    { 'e', 'd' },
765
36.8k
    { 'e', 'e' },
766
36.8k
    { 'e', 'f' },
767
36.8k
    { 'f', '0' },
768
36.8k
    { 'f', '1' },
769
36.8k
    { 'f', '2' },
770
36.8k
    { 'f', '3' },
771
36.8k
    { 'f', '4' },
772
36.8k
    { 'f', '5' },
773
36.8k
    { 'f', '6' },
774
36.8k
    { 'f', '7' },
775
36.8k
    { 'f', '8' },
776
36.8k
    { 'f', '9' },
777
36.8k
    { 'f', 'a' },
778
36.8k
    { 'f', 'b' },
779
36.8k
    { 'f', 'c' },
780
36.8k
    { 'f', 'd' },
781
36.8k
    { 'f', 'e' },
782
36.8k
    { 'f', 'f' }
783
#ifndef NDEBUG
784
    ,
785
    { 0, 0 }
786
#endif /* ! NDEBUG */
787
36.8k
  };
788
789
36.8k
  mhd_assert (257u == \
790
36.8k
              (sizeof(map_uint8_to_two_xdigits) \
791
36.8k
               / sizeof(map_uint8_to_two_xdigits[0])));
792
793
36.8k
  return map_uint8_to_two_xdigits[v];
794
  /**
795
   * Indicates that function uint8totwoxdigits() is available
796
   */
797
36.8k
#define mhd_HAVE_UINT8TOTWOXDIGITS 1
798
36.8k
}
799
800
801
#endif /* ! MHD_FAVOR_SMALL_CODE */
802
803
804
/**
805
 * Caseless compare two characters.
806
 *
807
 * @param c1 the first char to compare
808
 * @param c2 the second char to compare
809
 * @return boolean 'true' if chars are caseless equal, false otherwise
810
 */
811
MHD_static_inline_ MHD_FN_CONST_ bool
812
charsequalcaseless (char c1, char c2)
813
18.8k
{
814
18.8k
  if (c1 == c2)
815
15.0k
    return true;
816
  /* Fold case on both sides */
817
3.77k
  c1 = ((char) (~0x20u & (unsigned char) c1));
818
3.77k
  c2 = ((char) (~0x20u & (unsigned char) c2));
819
3.77k
  return (c1 == c2) && isasciiupper (c1);
820
18.8k
}
821
822
823
#else  /* !HAVE_INLINE_FUNCS */
824
825
826
/**
827
 * Checks whether character is lower case letter in US-ASCII
828
 *
829
 * @param c character to check
830
 * @return boolean true if character is lower case letter,
831
 *         boolean false otherwise
832
 */
833
#  define isasciilower(c) ((((char) (c)) >= 'a') && (((char) (c)) <= 'z'))
834
835
836
/**
837
 * Checks whether character is upper case letter in US-ASCII
838
 *
839
 * @param c character to check
840
 * @return boolean true if character is upper case letter,
841
 *         boolean false otherwise
842
 */
843
#  define isasciiupper(c) ((((char) (c)) <= 'Z') && (((char) (c)) >= 'A'))
844
845
846
/**
847
 * Checks whether character is letter in US-ASCII
848
 *
849
 * @param c character to check
850
 * @return boolean true if character is letter, boolean false
851
 *         otherwise
852
 */
853
#  define isasciialpha(c) (isasciilower (c) || isasciiupper (c))
854
855
856
/**
857
 * Check whether character is decimal digit in US-ASCII
858
 *
859
 * @param c character to check
860
 * @return boolean true if character is decimal digit, boolean false
861
 *         otherwise
862
 */
863
#  define isasciidigit(c) ((((char) (c)) <= '9') && (((char) (c)) >= '0'))
864
865
866
/**
867
 * Check whether character is hexadecimal digit in US-ASCII
868
 *
869
 * @param c character to check
870
 * @return boolean true if character is hexadecimal digit,
871
 *         boolean false otherwise
872
 */
873
#  define isasciixdigit(c) (isasciidigit ((c)) || \
874
                            (((char) (c)) <= 'F' && ((char) (c)) >= 'A') || \
875
                            (((char) (c)) <= 'f' && ((char) (c)) >= 'a'))
876
877
878
/**
879
 * Check whether character is decimal digit or letter in US-ASCII
880
 *
881
 * @param c character to check
882
 * @return boolean true if character is decimal digit or letter,
883
 *         boolean false otherwise
884
 */
885
#  define isasciialnum(c) (isasciialpha (c) || isasciidigit (c))
886
887
888
/**
889
 * Convert US-ASCII character to lower case.
890
 * If character is upper case letter in US-ASCII than it's converted to lower
891
 * case analog. If character is NOT upper case letter than it's returned
892
 * unmodified.
893
 *
894
 * @param c character to convert
895
 * @return converted to lower case character
896
 */
897
#  define toasciilower(c) ((isasciiupper (c)) ? (((char) (c)) - 'A' + 'a') : \
898
                           ((char) (c)))
899
900
901
/**
902
 * Convert US-ASCII character to upper case.
903
 * If character is lower case letter in US-ASCII than it's converted to upper
904
 * case analog. If character is NOT lower case letter than it's returned
905
 * unmodified.
906
 *
907
 * @param c character to convert
908
 * @return converted to upper case character
909
 */
910
#  define toasciiupper(c) ((isasciilower (c)) ? (((char) (c)) - 'a' + 'A') : \
911
                           ((char) (c)))
912
913
914
/**
915
 * Convert US-ASCII decimal digit to its value.
916
 *
917
 * @param c character to convert
918
 * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit
919
 */
920
#  define todigitvalue(c) (isasciidigit (c) ? (int) (((char) (c)) - '0') : \
921
                           (int) (-1))
922
923
924
/**
925
 * Convert US-ASCII hexadecimal digit to its value.
926
 * @param c character to convert
927
 * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit
928
 */
929
#  define xdigittovalue(c) (isasciidigit (c) ? (int) (((char) (c)) - '0') : \
930
                            ( (((char) (c)) >= 'A' && ((char) (c)) <= 'F') ? \
931
                              (int) (((unsigned char) (c)) - 'A' + 10) : \
932
                              ( (((char) (c)) >= 'a' && ((char) (c)) <= 'f') ? \
933
                                (int) (((unsigned char) (c)) - 'a' + 10) : \
934
                                (int) (-1) )))
935
936
937
#if ! defined(MHD_FAVOR_SMALL_CODE)
938
static const char map_value_to_xdigit[16] =
939
{ '0', '1', '2', '3', '4', '5', '6', '7',
940
  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
941
942
/**
943
 * Convert 4 bit value to US-ASCII hexadecimal digit.
944
 *
945
 * @param v the value to convert, must be less then 16
946
 * @return hexadecimal digit
947
 */
948
#    define valuetoxdigit(v) map_value_to_xdigit[v]
949
#else  /* MHD_FAVOR_SMALL_CODE */
950
/**
951
 * Convert 4 bit value to US-ASCII hexadecimal digit.
952
 *
953
 * @param v the value to convert, must be less then 16
954
 * @return hexadecimal digit
955
 */
956
 #    define valuetoxdigit(v) \
957
         (char) ((v <= 9) ? ('0' + (char) v) : ('a' + (char) v - 10))
958
#endif /* MHD_FAVOR_SMALL_CODE */
959
960
/**
961
 * Caseless compare two characters.
962
 *
963
 * @param c1 the first char to compare
964
 * @param c2 the second char to compare
965
 * @return boolean 'true' if chars are caseless equal, false otherwise
966
 */
967
#define charsequalcaseless(c1, c2) \
968
        ( ((c1) == (c2)) || \
969
          (((0x20u | (unsigned char) c1) == (0x20u | (unsigned char) c2)) && \
970
           toasciilower (((char) (0x20u | (unsigned char) c2)))) )
971
972
#endif /* !HAVE_INLINE_FUNCS */
973
974
975
#ifndef MHD_FAVOR_SMALL_CODE
976
MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_
977
MHD_FN_PAR_CSTR_ (1) MHD_FN_PAR_CSTR_ (2) bool
978
mhd_str_equal_caseless (const char *str1,
979
                        const char *str2)
980
0
{
981
0
  while (0 != (*str1))
982
0
  {
983
0
    const char c1 = *str1;
984
0
    const char c2 = *str2;
985
0
    if (charsequalcaseless (c1, c2))
986
0
    {
987
0
      str1++;
988
0
      str2++;
989
0
    }
990
0
    else
991
0
      return false;
992
0
  }
993
0
  return 0 == (*str2);
994
0
}
995
996
997
#endif /* ! MHD_FAVOR_SMALL_CODE */
998
999
1000
MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_
1001
MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2) bool
1002
mhd_str_equal_caseless_n (const char *const str1,
1003
                          const char *const str2,
1004
                          size_t maxlen)
1005
0
{
1006
0
  size_t i;
1007
1008
0
  for (i = 0; i < maxlen; ++i)
1009
0
  {
1010
0
    const char c1 = str1[i];
1011
0
    const char c2 = str2[i];
1012
0
    if (0 == c2)
1013
0
      return 0 == c1;
1014
0
    if (charsequalcaseless (c1, c2))
1015
0
      continue;
1016
0
    else
1017
0
      return false;
1018
0
  }
1019
0
  return true;
1020
0
}
1021
1022
1023
MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_
1024
MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2) bool
1025
mhd_str_equal_caseless_bin_n (const char *const str1,
1026
                              const char *const str2,
1027
                              size_t len)
1028
1.16k
{
1029
1.16k
  size_t i;
1030
1031
8.02k
  for (i = 0; i < len; ++i)
1032
7.02k
  {
1033
7.02k
    const char c1 = str1[i];
1034
7.02k
    const char c2 = str2[i];
1035
7.02k
    if (charsequalcaseless (c1, c2))
1036
6.85k
      continue;
1037
176
    else
1038
176
      return 0;
1039
7.02k
  }
1040
993
  return ! 0;
1041
1.16k
}
1042
1043
1044
MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_
1045
MHD_FN_PAR_CSTR_ (1)
1046
MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2) bool
1047
mhd_str_has_token_caseless (const char *restrict str,
1048
                            const char *const restrict token,
1049
                            size_t token_len)
1050
0
{
1051
0
  if (0 == token_len)
1052
0
    return false;
1053
1054
0
  while (0 != *str)
1055
0
  {
1056
0
    size_t i;
1057
    /* Skip all whitespaces and empty tokens. */
1058
0
    while (' ' == *str || '\t' == *str || ',' == *str)
1059
0
      str++;
1060
1061
    /* Check for token match. */
1062
0
    i = 0;
1063
0
    while (1)
1064
0
    {
1065
0
      const char sc = *(str++);
1066
0
      const char tc = token[i++];
1067
1068
0
      if (0 == sc)
1069
0
        return false;
1070
0
      if (! charsequalcaseless (sc, tc))
1071
0
        break;
1072
0
      if (i >= token_len)
1073
0
      {
1074
        /* Check whether substring match token fully or
1075
         * has additional unmatched chars at tail. */
1076
0
        while (' ' == *str || '\t' == *str)
1077
0
          str++;
1078
        /* End of (sub)string? */
1079
0
        if ((0 == *str) || (',' == *str) )
1080
0
          return true;
1081
        /* Unmatched chars at end of substring. */
1082
0
        break;
1083
0
      }
1084
0
    }
1085
    /* Find next substring. */
1086
0
    while (0 != *str && ',' != *str)
1087
0
      str++;
1088
0
  }
1089
0
  return false;
1090
0
}
1091
1092
1093
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
1094
MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_IN_SIZE_ (3,4)
1095
MHD_FN_PAR_OUT_ (5) MHD_FN_PAR_INOUT_ (6) bool
1096
mhd_str_remove_token_caseless (const char *restrict str,
1097
                               size_t str_len,
1098
                               const char *const restrict token,
1099
                               const size_t token_len,
1100
                               char *restrict buf,
1101
                               ssize_t *restrict buf_size)
1102
1.25k
{
1103
1.25k
  const char *s1; /**< the "input" string / character */
1104
1.25k
  char *s2;       /**< the "output" string / character */
1105
1.25k
  size_t t_pos;   /**< position of matched character in the token */
1106
1.25k
  bool token_removed;
1107
1108
1.25k
  mhd_assert (NULL == memchr (token, 0, token_len));
1109
1.25k
  mhd_assert (NULL == memchr (token, ' ', token_len));
1110
1.25k
  mhd_assert (NULL == memchr (token, '\t', token_len));
1111
1.25k
  mhd_assert (NULL == memchr (token, ',', token_len));
1112
1.25k
  mhd_assert (0 <= *buf_size);
1113
1114
1.25k
  if (SSIZE_MAX <= ((str_len / 2) * 3 + 3))
1115
0
  {
1116
    /* The return value may overflow, refuse */
1117
0
    *buf_size = (ssize_t) -1;
1118
0
    return false;
1119
0
  }
1120
1.25k
  s1 = str;
1121
1.25k
  s2 = buf;
1122
1.25k
  token_removed = false;
1123
1124
4.97k
  while ((size_t) (s1 - str) < str_len)
1125
4.39k
  {
1126
4.39k
    const char *cur_token; /**< the first char of current token */
1127
4.39k
    size_t copy_size;
1128
1129
    /* Skip any initial whitespaces and empty tokens */
1130
16.2k
    while ( ((size_t) (s1 - str) < str_len) &&
1131
16.2k
            ((' ' == *s1) || ('\t' == *s1) || (',' == *s1)) )
1132
11.8k
      s1++;
1133
1134
    /* 's1' points to the first char of token in the input string or
1135
     * points just beyond the end of the input string */
1136
1137
4.39k
    if ((size_t) (s1 - str) >= str_len)
1138
83
      break; /* Nothing to copy, end of the input string */
1139
1140
    /* 's1' points to the first char of token in the input string */
1141
1142
4.31k
    cur_token = s1; /* the first char of input token */
1143
1144
    /* Check the token with case-insensetive match */
1145
4.31k
    t_pos = 0;
1146
12.1k
    while ( ((size_t) (s1 - str) < str_len) && (token_len > t_pos) &&
1147
12.1k
            (charsequalcaseless (*s1, token[t_pos])) )
1148
7.87k
    {
1149
7.87k
      s1++;
1150
7.87k
      t_pos++;
1151
7.87k
    }
1152
    /* s1 may point just beyond the end of the input string */
1153
4.31k
    if ( (token_len == t_pos) && (0 != token_len) )
1154
1.02k
    {
1155
      /* 'token' matched, check that current input token does not have
1156
       * any suffixes */
1157
2.45k
      while ( ((size_t) (s1 - str) < str_len) &&
1158
2.45k
              ((' ' == *s1) || ('\t' == *s1)) )
1159
1.43k
        s1++;
1160
      /* 's1' points to the first non-whitespace char after the token matched
1161
       * requested token or points just beyond the end of the input string after
1162
       * the requested token */
1163
1.02k
      if (((size_t) (s1 - str) == str_len) || (',' == *s1))
1164
794
      {/* full token match, do not copy current token to the output */
1165
794
        token_removed = true;
1166
794
        continue;
1167
794
      }
1168
1.02k
    }
1169
1170
    /* 's1' points to first non-whitespace char, to some char after
1171
     * first non-whitespace char in the token in the input string, to
1172
     * the ',', or just beyond the end of the input string */
1173
    /* The current token in the input string does not match the token
1174
     * to exclude, it must be copied to the output string */
1175
    /* the current token size excluding leading whitespaces and current char */
1176
3.52k
    copy_size = (size_t) (s1 - cur_token);
1177
3.52k
    if (buf == s2)
1178
977
    { /* The first token to copy to the output */
1179
977
      if ((size_t) *buf_size < copy_size)
1180
31
      { /* Not enough space in the output buffer */
1181
31
        *buf_size = (ssize_t) -1;
1182
31
        return false;
1183
31
      }
1184
977
    }
1185
2.54k
    else
1186
2.54k
    { /* Some token was already copied to the output buffer */
1187
2.54k
      mhd_assert (s2 > buf);
1188
2.54k
      if ((size_t) *buf_size < ((size_t) (s2 - buf)) + copy_size + 2)
1189
22
      { /* Not enough space in the output buffer */
1190
22
        *buf_size = (ssize_t) -1;
1191
22
        return false;
1192
22
      }
1193
2.52k
      *(s2++) = ',';
1194
2.52k
      *(s2++) = ' ';
1195
2.52k
    }
1196
    /* Copy non-matched token to the output */
1197
3.46k
    if (0 != copy_size)
1198
518
    {
1199
518
      memcpy (s2, cur_token, copy_size);
1200
518
      s2 += copy_size;
1201
518
    }
1202
1203
6.45k
    while ( ((size_t) (s1 - str) < str_len) && (',' != *s1))
1204
3.52k
    {
1205
      /* 's1' points to first non-whitespace char, to some char after
1206
       * first non-whitespace char in the token in the input string */
1207
      /* Copy all non-whitespace chars from the current token in
1208
       * the input string */
1209
18.8k
      while ( ((size_t) (s1 - str) < str_len) &&
1210
18.8k
              (',' != *s1) && (' ' != *s1) && ('\t' != *s1) )
1211
15.7k
      {
1212
15.7k
        mhd_assert (s2 >= buf);
1213
15.7k
        if ((size_t) *buf_size <= (size_t) (s2 - buf)) /* '<= s2' equals '< s2 + 1' */
1214
490
        { /* Not enough space in the output buffer */
1215
490
          *buf_size = (ssize_t) -1;
1216
490
          return false;
1217
490
        }
1218
15.2k
        *(s2++) = *(s1++);
1219
15.2k
      }
1220
      /* 's1' points to some whitespace char in the token in the input
1221
       * string, to the ',', or just beyond the end of the input string */
1222
      /* Skip all whitespaces */
1223
5.77k
      while ( ((size_t) (s1 - str) < str_len) &&
1224
5.77k
              ((' ' == *s1) || ('\t' == *s1)) )
1225
2.74k
        s1++;
1226
1227
      /* 's1' points to the first non-whitespace char in the input string
1228
       * after whitespace chars, to the ',', or just beyond the end of
1229
       * the input string */
1230
3.03k
      if (((size_t) (s1 - str) < str_len) && (',' != *s1))
1231
389
      { /* Not the end of the current token */
1232
389
        mhd_assert (s2 >= buf);
1233
389
        if ((size_t) *buf_size <= (size_t) (s2 - buf)) /* '<= s2' equals '< s2 + 1' */
1234
50
        { /* Not enough space in the output buffer */
1235
50
          *buf_size = (ssize_t) -1;
1236
50
          return false;
1237
50
        }
1238
339
        *(s2++) = ' ';
1239
339
      }
1240
3.03k
    }
1241
3.46k
  }
1242
660
  mhd_assert (((ssize_t) (s2 - buf)) <= *buf_size);
1243
660
  *buf_size = (ssize_t) (s2 - buf);
1244
660
  return token_removed;
1245
1.25k
}
1246
1247
1248
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
1249
MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_INOUT_ (2)
1250
MHD_FN_PAR_IN_SIZE_ (3,4) bool
1251
mhd_str_remove_tokens_caseless (char *restrict str,
1252
                                size_t *restrict str_len,
1253
                                const char *const restrict tkns,
1254
                                const size_t tkns_len)
1255
0
{
1256
0
  size_t pt;                      /**< position in @a tokens */
1257
0
  bool token_removed;
1258
1259
0
  mhd_assert (NULL == memchr (tkns, 0, tkns_len));
1260
1261
0
  token_removed = false;
1262
0
  pt = 0;
1263
1264
0
  while (pt < tkns_len && *str_len != 0)
1265
0
  {
1266
0
    const char *tkn; /**< the current token */
1267
0
    size_t tkn_len;
1268
1269
    /* Skip any initial whitespaces and empty tokens in 'tokens' */
1270
0
    while ( (pt < tkns_len) &&
1271
0
            ((' ' == tkns[pt]) || ('\t' == tkns[pt]) || (',' == tkns[pt])) )
1272
0
      pt++;
1273
1274
0
    if (pt >= tkns_len)
1275
0
      break; /* No more tokens, nothing to remove */
1276
1277
    /* Found non-whitespace char which is not a comma */
1278
0
    tkn = tkns + pt;
1279
0
    do
1280
0
    {
1281
0
      do
1282
0
      {
1283
0
        pt++;
1284
0
      } while (pt < tkns_len &&
1285
0
               (' ' != tkns[pt] && '\t' != tkns[pt] && ',' != tkns[pt]));
1286
      /* Found end of the token string, space, tab, or comma */
1287
0
      tkn_len = pt - (size_t) (tkn - tkns);
1288
1289
      /* Skip all spaces and tabs */
1290
0
      while (pt < tkns_len && (' ' == tkns[pt] || '\t' == tkns[pt]))
1291
0
        pt++;
1292
      /* Found end of the token string or non-whitespace char */
1293
0
    } while (pt < tkns_len && ',' != tkns[pt]);
1294
1295
    /* 'tkn' is the input token with 'tkn_len' chars */
1296
0
    mhd_assert (0 != tkn_len);
1297
1298
0
    if (*str_len == tkn_len)
1299
0
    {
1300
0
      if (mhd_str_equal_caseless_bin_n (str, tkn, tkn_len))
1301
0
      {
1302
0
        *str_len = 0;
1303
0
        token_removed = true;
1304
0
      }
1305
0
      continue;
1306
0
    }
1307
    /* 'tkn' cannot match part of 'str' if length of 'tkn' is larger
1308
     * than length of 'str'.
1309
     * It's know that 'tkn' is not equal to the 'str' (was checked previously).
1310
     * As 'str' is normalized when 'tkn' is not equal to the 'str'
1311
     * it is required that 'str' to be at least 3 chars larger then 'tkn'
1312
     * (the comma, the space and at least one additional character for the next
1313
     * token) to remove 'tkn' from the 'str'. */
1314
0
    if (*str_len > tkn_len + 2)
1315
0
    { /* Remove 'tkn' from the input string */
1316
0
      size_t pr;    /**< the 'read' position in the @a str */
1317
0
      size_t pw;    /**< the 'write' position in the @a str */
1318
1319
0
      pr = 0;
1320
0
      pw = 0;
1321
1322
0
      do
1323
0
      {
1324
0
        mhd_assert (pr >= pw);
1325
0
        mhd_assert ((*str_len) >= (pr + tkn_len));
1326
0
        if ( ( ((*str_len) == (pr + tkn_len)) || (',' == str[pr + tkn_len]) ) &&
1327
0
             mhd_str_equal_caseless_bin_n (str + pr, tkn, tkn_len) )
1328
0
        {
1329
          /* current token in the input string matches the 'tkn', skip it */
1330
0
          mhd_assert ((*str_len == pr + tkn_len) || \
1331
0
                      (' ' == str[pr + tkn_len + 1])); /* 'str' must be normalized */
1332
0
          token_removed = true;
1333
          /* Advance to the next token in the input string or beyond
1334
           * the end of the input string. */
1335
0
          pr += tkn_len + 2;
1336
0
        }
1337
0
        else
1338
0
        {
1339
          /* current token in the input string does not match the 'tkn',
1340
           * copy to the output */
1341
0
          if (0 != pw)
1342
0
          { /* not the first output token, add ", " to separate */
1343
0
            if (pr != pw + 2)
1344
0
            {
1345
0
              str[pw++] = ',';
1346
0
              str[pw++] = ' ';
1347
0
            }
1348
0
            else
1349
0
              pw += 2; /* 'str' is not yet modified in this round */
1350
0
          }
1351
0
          do
1352
0
          {
1353
0
            if (pr != pw)
1354
0
              str[pw] = str[pr];
1355
0
            pr++;
1356
0
            pw++;
1357
0
          } while (pr < *str_len && ',' != str[pr]);
1358
          /* Advance to the next token in the input string or beyond
1359
           * the end of the input string. */
1360
0
          pr += 2;
1361
0
        }
1362
        /* 'pr' should point to the next token in the input string or beyond
1363
         * the end of the input string */
1364
0
        if ((*str_len) < (pr + tkn_len))
1365
0
        { /* The rest of the 'str + pr' is too small to match 'tkn' */
1366
0
          if ((*str_len) > pr)
1367
0
          { /* Copy the rest of the string */
1368
0
            size_t copy_size;
1369
0
            copy_size = *str_len - pr;
1370
0
            if (0 != pw)
1371
0
            { /* not the first output token, add ", " to separate */
1372
0
              if (pr != pw + 2)
1373
0
              {
1374
0
                str[pw++] = ',';
1375
0
                str[pw++] = ' ';
1376
0
              }
1377
0
              else
1378
0
                pw += 2; /* 'str' is not yet modified in this round */
1379
0
            }
1380
0
            if (pr != pw)
1381
0
              memmove (str + pw, str + pr, copy_size);
1382
0
            pw += copy_size;
1383
0
          }
1384
0
          *str_len = pw;
1385
0
          break;
1386
0
        }
1387
0
        mhd_assert ((' ' != str[0]) && ('\t' != str[0]));
1388
0
        mhd_assert ((0 == pr) || (3 <= pr));
1389
0
        mhd_assert ((0 == pr) || (' ' == str[pr - 1]));
1390
0
        mhd_assert ((0 == pr) || (',' == str[pr - 2]));
1391
0
      } while (1);
1392
0
    }
1393
0
  }
1394
1395
0
  return token_removed;
1396
0
}
1397
1398
1399
#ifndef MHD_FAVOR_SMALL_CODE
1400
/* Use individual function for each case */
1401
1402
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
1403
MHD_FN_PAR_CSTR_ (1) MHD_FN_PAR_IN_ (1)
1404
MHD_FN_PAR_OUT_ (2) size_t
1405
mhd_str_to_uint64 (const char *restrict str,
1406
                   uint_fast64_t *restrict out_val)
1407
1.17k
{
1408
1.17k
  const char *const start = str;
1409
1.17k
  uint_fast64_t res;
1410
1411
1.17k
  if (! isasciidigit (str[0]))
1412
708
    return 0;
1413
1414
463
  res = 0;
1415
463
  do
1416
10.1k
  {
1417
10.1k
    const int digit = (unsigned char) (*str) - '0';
1418
10.1k
    uint_fast64_t prev_res = res;
1419
1420
10.1k
    res *= 10;
1421
10.1k
    if (res / 10 != prev_res)
1422
26
      return 0;
1423
10.1k
    res += (unsigned int) digit;
1424
10.1k
    if (res < (unsigned int) digit)
1425
32
      return 0;
1426
1427
10.1k
    str++;
1428
10.1k
  } while (isasciidigit (*str));
1429
1430
405
  *out_val = res;
1431
405
  return (size_t) (str - start);
1432
463
}
1433
1434
1435
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
1436
MHD_FN_PAR_IN_SIZE_ (1,2)
1437
MHD_FN_PAR_OUT_ (3) size_t
1438
mhd_str_to_uint64_n (const char *restrict str,
1439
                     size_t maxlen,
1440
                     uint_fast64_t *restrict out_val)
1441
1.17k
{
1442
1.17k
  uint_fast64_t res;
1443
1.17k
  size_t i;
1444
1445
1.17k
  if (! maxlen || ! isasciidigit (str[0]))
1446
901
    return 0;
1447
1448
270
  res = 0;
1449
270
  i = 0;
1450
270
  do
1451
5.93k
  {
1452
5.93k
    const int digit = (unsigned char) str[i] - '0';
1453
5.93k
    uint_fast64_t prev_res = res;
1454
1455
5.93k
    res *= 10;
1456
5.93k
    if (res / 10 != prev_res)
1457
15
      return 0;
1458
5.92k
    res += (unsigned int) digit;
1459
5.92k
    if (res < (unsigned int) digit)
1460
19
      return 0;
1461
5.90k
    i++;
1462
5.90k
  } while ( (i < maxlen) &&
1463
5.90k
            isasciidigit (str[i]) );
1464
1465
236
  *out_val = res;
1466
236
  return i;
1467
270
}
1468
1469
1470
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
1471
MHD_FN_PAR_CSTR_ (1)
1472
MHD_FN_PAR_IN_ (1) MHD_FN_PAR_OUT_ (2) size_t
1473
mhd_strx_to_uint32 (const char *restrict str,
1474
                    uint_fast32_t *restrict out_val)
1475
1.17k
{
1476
1.17k
  const char *const start = str;
1477
1.17k
  uint_fast32_t res;
1478
1.17k
  int digit;
1479
1480
1.17k
  res = 0;
1481
1.17k
  digit = xdigittovalue (*str);
1482
14.2k
  while (digit >= 0)
1483
13.2k
  {
1484
13.2k
    uint_fast32_t prev_res = res;
1485
1486
13.2k
    res *= 16;
1487
13.2k
    if (res / 16 != prev_res)
1488
173
      return 0;
1489
13.0k
    res += (unsigned int) digit;
1490
13.0k
    if (res < (unsigned int) digit)
1491
0
      return 0;
1492
1493
13.0k
    str++;
1494
13.0k
    digit = xdigittovalue (*str);
1495
13.0k
  }
1496
1497
998
  if (str - start > 0)
1498
544
    *out_val = res;
1499
998
  return (size_t) (str - start);
1500
1.17k
}
1501
1502
1503
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
1504
MHD_FN_PAR_IN_SIZE_ (1,2)
1505
MHD_FN_PAR_OUT_ (3) size_t
1506
mhd_strx_to_uint32_n (const char *restrict str,
1507
                      size_t maxlen,
1508
                      uint_fast32_t *restrict out_val)
1509
1.17k
{
1510
1.17k
  size_t i;
1511
1.17k
  uint_fast32_t res;
1512
1.17k
  int digit;
1513
1514
1.17k
  res = 0;
1515
1.17k
  i = 0;
1516
6.94k
  while (i < maxlen && (digit = xdigittovalue (str[i])) >= 0)
1517
6.01k
  {
1518
6.01k
    uint_fast32_t prev_res = res;
1519
1520
6.01k
    res *= 16;
1521
6.01k
    if (res / 16 != prev_res)
1522
243
      return 0;
1523
5.77k
    res += (unsigned int) digit;
1524
5.77k
    if (res < (unsigned int) digit)
1525
0
      return 0;
1526
1527
5.77k
    res *= 16;
1528
5.77k
    res += (unsigned int) digit;
1529
5.77k
    i++;
1530
5.77k
  }
1531
1532
928
  if (i)
1533
159
    *out_val = res;
1534
928
  return i;
1535
1.17k
}
1536
1537
1538
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
1539
MHD_FN_PAR_CSTR_ (1)
1540
MHD_FN_PAR_IN_ (1) MHD_FN_PAR_OUT_ (2) size_t
1541
mhd_strx_to_uint64 (const char *restrict str,
1542
                    uint_fast64_t *restrict out_val)
1543
1.17k
{
1544
1.17k
  const char *const start = str;
1545
1.17k
  uint_fast64_t res;
1546
1.17k
  int digit;
1547
1548
1.17k
  res = 0;
1549
1.17k
  digit = xdigittovalue (*str);
1550
14.2k
  while (digit >= 0)
1551
13.2k
  {
1552
13.2k
    uint_fast64_t prev_res = res;
1553
1554
13.2k
    res *= 16;
1555
13.2k
    if (res / 16 != prev_res)
1556
173
      return 0;
1557
13.0k
    res += (unsigned int) digit;
1558
13.0k
    if (res < (unsigned int) digit)
1559
0
      return 0;
1560
1561
13.0k
    str++;
1562
13.0k
    digit = xdigittovalue (*str);
1563
13.0k
  }
1564
1565
998
  if (str - start > 0)
1566
544
    *out_val = res;
1567
998
  return (size_t) (str - start);
1568
1.17k
}
1569
1570
1571
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
1572
MHD_FN_PAR_IN_SIZE_ (1,2)
1573
MHD_FN_PAR_OUT_ (3) size_t
1574
mhd_strx_to_uint64_n (const char *restrict str,
1575
                      size_t maxlen,
1576
                      uint_fast64_t *restrict out_val)
1577
1.17k
{
1578
1.17k
  size_t i;
1579
1.17k
  uint_fast64_t res;
1580
1.17k
  int digit;
1581
1582
1.17k
  res = 0;
1583
1.17k
  i = 0;
1584
8.54k
  while (i < maxlen && (digit = xdigittovalue (str[i])) >= 0)
1585
7.48k
  {
1586
7.48k
    uint_fast64_t prev_res = res;
1587
1588
7.48k
    res *= 16;
1589
7.48k
    if (res / 16 != prev_res)
1590
102
      return 0;
1591
7.37k
    res += (unsigned int) digit;
1592
7.37k
    if (res < (unsigned int) digit)
1593
0
      return 0;
1594
7.37k
    i++;
1595
7.37k
  }
1596
1597
1.06k
  if (i)
1598
300
    *out_val = res;
1599
1.06k
  return i;
1600
1.17k
}
1601
1602
1603
#else  /* MHD_FAVOR_SMALL_CODE */
1604
1605
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
1606
MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4) size_t
1607
mhd_str_to_uvalue_n (const char *restrict str,
1608
                     size_t maxlen,
1609
                     void *restrict out_val,
1610
                     size_t val_size,
1611
                     uint_fast64_t max_val,
1612
                     unsigned int base)
1613
{
1614
  size_t i;
1615
  uint_fast64_t res;
1616
  const uint_fast64_t max_v_div_b = max_val / base;
1617
  const uint_fast64_t max_v_mod_b = max_val % base;
1618
1619
  if ((base != 16) && (base != 10))
1620
    return 0;
1621
1622
  res = 0;
1623
  i = 0;
1624
  while (maxlen > i)
1625
  {
1626
    const int digit = (base == 16) ?
1627
                      xdigittovalue (str[i]) : todigitvalue (str[i]);
1628
1629
    if (0 > digit)
1630
      break;
1631
    if ( ((max_v_div_b) < res) ||
1632
         (( (max_v_div_b) == res) &&
1633
          ( (max_v_mod_b) < (uint_fast64_t) digit) ) )
1634
      return 0;
1635
1636
    res *= base;
1637
    res += (unsigned int) digit;
1638
    i++;
1639
  }
1640
1641
  if (i)
1642
  {
1643
    if (8 == val_size)
1644
      *(uint_fast64_t *) out_val = res;
1645
    else if (4 == val_size)
1646
      *(uint_fast32_t *) out_val = (uint_fast32_t) res;
1647
    else
1648
      return 0;
1649
  }
1650
  return i;
1651
}
1652
1653
1654
#endif /* MHD_FAVOR_SMALL_CODE */
1655
1656
1657
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
1658
MHD_FN_PAR_OUT_SIZE_ (2,3) size_t
1659
mhd_uint32_to_strx (uint_fast32_t val,
1660
                    char *buf,
1661
                    size_t buf_size)
1662
0
{
1663
0
  size_t o_pos = 0; /**< position of the output character */
1664
0
  int digit_pos = 8; /** zero-based, digit position in @a 'val' */
1665
0
  uint_least32_t val32 = ((uint_least32_t) val) & 0xFFFFFFFFu;
1666
0
  unsigned int xdigit;
1667
1668
  /* Skip leading zeros */
1669
0
  do
1670
0
  {
1671
0
    digit_pos--;
1672
0
    xdigit = (unsigned int) (val32 >> 28);
1673
0
    val32 <<= 4;
1674
0
    val32 &= 0xFFFFFFFFu;
1675
0
  } while ((0 == xdigit) && (0 != digit_pos));
1676
1677
0
  while (o_pos < buf_size)
1678
0
  {
1679
0
    buf[o_pos++] = valuetoxdigit (xdigit);
1680
0
    if (0 == digit_pos)
1681
0
      return o_pos;
1682
0
    digit_pos--;
1683
0
    xdigit = (unsigned int) (val32 >> 28);
1684
0
    val32 <<= 4;
1685
0
    val32 &= 0xFFFFFFFFu;
1686
0
  }
1687
0
  return 0; /* The buffer is too small */
1688
0
}
1689
1690
1691
#ifndef MHD_FAVOR_SMALL_CODE
1692
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
1693
MHD_FN_PAR_OUT_SIZE_ (2,3) size_t
1694
mhd_uint16_to_str (uint_least16_t val,
1695
                   char *buf,
1696
                   size_t buf_size)
1697
2.34k
{
1698
2.34k
  char *chr;  /**< pointer to the current printed digit */
1699
  /* The biggest printable number is 65535 */
1700
2.34k
  uint_least16_t divisor = UINT16_C (10000);
1701
2.34k
  int digit;
1702
1703
2.34k
  val &= 0xFFFFu;
1704
2.34k
  chr = buf;
1705
2.34k
  digit = (int) (val / divisor);
1706
2.34k
  mhd_assert (digit < 10);
1707
1708
  /* Do not print leading zeros */
1709
9.19k
  while ((0 == digit) && (1 < divisor))
1710
6.85k
  {
1711
6.85k
    divisor /= 10;
1712
6.85k
    digit = (int) (val / divisor);
1713
6.85k
    mhd_assert (digit < 10);
1714
6.85k
  }
1715
1716
4.85k
  while (0 != buf_size)
1717
4.58k
  {
1718
4.58k
    *chr = (char) ((char) digit + '0');
1719
4.58k
    chr++;
1720
4.58k
    buf_size--;
1721
4.58k
    if (1 == divisor)
1722
2.06k
      return (size_t) (chr - buf);
1723
2.51k
    val = (uint_least16_t) (val % divisor);
1724
2.51k
    divisor /= 10;
1725
2.51k
    digit = (int) (val / divisor);
1726
2.51k
    mhd_assert (digit < 10);
1727
2.51k
  }
1728
274
  return 0; /* The buffer is too small */
1729
2.34k
}
1730
1731
1732
#endif /* !MHD_FAVOR_SMALL_CODE */
1733
1734
1735
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
1736
MHD_FN_PAR_OUT_SIZE_ (2,3) size_t
1737
mhd_uint64_to_str (uint_fast64_t val,
1738
                   char *buf,
1739
                   size_t buf_size)
1740
2.34k
{
1741
2.34k
  char *chr;  /**< pointer to the current printed digit */
1742
  /* The biggest printable number is 18446744073709551615 */
1743
2.34k
  uint_fast64_t divisor = (uint_fast64_t) 10000000000000000000U;
1744
2.34k
  int digit;
1745
1746
2.34k
  val &= 0xFFFFFFFFFFFFFFFFu;
1747
2.34k
  chr = buf;
1748
2.34k
  digit = (int) (val / divisor);
1749
2.34k
  mhd_assert (digit < 10);
1750
1751
  /* Do not print leading zeros */
1752
31.6k
  while ((0 == digit) && (1 < divisor))
1753
29.2k
  {
1754
29.2k
    divisor /= 10;
1755
29.2k
    digit = (int) (val / divisor);
1756
29.2k
    mhd_assert (digit < 10);
1757
29.2k
  }
1758
1759
11.0k
  while (0 != buf_size)
1760
10.5k
  {
1761
10.5k
    *chr = (char) ((char) digit + '0');
1762
10.5k
    chr++;
1763
10.5k
    buf_size--;
1764
10.5k
    if (1 == divisor)
1765
1.83k
      return (size_t) (chr - buf);
1766
8.70k
    val %= divisor;
1767
8.70k
    divisor /= 10;
1768
8.70k
    digit = (int) (val / divisor);
1769
8.70k
    mhd_assert (digit < 10);
1770
8.70k
  }
1771
508
  return 0; /* The buffer is too small */
1772
2.34k
}
1773
1774
1775
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
1776
MHD_FN_PAR_OUT_SIZE_ (3,4) size_t
1777
mhd_uint8_to_str_pad (uint8_t val,
1778
                      uint8_t min_digits,
1779
                      char *buf,
1780
                      size_t buf_size)
1781
0
{
1782
0
  size_t pos; /**< the position of the current printed digit */
1783
0
  int digit;
1784
0
  mhd_assert (3 >= min_digits);
1785
1786
0
  pos = 0;
1787
0
  digit = val / 100;
1788
0
  if (0 == digit)
1789
0
  {
1790
0
    if (3 <= min_digits)
1791
0
      buf[pos++] = '0';
1792
0
  }
1793
0
  else
1794
0
  {
1795
0
    buf[pos++] = (char) ('0' + (char) digit);
1796
0
    val %= 100;
1797
0
    min_digits = 2;
1798
0
  }
1799
1800
0
  if (buf_size <= pos)
1801
0
    return 0;
1802
0
  digit = val / 10;
1803
0
  if (0 == digit)
1804
0
  {
1805
0
    if (2 <= min_digits)
1806
0
      buf[pos++] = '0';
1807
0
  }
1808
0
  else
1809
0
  {
1810
0
    buf[pos++] = (char) ('0' + (char) digit);
1811
0
    val %= 10;
1812
0
  }
1813
1814
0
  if (buf_size <= pos)
1815
0
    return 0;
1816
0
  buf[pos++] = (char) ('0' + (char) val);
1817
0
  return pos;
1818
0
}
1819
1820
1821
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
1822
MHD_FN_PAR_IN_SIZE_ (1, 2) MHD_FN_PAR_OUT_ (3) size_t
1823
mhd_bin_to_hex (const void *restrict bin,
1824
                size_t size,
1825
                char *restrict hex)
1826
218
{
1827
218
  size_t i;
1828
1829
37.0k
  for (i = 0; i < size; ++i)
1830
36.8k
  {
1831
36.8k
    const uint8_t b = ((const uint8_t *) bin)[i];
1832
36.8k
#ifdef mhd_HAVE_UINT8TOTWOXDIGITS
1833
36.8k
    const char *two_xdigits = uint8totwoxdigits (b);
1834
36.8k
    hex[i * 2] = two_xdigits[0];
1835
36.8k
    hex[i * 2 + 1] = two_xdigits[1];
1836
#else  /* ! mhd_HAVE_UINT8TOTWOXDIGITS */
1837
    hex[i * 2] = valuetoxdigit (b >> 4);
1838
    hex[i * 2 + 1] = valuetoxdigit (b & 0x0Fu);
1839
#endif /* ! mhd_HAVE_UINT8TOTWOXDIGITS */
1840
36.8k
  }
1841
218
  return i * 2;
1842
218
}
1843
1844
1845
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
1846
MHD_FN_PAR_IN_SIZE_ (1, 2) MHD_FN_PAR_OUT_ (3) size_t
1847
mhd_bin_to_hex_z (const void *restrict bin,
1848
                  size_t size,
1849
                  char *restrict hex)
1850
0
{
1851
0
  size_t res;
1852
1853
0
  res = mhd_bin_to_hex (bin, size, hex);
1854
0
  hex[res] = 0;
1855
1856
0
  return res;
1857
0
}
1858
1859
1860
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
1861
MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_ (3) size_t
1862
mhd_hex_to_bin (const char *restrict hex,
1863
                size_t len,
1864
                void *restrict bin)
1865
123
{
1866
123
  size_t r;
1867
123
  size_t w;
1868
1869
123
  r = 0;
1870
123
  w = 0;
1871
123
  if (0 != len % 2)
1872
55
  {
1873
    /* Assume the first byte is encoded with single digit */
1874
55
    const char c2 = hex[r++];
1875
55
    const int l = xdigittovalue (c2);
1876
55
    if (0 > l)
1877
37
      return 0;
1878
18
    ((uint8_t *) bin)[w++] = (uint8_t) ((unsigned int) l);
1879
18
  }
1880
1.85k
  while (r < len)
1881
1.81k
  {
1882
1.81k
    const char c1 = hex[r++];
1883
1.81k
    const char c2 = hex[r++];
1884
1.81k
    const int h = xdigittovalue (c1);
1885
1.81k
    const int l = xdigittovalue (c2);
1886
1.81k
    if ((0 > h) || (0 > l))
1887
45
      return 0;
1888
1.77k
    ((uint8_t *) bin)[w++] =
1889
1.77k
      (uint8_t) ( ((uint8_t) (((uint8_t) ((unsigned int) h)) << 4))
1890
1.77k
                  | ((uint8_t) ((unsigned int) l)) );
1891
1.77k
  }
1892
41
  mhd_assert (len == r);
1893
41
  mhd_assert ((len + 1) / 2 == w);
1894
41
  return w;
1895
86
}
1896
1897
1898
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
1899
MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4) size_t
1900
mhd_str_pct_decode_strict_n (const char *pct_encoded,
1901
                             size_t pct_encoded_len,
1902
                             char *decoded,
1903
                             size_t buf_size)
1904
232
{
1905
#ifdef MHD_FAVOR_SMALL_CODE
1906
  bool broken;
1907
  size_t res;
1908
1909
  res = mhd_str_pct_decode_lenient_n (pct_encoded, pct_encoded_len, decoded,
1910
                                      buf_size, &broken);
1911
  if (broken)
1912
    return 0;
1913
  return res;
1914
#else  /* ! MHD_FAVOR_SMALL_CODE */
1915
232
  size_t r;
1916
232
  size_t w;
1917
232
  r = 0;
1918
232
  w = 0;
1919
1920
232
  if (buf_size >= pct_encoded_len)
1921
232
  {
1922
11.1k
    while (r < pct_encoded_len)
1923
11.0k
    {
1924
11.0k
      const char chr = pct_encoded[r];
1925
11.0k
      if ('%' == chr)
1926
349
      {
1927
349
        if (2 > pct_encoded_len - r)
1928
16
          return 0;
1929
333
        else
1930
333
        {
1931
333
          const char c1 = pct_encoded[++r];
1932
333
          const char c2 = pct_encoded[++r];
1933
333
          const int h = xdigittovalue (c1);
1934
333
          const int l = xdigittovalue (c2);
1935
333
          unsigned char out;
1936
333
          if ((0 > h) || (0 > l))
1937
108
            return 0;
1938
225
          out =
1939
225
            (unsigned char) (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4))
1940
225
                             | ((uint8_t) ((unsigned int) l)));
1941
225
          decoded[w] = (char) out;
1942
225
        }
1943
349
      }
1944
10.7k
      else
1945
10.7k
        decoded[w] = chr;
1946
10.9k
      ++r;
1947
10.9k
      ++w;
1948
10.9k
    }
1949
108
    return w;
1950
232
  }
1951
1952
0
  while (r < pct_encoded_len)
1953
0
  {
1954
0
    const char chr = pct_encoded[r];
1955
0
    if (w >= buf_size)
1956
0
      return 0;
1957
0
    if ('%' == chr)
1958
0
    {
1959
0
      if (2 > pct_encoded_len - r)
1960
0
        return 0;
1961
0
      else
1962
0
      {
1963
0
        const char c1 = pct_encoded[++r];
1964
0
        const char c2 = pct_encoded[++r];
1965
0
        const int h = xdigittovalue (c1);
1966
0
        const int l = xdigittovalue (c2);
1967
0
        unsigned char out;
1968
0
        if ((0 > h) || (0 > l))
1969
0
          return 0;
1970
0
        out =
1971
0
          (unsigned char) (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4))
1972
0
                           | ((uint8_t) ((unsigned int) l)));
1973
0
        decoded[w] = (char) out;
1974
0
      }
1975
0
    }
1976
0
    else
1977
0
      decoded[w] = chr;
1978
0
    ++r;
1979
0
    ++w;
1980
0
  }
1981
0
  return w;
1982
0
#endif /* ! MHD_FAVOR_SMALL_CODE */
1983
0
}
1984
1985
1986
MHD_INTERNAL
1987
MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (3)
1988
MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4) size_t
1989
mhd_str_pct_decode_lenient_n (const char *pct_encoded,
1990
                              size_t pct_encoded_len,
1991
                              char *decoded,
1992
                              size_t buf_size,
1993
                              bool *restrict broken_encoding)
1994
232
{
1995
232
  size_t r;
1996
232
  size_t w;
1997
232
  r = 0;
1998
232
  w = 0;
1999
232
  if (NULL != broken_encoding)
2000
232
    *broken_encoding = false;
2001
232
#ifndef MHD_FAVOR_SMALL_CODE
2002
232
  if (buf_size >= pct_encoded_len)
2003
232
  {
2004
15.4k
    while (r < pct_encoded_len)
2005
15.2k
    {
2006
15.2k
      const char chr = pct_encoded[r];
2007
15.2k
      if ('%' == chr)
2008
1.82k
      {
2009
1.82k
        if (2 > pct_encoded_len - r)
2010
30
        {
2011
30
          if (NULL != broken_encoding)
2012
30
            *broken_encoding = true;
2013
30
          decoded[w] = chr; /* Copy "as is" */
2014
30
        }
2015
1.79k
        else
2016
1.79k
        {
2017
1.79k
          const char c1 = pct_encoded[++r];
2018
1.79k
          const char c2 = pct_encoded[++r];
2019
1.79k
          const int h = xdigittovalue (c1);
2020
1.79k
          const int l = xdigittovalue (c2);
2021
1.79k
          unsigned char out;
2022
1.79k
          if ((0 > h) || (0 > l))
2023
1.25k
          {
2024
1.25k
            r -= 2;
2025
1.25k
            if (NULL != broken_encoding)
2026
1.25k
              *broken_encoding = true;
2027
1.25k
            decoded[w] = chr; /* Copy "as is" */
2028
1.25k
          }
2029
543
          else
2030
543
          {
2031
543
            out =
2032
543
              (unsigned char)
2033
543
              (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4))
2034
543
               | ((uint8_t) ((unsigned int) l)));
2035
543
            decoded[w] = (char) out;
2036
543
          }
2037
1.79k
        }
2038
1.82k
      }
2039
13.4k
      else
2040
13.4k
        decoded[w] = chr;
2041
15.2k
      ++r;
2042
15.2k
      ++w;
2043
15.2k
    }
2044
232
    return w;
2045
232
  }
2046
0
#endif /* ! MHD_FAVOR_SMALL_CODE */
2047
0
  while (r < pct_encoded_len)
2048
0
  {
2049
0
    const char chr = pct_encoded[r];
2050
0
    if (w >= buf_size)
2051
0
      return 0;
2052
0
    if ('%' == chr)
2053
0
    {
2054
0
      if (2 > pct_encoded_len - r)
2055
0
      {
2056
0
        if (NULL != broken_encoding)
2057
0
          *broken_encoding = true;
2058
0
        decoded[w] = chr; /* Copy "as is" */
2059
0
      }
2060
0
      else
2061
0
      {
2062
0
        const char c1 = pct_encoded[++r];
2063
0
        const char c2 = pct_encoded[++r];
2064
0
        const int h = xdigittovalue (c1);
2065
0
        const int l = xdigittovalue (c2);
2066
0
        if ((0 > h) || (0 > l))
2067
0
        {
2068
0
          r -= 2;
2069
0
          if (NULL != broken_encoding)
2070
0
            *broken_encoding = true;
2071
0
          decoded[w] = chr; /* Copy "as is" */
2072
0
        }
2073
0
        else
2074
0
        {
2075
0
          unsigned char out;
2076
0
          out =
2077
0
            (unsigned char)
2078
0
            (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4))
2079
0
             | ((uint8_t) ((unsigned int) l)));
2080
0
          decoded[w] = (char) out;
2081
0
        }
2082
0
      }
2083
0
    }
2084
0
    else
2085
0
      decoded[w] = chr;
2086
0
    ++r;
2087
0
    ++w;
2088
0
  }
2089
0
  return w;
2090
0
}
2091
2092
2093
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
2094
MHD_FN_PAR_CSTR_ (1) size_t
2095
mhd_str_pct_decode_in_place_strict (char *str)
2096
232
{
2097
#ifdef MHD_FAVOR_SMALL_CODE
2098
  size_t res;
2099
  bool broken;
2100
2101
  res = mhd_str_pct_decode_in_place_lenient (str, &broken);
2102
  if (broken)
2103
  {
2104
    res = 0;
2105
    str[0] = 0;
2106
  }
2107
  return res;
2108
#else  /* ! MHD_FAVOR_SMALL_CODE */
2109
232
  size_t r;
2110
232
  size_t w;
2111
232
  r = 0;
2112
232
  w = 0;
2113
2114
5.08k
  while (0 != str[r])
2115
4.97k
  {
2116
4.97k
    const char chr = str[r++];
2117
4.97k
    if ('%' == chr)
2118
340
    {
2119
340
      const char d1 = str[r++];
2120
340
      if (0 == d1)
2121
12
        return 0;
2122
328
      else
2123
328
      {
2124
328
        const char d2 = str[r++];
2125
328
        if (0 == d2)
2126
35
          return 0;
2127
293
        else
2128
293
        {
2129
293
          const int h = xdigittovalue (d1);
2130
293
          const int l = xdigittovalue (d2);
2131
293
          unsigned char out;
2132
293
          if ((0 > h) || (0 > l))
2133
72
            return 0;
2134
221
          out =
2135
221
            (unsigned char)
2136
221
            (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4))
2137
221
             | ((uint8_t) ((unsigned int) l)));
2138
221
          str[w++] = (char) out;
2139
221
        }
2140
328
      }
2141
340
    }
2142
4.63k
    else
2143
4.63k
      str[w++] = chr;
2144
4.97k
  }
2145
113
  str[w] = 0;
2146
113
  return w;
2147
232
#endif /* ! MHD_FAVOR_SMALL_CODE */
2148
232
}
2149
2150
2151
MHD_INTERNAL
2152
MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_CSTR_ (1) size_t
2153
mhd_str_pct_decode_in_place_lenient (char *restrict str,
2154
                                     bool *restrict broken_encoding)
2155
232
{
2156
#ifdef MHD_FAVOR_SMALL_CODE
2157
  size_t len;
2158
  size_t res;
2159
2160
  len = strlen (str);
2161
  res = mhd_str_pct_decode_lenient_n (str, len, str, len, broken_encoding);
2162
  str[res] = 0;
2163
2164
  return res;
2165
#else  /* ! MHD_FAVOR_SMALL_CODE */
2166
232
  size_t r;
2167
232
  size_t w;
2168
232
  if (NULL != broken_encoding)
2169
232
    *broken_encoding = false;
2170
232
  r = 0;
2171
232
  w = 0;
2172
6.82k
  while (0 != str[r])
2173
6.64k
  {
2174
6.64k
    const char chr = str[r++];
2175
6.64k
    if ('%' == chr)
2176
914
    {
2177
914
      const char d1 = str[r++];
2178
914
      if (0 == d1)
2179
14
      {
2180
14
        if (NULL != broken_encoding)
2181
14
          *broken_encoding = true;
2182
14
        str[w++] = chr; /* Copy "as is" */
2183
14
        str[w] = 0;
2184
14
        return w;
2185
14
      }
2186
900
      else
2187
900
      {
2188
900
        const char d2 = str[r++];
2189
900
        if (0 == d2)
2190
38
        {
2191
38
          if (NULL != broken_encoding)
2192
38
            *broken_encoding = true;
2193
38
          str[w++] = chr; /* Copy "as is" */
2194
38
          str[w++] = d1; /* Copy "as is" */
2195
38
          str[w] = 0;
2196
38
          return w;
2197
38
        }
2198
862
        else
2199
862
        {
2200
862
          const int h = xdigittovalue (d1);
2201
862
          const int l = xdigittovalue (d2);
2202
862
          unsigned char out;
2203
862
          if ((0 > h) || (0 > l))
2204
620
          {
2205
620
            if (NULL != broken_encoding)
2206
620
              *broken_encoding = true;
2207
620
            str[w++] = chr; /* Copy "as is" */
2208
620
            str[w++] = d1;
2209
620
            str[w++] = d2;
2210
620
            continue;
2211
620
          }
2212
242
          out =
2213
242
            (unsigned char)
2214
242
            (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4))
2215
242
             | ((uint8_t) ((unsigned int) l)));
2216
242
          str[w++] = (char) out;
2217
242
          continue;
2218
862
        }
2219
900
      }
2220
914
    }
2221
5.72k
    str[w++] = chr;
2222
5.72k
  }
2223
180
  str[w] = 0;
2224
180
  return w;
2225
232
#endif /* ! MHD_FAVOR_SMALL_CODE */
2226
232
}
2227
2228
2229
#ifdef MHD_SUPPORT_AUTH_DIGEST
2230
2231
MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_
2232
MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_IN_SIZE_ (3,4) bool
2233
mhd_str_equal_quoted_bin_n (const char *quoted,
2234
                            size_t quoted_len,
2235
                            const char *unquoted,
2236
                            size_t unquoted_len)
2237
0
{
2238
0
  size_t i;
2239
0
  size_t j;
2240
0
  if (unquoted_len < quoted_len / 2)
2241
0
    return false;
2242
2243
0
  j = 0;
2244
0
  for (i = 0; quoted_len > i && unquoted_len > j; ++i, ++j)
2245
0
  {
2246
0
    if ('\\' == quoted[i])
2247
0
    {
2248
0
      i++; /* Advance to the next character */
2249
0
      if (quoted_len == i)
2250
0
        return false; /* No character after escaping backslash */
2251
0
    }
2252
0
    if (quoted[i] != unquoted[j])
2253
0
      return false; /* Different characters */
2254
0
  }
2255
0
  if ((quoted_len != i) || (unquoted_len != j))
2256
0
    return false; /* The strings have different length */
2257
2258
0
  return true;
2259
0
}
2260
2261
2262
MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_
2263
MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_IN_SIZE_ (3,4) bool
2264
mhd_str_equal_caseless_quoted_bin_n (const char *quoted,
2265
                                     size_t quoted_len,
2266
                                     const char *unquoted,
2267
                                     size_t unquoted_len)
2268
0
{
2269
0
  size_t i;
2270
0
  size_t j;
2271
0
  if (unquoted_len < quoted_len / 2)
2272
0
    return false;
2273
2274
0
  j = 0;
2275
0
  for (i = 0; quoted_len > i && unquoted_len > j; ++i, ++j)
2276
0
  {
2277
0
    if ('\\' == quoted[i])
2278
0
    {
2279
0
      i++; /* Advance to the next character */
2280
0
      if (quoted_len == i)
2281
0
        return false; /* No character after escaping backslash */
2282
0
    }
2283
0
    if (! charsequalcaseless (quoted[i], unquoted[j]))
2284
0
      return false; /* Different characters */
2285
0
  }
2286
0
  if ((quoted_len != i) || (unquoted_len != j))
2287
0
    return false; /* The strings have different length */
2288
2289
0
  return true;
2290
0
}
2291
2292
2293
#endif /* MHD_SUPPORT_AUTH_DIGEST */
2294
2295
#if defined(MHD_SUPPORT_AUTH_DIGEST) || defined(MHD_SUPPORT_POST_PARSER)
2296
2297
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
2298
MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,2) size_t
2299
mhd_str_unquote (const char *quoted,
2300
                 size_t quoted_len,
2301
                 char *result)
2302
366
{
2303
366
  size_t r;
2304
366
  size_t w;
2305
2306
366
  r = 0;
2307
366
  w = 0;
2308
2309
33.8k
  while (quoted_len > r)
2310
33.5k
  {
2311
33.5k
    if ('\\' == quoted[r])
2312
446
    {
2313
446
      ++r;
2314
446
      if (quoted_len == r)
2315
23
        return 0; /* Last backslash is not followed by char to unescape */
2316
446
    }
2317
33.4k
    result[w++] = quoted[r++];
2318
33.4k
  }
2319
343
  return w;
2320
366
}
2321
2322
2323
#endif /* MHD_SUPPORT_AUTH_DIGEST || MHD_SUPPORT_POST_PARSER */
2324
2325
#if defined(MHD_SUPPORT_AUTH_DIGEST) || defined(MHD_SUPPORT_AUTH_BASIC)
2326
2327
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
2328
MHD_FN_PAR_IN_SIZE_ (1,2)
2329
MHD_FN_PAR_OUT_SIZE_ (3,4) size_t
2330
mhd_str_quote (const char *unquoted,
2331
               size_t unquoted_len,
2332
               char *result,
2333
               size_t buf_size)
2334
1.06k
{
2335
1.06k
  size_t r;
2336
1.06k
  size_t w;
2337
2338
1.06k
  r = 0;
2339
1.06k
  w = 0;
2340
2341
1.06k
#ifndef MHD_FAVOR_SMALL_CODE
2342
1.06k
  if (unquoted_len * 2 <= buf_size)
2343
1.06k
  {
2344
    /* Fast loop: the output will fit the buffer with any input string content */
2345
39.6k
    while (unquoted_len > r)
2346
38.5k
    {
2347
38.5k
      const char chr = unquoted[r++];
2348
38.5k
      if (('\\' == chr) || ('\"' == chr))
2349
1.05k
        result[w++] = '\\'; /* Escape current char */
2350
38.5k
      result[w++] = chr;
2351
38.5k
    }
2352
1.06k
  }
2353
0
  else
2354
0
  {
2355
0
    if (unquoted_len > buf_size)
2356
0
      return 0; /* Quick fail: the output buffer is too small */
2357
#else  /* MHD_FAVOR_SMALL_CODE */
2358
  if (1)
2359
  {
2360
#endif /* MHD_FAVOR_SMALL_CODE */
2361
2362
0
    while (unquoted_len > r)
2363
0
    {
2364
0
      if (buf_size <= w)
2365
0
        return 0; /* The output buffer is too small */
2366
0
      else
2367
0
      {
2368
0
        const char chr = unquoted[r++];
2369
0
        if (('\\' == chr) || ('\"' == chr))
2370
0
        {
2371
0
          result[w++] = '\\'; /* Escape current char */
2372
0
          if (buf_size <= w)
2373
0
            return 0; /* The output buffer is too small */
2374
0
        }
2375
0
        result[w++] = chr;
2376
0
      }
2377
0
    }
2378
0
  }
2379
2380
1.06k
  mhd_assert (w >= r);
2381
1.06k
  mhd_assert (w <= r * 2);
2382
1.06k
  return w;
2383
1.06k
}
2384
2385
2386
#endif /* MHD_SUPPORT_AUTH_DIGEST || MHD_SUPPORT_AUTH_BASIC */
2387
2388
#ifdef MHD_SUPPORT_AUTH_BASIC
2389
2390
/*
2391
 * MHD_BASE64_FUNC_VERSION
2392
 * 1 = smallest,
2393
 * 2 = medium,
2394
 * 3 = fastest
2395
 */
2396
#ifndef MHD_BASE64_FUNC_VERSION
2397
#ifdef MHD_FAVOR_SMALL_CODE
2398
#define MHD_BASE64_FUNC_VERSION 1
2399
#else  /* ! MHD_FAVOR_SMALL_CODE */
2400
#define MHD_BASE64_FUNC_VERSION 3
2401
#endif /* ! MHD_FAVOR_SMALL_CODE */
2402
#endif /* ! MHD_BASE64_FUNC_VERSION */
2403
2404
#if MHD_BASE64_FUNC_VERSION < 1 || MHD_BASE64_FUNC_VERSION > 3
2405
#error Wrong MHD_BASE64_FUNC_VERSION value
2406
#endif /* MHD_BASE64_FUNC_VERSION < 1 || MHD_BASE64_FUNC_VERSION > 3 */
2407
2408
#if MHD_BASE64_FUNC_VERSION == 3
2409
#define mhd_base64_map_type int
2410
#else  /* MHD_BASE64_FUNC_VERSION < 3 */
2411
#define mhd_base64_map_type int8_t
2412
#endif /* MHD_BASE64_FUNC_VERSION < 3 */
2413
2414
#if MHD_BASE64_FUNC_VERSION == 1
2415
static mhd_base64_map_type
2416
base64_char_to_value_ (uint8_t c)
2417
{
2418
  if ('Z' >= c)
2419
  {
2420
    if ('A' <= c)
2421
      return (mhd_base64_map_type) ((c - 'A') + 0);
2422
    else if ('0' <= c)
2423
    {
2424
      if ('9' >= c)
2425
        return (mhd_base64_map_type) ((c - '0') + 52);
2426
      else if ('=' == c)
2427
        return -2;
2428
      else
2429
        return -1;
2430
    }
2431
    else if ('+' == c)
2432
      return 62;
2433
    else if ('/' == c)
2434
      return 63;
2435
    else
2436
      return -1;
2437
  }
2438
  else if (('z' >= c) && ('a' <= c))
2439
    return (mhd_base64_map_type) ((c - 'a') + 26);
2440
  return -1;
2441
}
2442
2443
2444
#endif /* MHD_BASE64_FUNC_VERSION == 1 */
2445
2446
2447
mhd_DATA_TRUNCATION_RUNTIME_CHECK_DISABLE
2448
2449
2450
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
2451
MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4) size_t
2452
mhd_base64_to_bin_n (const char *base64,
2453
                     size_t base64_len,
2454
                     void *bin,
2455
                     size_t bin_size)
2456
143
{
2457
143
#if MHD_BASE64_FUNC_VERSION >= 2
2458
143
  static const mhd_base64_map_type map[] = {
2459
    /* -1 = invalid char, -2 = padding
2460
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
2461
    NUL,  SOH,  STX,  ETX,  EOT,  ENQ,  ACK,  BEL,  */
2462
143
    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
2463
    /*
2464
    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
2465
    BS,   HT,   LF,   VT,   FF,   CR,   SO,   SI,   */
2466
143
    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
2467
    /*
2468
    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
2469
    DLE,  DC1,  DC2,  DC3,  DC4,  NAK,  SYN,  ETB,  */
2470
143
    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
2471
    /*
2472
    0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
2473
    CAN,  EM,   SUB,  ESC,  FS,   GS,   RS,   US,   */
2474
143
    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
2475
    /*
2476
    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
2477
    ' ',  '!',  '"',  '#',  '$',  '%',  '&',  '\'', */
2478
143
    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
2479
    /*
2480
    0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
2481
    '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',  */
2482
143
    -1,   -1,   -1,   62,   -1,   -1,   -1,   63,
2483
    /*
2484
    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
2485
    '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',  */
2486
143
    52,   53,   54,   55,   56,   57,   58,   59,
2487
    /*
2488
    0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
2489
    '8',  '9',  ':',  ';',  '<',  '=',  '>',  '?',  */
2490
143
    60,   61,   -1,   -1,   -1,   -2,   -1,   -1,
2491
    /*
2492
    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
2493
    '@',  'A',  'B',  'C',  'D',  'E',  'F',  'G',  */
2494
143
    -1,    0,    1,    2,    3,    4,    5,    6,
2495
    /*
2496
    0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
2497
    'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',  */
2498
143
    7,     8,    9,   10,   11,   12,   13,   14,
2499
    /*
2500
    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
2501
    'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',  */
2502
143
    15,   16,   17,   18,   19,   20,   21,   22,
2503
    /*
2504
     0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
2505
    'X',  'Y',  'Z',  '[',  '\',  ']',  '^',  '_',  */
2506
143
    23,   24,   25,   -1,   -1,   -1,   -1,   -1,
2507
    /*
2508
    0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
2509
    '`',  'a',  'b',  'c',  'd',  'e',  'f',  'g',  */
2510
143
    -1,   26,   27,   28,   29,   30,   31,   32,
2511
    /*
2512
    0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
2513
    'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',  */
2514
143
    33,   34,   35,   36,   37,   38,   39,   40,
2515
    /*
2516
    0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
2517
    'p',  'q',  'r',  's',  't',  'u',  'v',  'w',  */
2518
143
    41,   42,   43,   44,   45,   46,   47,   48,
2519
    /*
2520
    0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
2521
    'x',  'y',  'z',  '{',  '|',  '}',  '~',  DEL,  */
2522
143
    49,   50,   51,   -1,   -1,   -1,   -1,   -1
2523
2524
143
#if MHD_BASE64_FUNC_VERSION == 3
2525
143
    ,
2526
143
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 80..8F */
2527
143
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 90..9F */
2528
143
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* A0..AF */
2529
143
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* B0..BF */
2530
143
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* C0..CF */
2531
143
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* D0..DF */
2532
143
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* E0..EF */
2533
143
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* F0..FF */
2534
143
#endif /* ! MHD_BASE64_FUNC_VERSION == 3 */
2535
143
  };
2536
14.3k
#define base64_char_to_value_(c) map[(c)]
2537
143
#endif /* MHD_BASE64_FUNC_VERSION >= 2 */
2538
143
  const uint8_t *const in = (const uint8_t *) base64;
2539
143
  uint8_t *const out = (uint8_t *) bin;
2540
143
  size_t i;
2541
143
  size_t j;
2542
143
  if (0 == base64_len)
2543
24
    return 0;  /* Nothing to decode */
2544
119
  if (0 != base64_len % 4)
2545
61
    return 0;  /* Wrong input length */
2546
58
  if (base64_len / 4 * 3 - 2 > bin_size)
2547
0
    return 0;
2548
2549
58
  j = 0;
2550
3.58k
  for (i = 0; i < (base64_len - 4); i += 4)
2551
3.52k
  {
2552
#if MHD_BASE64_FUNC_VERSION == 2
2553
    if (0 != (0x80 & (in[i] | in[i + 1] | in[i + 2] | in[i + 3])))
2554
      return 0;
2555
#endif /* MHD_BASE64_FUNC_VERSION == 2 */
2556
3.52k
    if (1)
2557
3.52k
    {
2558
3.52k
      const mhd_base64_map_type v1 = base64_char_to_value_ (in[i + 0]);
2559
3.52k
      const mhd_base64_map_type v2 = base64_char_to_value_ (in[i + 1]);
2560
3.52k
      const mhd_base64_map_type v3 = base64_char_to_value_ (in[i + 2]);
2561
3.52k
      const mhd_base64_map_type v4 = base64_char_to_value_ (in[i + 3]);
2562
3.52k
      if ((0 > v1) || (0 > v2) || (0 > v3) || (0 > v4))
2563
0
        return 0;
2564
3.52k
      out[j + 0] = (uint8_t) (((uint8_t) (((uint8_t) v1) << 2))
2565
3.52k
                              | ((uint8_t) (((uint8_t) v2) >> 4)));
2566
3.52k
      out[j + 1] = (uint8_t) (((uint8_t) (((uint8_t) v2) << 4))
2567
3.52k
                              | ((uint8_t) (((uint8_t) v3) >> 2)));
2568
3.52k
      out[j + 2] = (uint8_t) (((uint8_t) (((uint8_t) v3) << 6))
2569
3.52k
                              | ((uint8_t) v4));
2570
3.52k
    }
2571
3.52k
    j += 3;
2572
3.52k
  }
2573
#if MHD_BASE64_FUNC_VERSION == 2
2574
  if (0 != (0x80 & (in[i] | in[i + 1] | in[i + 2] | in[i + 3])))
2575
    return 0;
2576
#endif /* MHD_BASE64_FUNC_VERSION == 2 */
2577
58
  if (1)
2578
58
  { /* The last four chars block */
2579
58
    const mhd_base64_map_type v1 = base64_char_to_value_ (in[i + 0]);
2580
58
    const mhd_base64_map_type v2 = base64_char_to_value_ (in[i + 1]);
2581
58
    const mhd_base64_map_type v3 = base64_char_to_value_ (in[i + 2]);
2582
58
    const mhd_base64_map_type v4 = base64_char_to_value_ (in[i + 3]);
2583
58
    if ((0 > v1) || (0 > v2))
2584
0
      return 0; /* Invalid char or padding at first two positions */
2585
58
    mhd_assert (j < bin_size);
2586
58
    out[j++] = (uint8_t) (((uint8_t) (((uint8_t) v1) << 2))
2587
58
                          | ((uint8_t) (((uint8_t) v2) >> 4)));
2588
58
    if (0 > v3)
2589
0
    { /* Third char is either padding or invalid */
2590
0
      if ((-2 != v3) || (-2 != v4))
2591
0
        return 0;  /* Both two last chars must be padding */
2592
0
      if (0 != (uint8_t) (((uint8_t) v2) << 4))
2593
0
        return 0;  /* Wrong last char */
2594
0
      return j;
2595
0
    }
2596
58
    if (j >= bin_size)
2597
0
      return 0; /* Not enough space */
2598
58
    out[j++] = (uint8_t) (((uint8_t) (((uint8_t) v2) << 4))
2599
58
                          | ((uint8_t) (((uint8_t) v3) >> 2)));
2600
58
    if (0 > v4)
2601
0
    { /* Fourth char is either padding or invalid */
2602
0
      if (-2 != v4)
2603
0
        return 0;  /* The char must be padding */
2604
0
      if (0 != (uint8_t) (((uint8_t) v3) << 6))
2605
0
        return 0;  /* Wrong last char */
2606
0
      return j;
2607
0
    }
2608
58
    if (j >= bin_size)
2609
0
      return 0; /* Not enough space */
2610
58
    out[j++] = (uint8_t) (((uint8_t) (((uint8_t) v3) << 6))
2611
58
                          | ((uint8_t) v4));
2612
58
  }
2613
58
  return j;
2614
58
#if MHD_BASE64_FUNC_VERSION >= 2
2615
58
#undef base64_char_to_value_
2616
58
#endif /* MHD_BASE64_FUNC_VERSION >= 2 */
2617
58
}
2618
2619
2620
mhd_DATA_TRUNCATION_RUNTIME_CHECK_RESTORE
2621
2622
2623
#undef mhd_base64_map_type
2624
2625
#endif /* MHD_SUPPORT_AUTH_BASIC */
2626
2627
2628
MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ bool
2629
mhd_str_starts_with_token_opt_param (const struct MHD_String *restrict str,
2630
                                     const struct MHD_String *restrict token)
2631
0
{
2632
0
  size_t i;
2633
2634
0
  mhd_assert (0 != token->len);
2635
0
  mhd_assert (NULL == memchr (token->cstr, '=', token->len));
2636
0
  mhd_assert (NULL == memchr (token->cstr, ' ', token->len));
2637
0
  mhd_assert (NULL == memchr (token->cstr, '\t', token->len));
2638
2639
0
  if (str->len < token->len)
2640
0
    return false; /* The string is too short to match */
2641
2642
0
  if (! mhd_str_equal_caseless_bin_n (str->cstr,
2643
0
                                      token->cstr,
2644
0
                                      token->len))
2645
0
    return false; /* The string does not start with the token */
2646
2647
0
  for (i = token->len; i < str->len; ++i)
2648
0
  {
2649
0
    const char c = str->cstr[i];
2650
0
    if ((' ' == c) || ('\t' == c))
2651
0
      continue;
2652
0
    if (';' == c)
2653
0
      return true; /* Found the start of the token parameters */
2654
0
    return false; /* The initial part of the string does not fully match the token */
2655
0
  }
2656
0
  mhd_assert (0 && "The string should not have whitespace at the end");
2657
0
  return true;
2658
0
}
2659
2660
2661
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
2662
MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2) MHD_FN_PAR_IN_ (3)
2663
MHD_FN_PAR_OUT_ (4) MHD_FN_PAR_OUT_ (5) enum mhd_StingStartsWithTokenResult
2664
mhd_str_starts_with_token_req_param (
2665
  const struct MHD_String *restrict str,
2666
  const struct MHD_String *restrict token,
2667
  const struct MHD_String *restrict par,
2668
  struct mhd_BufferConst *restrict par_value,
2669
  bool *restrict par_value_needs_unquote)
2670
1.25k
{
2671
1.25k
  size_t i;
2672
1.25k
  const char *const restrict cstr = str->cstr;
2673
1.25k
  bool token_found;
2674
1.25k
  bool param_found;
2675
2676
1.25k
  mhd_assert (0 != token->len);
2677
1.25k
  mhd_assert (NULL == memchr (token->cstr, '=', token->len));
2678
1.25k
  mhd_assert (NULL == memchr (token->cstr, ' ', token->len));
2679
1.25k
  mhd_assert (NULL == memchr (token->cstr, '\t', token->len));
2680
1.25k
  mhd_assert (NULL == memchr (par->cstr, '=', par->len));
2681
1.25k
  mhd_assert (NULL == memchr (par->cstr, ' ', par->len));
2682
1.25k
  mhd_assert (NULL == memchr (par->cstr, '\t', par->len));
2683
2684
1.25k
  par_value->data = NULL;
2685
1.25k
  par_value->size = 0;
2686
2687
1.25k
  if (str->len < token->len)
2688
84
    return mhd_STR_STARTS_W_TOKEN_NO_TOKEN; /* The string is too short to match */
2689
2690
1.16k
  if (! mhd_str_equal_caseless_bin_n (cstr,
2691
1.16k
                                      token->cstr,
2692
1.16k
                                      token->len))
2693
176
    return mhd_STR_STARTS_W_TOKEN_NO_TOKEN; /* The string does not start with the token */
2694
993
  token_found = false;
2695
993
  param_found = false;
2696
2697
993
  i = token->len;
2698
993
  do
2699
3.43k
  {
2700
    /* Find start of the next parameter */
2701
9.21k
    for ((void) 0; i < str->len; ++i)
2702
8.99k
    {
2703
8.99k
      const char c = cstr[i];
2704
8.99k
      if ((' ' == c) || ('\t' == c))
2705
5.77k
        continue;
2706
3.22k
      if (';' == c)
2707
2.91k
      {
2708
        /* Found the start of the next token parameter */
2709
2.91k
        if (param_found)
2710
20
          return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN;
2711
2.89k
        ++i; /* Move to the next char */
2712
2.89k
        break;
2713
2.91k
      }
2714
310
      if (',' == c)
2715
42
        return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN; /* Found the start of the next token */
2716
2717
268
      if (! token_found)
2718
248
      {
2719
248
        if (i == token->len)
2720
200
        {
2721
          /* The initial part of the string does not fully match the token or
2722
             formatting is not correct */
2723
200
          return mhd_STR_STARTS_W_TOKEN_NO_TOKEN;
2724
200
        }
2725
        /* The string has garbage after the token and whitespace */
2726
48
        return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT;
2727
248
      }
2728
      /* The garbage after the parameter */
2729
20
      return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT;
2730
268
    }
2731
3.10k
    token_found = true;
2732
2733
3.10k
    if (i == str->len)
2734
241
      return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN;
2735
2736
    /* 'i' is at the start of the parameter */
2737
2738
3.48k
    while ((' ' == cstr[i]) || ('\t' == cstr[i]))
2739
636
    {
2740
636
      if (++i == str->len)
2741
23
        return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN;
2742
636
    }
2743
2744
    /* 'i' is at the start of the parameter name */
2745
2746
2.84k
    if (par->len > str->len - i - 1)
2747
30
      return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN; /* the token is found, but the parameter is not */
2748
2.81k
    else
2749
2.81k
    { /* Check the parameter */
2750
2.81k
      bool val_needs_unquote;
2751
2.81k
      size_t j;
2752
2.81k
      const char *const prm_str = cstr + i;
2753
2754
4.28k
      for (j = 0; j < par->len; ++j)
2755
2.71k
        if (! charsequalcaseless (prm_str[j],
2756
2.71k
                                  par->cstr[j]))
2757
1.24k
          break;
2758
2.81k
      i += j;
2759
2.81k
      mhd_assert (str->len > i);
2760
2.81k
      if ((j == par->len) &&
2761
2.81k
          ('=' == cstr[i]))
2762
186
      {
2763
        /* The parameter name matches required parameter */
2764
186
        param_found = true;
2765
186
        par_value->data = cstr + i + 1;
2766
186
      }
2767
2.62k
      else
2768
2.62k
      {
2769
        /* i points to the char in the parameter name */
2770
7.20k
        while ('=' != cstr[i])
2771
4.74k
        {
2772
4.74k
          if ((';' == cstr[i])      /* end of the parameter */
2773
4.74k
              || (',' == cstr[i])   /* end of the token */
2774
4.74k
              || (str->len == ++i)) /* end of the field string */
2775
168
          {
2776
            /* parameter without the value */
2777
168
            return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT;
2778
168
          }
2779
4.74k
        }
2780
2.62k
      }
2781
2.64k
      mhd_assert (str->len > i);
2782
2.64k
      mhd_assert ('=' == cstr[i]);
2783
2784
      /* 'i' points to '=' between parameter name and parameter value */
2785
2786
2.64k
      ++i; /* Advance to the first char in the parameter value */
2787
2.64k
      if (str->len == i)
2788
30
        return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN; /* Zero-length parameter value */
2789
2790
2.61k
      val_needs_unquote = false;
2791
2792
      /* 'i' points to the char after '=' */
2793
2794
2.61k
      if ('"' == cstr[i])
2795
430
      {
2796
        /* The value is quoted */
2797
430
        if (param_found)
2798
81
          ++(par_value->data); /* Point to the first quoted char */
2799
430
        do
2800
8.28k
        {
2801
8.28k
          ++i; /* Advance to the next char */
2802
8.28k
          if (str->len == i)
2803
73
            return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT; /* No closing quote */
2804
8.21k
          if ('\\' == cstr[i])
2805
272
          {
2806
272
            val_needs_unquote = true;
2807
272
            ++i; /* Skip quoted char */
2808
272
            if (str->len == i)
2809
11
              return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT; /* No closing quote */
2810
272
          }
2811
8.21k
        } while ('"' != cstr[i]);
2812
346
        if (param_found)
2813
15
        {
2814
15
          par_value->size = (size_t) ((cstr + i) - par_value->data);
2815
15
          *par_value_needs_unquote = val_needs_unquote;
2816
15
        }
2817
        /* Complete value found */
2818
        /* Check for the garbage data at the end */
2819
346
        ++i; /* Advance to the next char */
2820
346
      }
2821
2.18k
      else
2822
2.18k
      {
2823
        /* The value is not quoted */
2824
4.65k
        while ((' ' != cstr[i]) &&
2825
4.65k
               ('\t' != cstr[i]))
2826
4.01k
        {
2827
4.01k
          if ((';' == cstr[i])      /* end of the parameter */
2828
4.01k
              || (',' == cstr[i])   /* end of the token */
2829
4.01k
              || (str->len == ++i)) /* end of the field string */
2830
1.55k
            break;
2831
4.01k
        }
2832
        /* The end parameter value */
2833
2.18k
        if (param_found)
2834
89
        {
2835
89
          par_value->size = (size_t) ((cstr + i) - par_value->data);
2836
89
          *par_value_needs_unquote = false;
2837
89
        }
2838
        /* Check for the garbage data at the end */
2839
2.18k
      }
2840
2841
      /* 'i' points to the next char after end of the parameter value */
2842
2.61k
    }
2843
2.84k
  } while (i < str->len);
2844
2845
87
  mhd_assert (token_found);
2846
87
  return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN;
2847
993
}