comparison deps/Platinum/ThirdParty/Neptune/Source/Core/NptUtils.cpp @ 0:3425707ddbf6

Initial import (hopefully this mercurial stuff works...)
author fraserofthenight
date Mon, 06 Jul 2009 08:06:28 -0700
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:3425707ddbf6
1 /*****************************************************************
2 |
3 | Neptune - Utils
4 |
5 | Copyright (c) 2002-2008, Axiomatic Systems, LLC.
6 | All rights reserved.
7 |
8 | Redistribution and use in source and binary forms, with or without
9 | modification, are permitted provided that the following conditions are met:
10 | * Redistributions of source code must retain the above copyright
11 | notice, this list of conditions and the following disclaimer.
12 | * Redistributions in binary form must reproduce the above copyright
13 | notice, this list of conditions and the following disclaimer in the
14 | documentation and/or other materials provided with the distribution.
15 | * Neither the name of Axiomatic Systems nor the
16 | names of its contributors may be used to endorse or promote products
17 | derived from this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY
20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY
23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30 ****************************************************************/
31
32 /*----------------------------------------------------------------------
33 | includes
34 +---------------------------------------------------------------------*/
35 #include <math.h>
36
37 #include "NptConfig.h"
38 #include "NptTypes.h"
39 #include "NptDebug.h"
40 #include "NptUtils.h"
41 #include "NptResults.h"
42
43 #if defined(NPT_CONFIG_HAVE_LIMITS_H)
44 #include <limits.h>
45 #endif
46
47 /*----------------------------------------------------------------------
48 | constants
49 +---------------------------------------------------------------------*/
50 const unsigned int NPT_FORMAT_LOCAL_BUFFER_SIZE = 1024;
51 const unsigned int NPT_FORMAT_BUFFER_INCREMENT = 4096;
52 const unsigned int NPT_FORMAT_BUFFER_MAX_SIZE = 65536;
53
54 /*----------------------------------------------------------------------
55 | NPT_BytesToInt64Be
56 +---------------------------------------------------------------------*/
57 NPT_UInt64
58 NPT_BytesToInt64Be(const unsigned char* bytes)
59 {
60 return
61 ( ((NPT_UInt64)bytes[0])<<56 ) |
62 ( ((NPT_UInt64)bytes[1])<<48 ) |
63 ( ((NPT_UInt64)bytes[2])<<40 ) |
64 ( ((NPT_UInt64)bytes[3])<<32 ) |
65 ( ((NPT_UInt64)bytes[4])<<24 ) |
66 ( ((NPT_UInt64)bytes[5])<<16 ) |
67 ( ((NPT_UInt64)bytes[6])<<8 ) |
68 ( ((NPT_UInt64)bytes[7]) );
69 }
70
71 /*----------------------------------------------------------------------
72 | NPT_BytesToInt32Be
73 +---------------------------------------------------------------------*/
74 NPT_UInt32
75 NPT_BytesToInt32Be(const unsigned char* bytes)
76 {
77 return
78 ( ((NPT_UInt32)bytes[0])<<24 ) |
79 ( ((NPT_UInt32)bytes[1])<<16 ) |
80 ( ((NPT_UInt32)bytes[2])<<8 ) |
81 ( ((NPT_UInt32)bytes[3]) );
82 }
83
84 /*----------------------------------------------------------------------
85 | NPT_BytesToInt24Be
86 +---------------------------------------------------------------------*/
87 NPT_UInt32
88 NPT_BytesToInt24Be(const unsigned char* bytes)
89 {
90 return
91 ( ((NPT_UInt32)bytes[0])<<16 ) |
92 ( ((NPT_UInt32)bytes[1])<<8 ) |
93 ( ((NPT_UInt32)bytes[2]) );
94 }
95
96 /*----------------------------------------------------------------------
97 | NPT_BytesToInt16Be
98 +---------------------------------------------------------------------*/
99 NPT_UInt16
100 NPT_BytesToInt16Be(const unsigned char* bytes)
101 {
102 return
103 ( ((NPT_UInt16)bytes[0])<<8 ) |
104 ( ((NPT_UInt16)bytes[1]) );
105 }
106
107 /*----------------------------------------------------------------------
108 | NPT_BytesFromInt64Be
109 +---------------------------------------------------------------------*/
110 void
111 NPT_BytesFromInt64Be(unsigned char* buffer, NPT_UInt64 value)
112 {
113 buffer[0] = (unsigned char)(value>>56) & 0xFF;
114 buffer[1] = (unsigned char)(value>>48) & 0xFF;
115 buffer[2] = (unsigned char)(value>>40) & 0xFF;
116 buffer[3] = (unsigned char)(value>>32) & 0xFF;
117 buffer[4] = (unsigned char)(value>>24) & 0xFF;
118 buffer[5] = (unsigned char)(value>>16) & 0xFF;
119 buffer[6] = (unsigned char)(value>> 8) & 0xFF;
120 buffer[7] = (unsigned char)(value ) & 0xFF;
121 }
122
123 /*----------------------------------------------------------------------
124 | NPT_BytesFromInt32Be
125 +---------------------------------------------------------------------*/
126 void
127 NPT_BytesFromInt32Be(unsigned char* buffer, NPT_UInt32 value)
128 {
129 buffer[0] = (unsigned char)(value>>24) & 0xFF;
130 buffer[1] = (unsigned char)(value>>16) & 0xFF;
131 buffer[2] = (unsigned char)(value>> 8) & 0xFF;
132 buffer[3] = (unsigned char)(value ) & 0xFF;
133 }
134
135 /*----------------------------------------------------------------------
136 | NPT_BytesFromInt24Be
137 +---------------------------------------------------------------------*/
138 void
139 NPT_BytesFromInt24Be(unsigned char* buffer, NPT_UInt32 value)
140 {
141 buffer[0] = (unsigned char)(value>>16) & 0xFF;
142 buffer[1] = (unsigned char)(value>> 8) & 0xFF;
143 buffer[2] = (unsigned char)(value ) & 0xFF;
144 }
145
146 /*----------------------------------------------------------------------
147 | NPT_BytesFromInt16Be
148 +---------------------------------------------------------------------*/
149 void
150 NPT_BytesFromInt16Be(unsigned char* buffer, NPT_UInt16 value)
151 {
152 buffer[0] = (unsigned char)((value>> 8) & 0xFF);
153 buffer[1] = (unsigned char)((value ) & 0xFF);
154 }
155
156 #if !defined(NPT_CONFIG_HAVE_SNPRINTF)
157 /*----------------------------------------------------------------------
158 | NPT_FormatString
159 +---------------------------------------------------------------------*/
160 int
161 NPT_FormatString(char* /*str*/, NPT_Size /*size*/, const char* /*format*/, ...)
162 {
163 NPT_ASSERT(0); // not implemented yet
164 return 0;
165 }
166 #endif // NPT_CONFIG_HAVE_SNPRINTF
167
168 /*----------------------------------------------------------------------
169 | NPT_NibbleToHex
170 +---------------------------------------------------------------------*/
171 static char NPT_NibbleToHex(unsigned int nibble, bool uppercase = true)
172 {
173 NPT_ASSERT(nibble < 16);
174 if (uppercase) {
175 return (nibble < 10) ? ('0' + nibble) : ('A' + (nibble-10));
176 } else {
177 return (nibble < 10) ? ('0' + nibble) : ('a' + (nibble-10));
178 }
179 return (nibble < 10) ? ('0' + nibble) : ('A' + (nibble-10));
180 }
181
182 /*----------------------------------------------------------------------
183 | NPT_HexToNibble
184 +---------------------------------------------------------------------*/
185 static int NPT_HexToNibble(char hex)
186 {
187 if (hex >= 'a' && hex <= 'f') {
188 return ((hex - 'a') + 10);
189 } else if (hex >= 'A' && hex <= 'F') {
190 return ((hex - 'A') + 10);
191 } else if (hex >= '0' && hex <= '9') {
192 return (hex - '0');
193 } else {
194 return -1;
195 }
196 }
197
198 /*----------------------------------------------------------------------
199 | NPT_ByteToHex
200 +---------------------------------------------------------------------*/
201 void
202 NPT_ByteToHex(NPT_Byte b, char* buffer, bool uppercase)
203 {
204 buffer[0] = NPT_NibbleToHex((b>>4) & 0x0F, uppercase);
205 buffer[1] = NPT_NibbleToHex(b & 0x0F, uppercase);
206 }
207
208 /*----------------------------------------------------------------------
209 | NPT_HexToByte
210 +---------------------------------------------------------------------*/
211 NPT_Result
212 NPT_HexToByte(const char* buffer, NPT_Byte& b)
213 {
214 int nibble_0 = NPT_HexToNibble(buffer[0]);
215 if (nibble_0 < 0) return NPT_ERROR_INVALID_SYNTAX;
216
217 int nibble_1 = NPT_HexToNibble(buffer[1]);
218 if (nibble_1 < 0) return NPT_ERROR_INVALID_SYNTAX;
219
220 b = (nibble_0 << 4) | nibble_1;
221 return NPT_SUCCESS;
222 }
223
224 /*----------------------------------------------------------------------
225 | NPT_HexString
226 +---------------------------------------------------------------------*/
227 NPT_String
228 NPT_HexString(const unsigned char* data,
229 NPT_Size data_size,
230 const char* separator,
231 bool uppercase)
232 {
233 NPT_String result;
234
235 // quick check
236 if (data == NULL || data_size == 0) return result;
237
238 // set the result size
239 NPT_Size separator_length = separator?NPT_StringLength(separator):0;
240 result.SetLength(data_size*2+(data_size-1)*separator_length);
241
242 // build the string
243 const unsigned char* src = data;
244 char* dst = result.UseChars();
245 while (data_size--) {
246 NPT_ByteToHex(*src++, dst, uppercase);
247 dst += 2;
248 if (data_size) {
249 NPT_CopyMemory(dst, separator, separator_length);
250 dst += separator_length;
251 }
252 }
253
254 return result;
255 }
256
257 /*----------------------------------------------------------------------
258 | NPT_ParseFloat
259 +---------------------------------------------------------------------*/
260 NPT_Result
261 NPT_ParseFloat(const char* str, float& result, bool relaxed)
262 {
263 // safe default value
264 result = 0.0f;
265
266 // check params
267 if (str == NULL || *str == '\0') {
268 return NPT_ERROR_INVALID_PARAMETERS;
269 }
270
271 // ignore leading whitespace
272 if (relaxed) {
273 while (*str == ' ' || *str == '\t') {
274 str++;
275 }
276 }
277 if (*str == '\0') {
278 return NPT_ERROR_INVALID_PARAMETERS;
279 }
280
281 // check for sign
282 bool negative = false;
283 if (*str == '-') {
284 // negative number
285 negative = true;
286 str++;
287 } else if (*str == '+') {
288 // skip the + sign
289 str++;
290 }
291
292 // parse the digits
293 bool after_radix = false;
294 bool empty = true;
295 float value = 0.0f;
296 float decimal = 10.0f;
297 char c;
298 while ((c = *str++)) {
299 if (c == '.') {
300 if (after_radix || (*str < '0' || *str > '9')) {
301 return NPT_ERROR_INVALID_PARAMETERS;
302 } else {
303 after_radix = true;
304 }
305 } else if (c >= '0' && c <= '9') {
306 empty = false;
307 if (after_radix) {
308 value += (float)(c-'0')/decimal;
309 decimal *= 10.0f;
310 } else {
311 value = 10.0f*value + (float)(c-'0');
312 }
313 } else if (c == 'e' || c == 'E') {
314 // exponent
315 if (*str == '+' || *str == '-' || (*str >= '0' && *str <= '9')) {
316 int exponent = 0;
317 if (NPT_SUCCEEDED(NPT_ParseInteger(str, exponent, relaxed))) {
318 value *= (float)pow(10.0f, (float)exponent);
319 break;
320 } else {
321 return NPT_ERROR_INVALID_PARAMETERS;
322 }
323 } else {
324 return NPT_ERROR_INVALID_PARAMETERS;
325 }
326 } else {
327 if (relaxed) {
328 break;
329 } else {
330 return NPT_ERROR_INVALID_PARAMETERS;
331 }
332 }
333 }
334
335 // check that the value was non empty
336 if (empty) {
337 return NPT_ERROR_INVALID_PARAMETERS;
338 }
339
340 // return the result
341 result = negative ? -value : value;
342 return NPT_SUCCESS;
343 }
344
345 /*----------------------------------------------------------------------
346 | NPT_ParseInteger64
347 +---------------------------------------------------------------------*/
348 NPT_Result
349 NPT_ParseInteger64(const char* str, NPT_Int64& result, bool relaxed, NPT_Cardinal* chars_used)
350 {
351 // safe default value
352 result = 0;
353 if (chars_used) *chars_used = 0;
354
355 if (str == NULL) {
356 return NPT_ERROR_INVALID_PARAMETERS;
357 }
358
359 // ignore leading whitespace
360 if (relaxed) {
361 while (*str == ' ' || *str == '\t') {
362 str++;
363 if (chars_used) (*chars_used)++;
364 }
365 }
366 if (*str == '\0') {
367 return NPT_ERROR_INVALID_PARAMETERS;
368 }
369
370 // check for sign
371 bool negative = false;
372 if (*str == '-') {
373 // negative number
374 negative = true;
375 str++;
376 if (chars_used) (*chars_used)++;
377 } else if (*str == '+') {
378 // skip the + sign
379 str++;
380 if (chars_used) (*chars_used)++;
381 }
382
383 // check for overflows
384 NPT_Int64 max = NPT_INT64_MAX/10;
385
386 // adjust the max for overflows when the value is negative
387 if (negative && ((NPT_INT64_MAX%10) == 9)) ++max;
388
389 // parse the digits
390 bool empty = true;
391 NPT_Int64 value = 0;
392 char c;
393 while ((c = *str++)) {
394 if (c >= '0' && c <= '9') {
395 if (value < 0 || value > max) return NPT_ERROR_OVERFLOW;
396 value = 10*value + (c-'0');
397 if (value < 0 && (!negative || value != NPT_INT64_MIN)) return NPT_ERROR_OVERFLOW;
398 empty = false;
399 if (chars_used) (*chars_used)++;
400 } else {
401 if (relaxed) {
402 break;
403 } else {
404 return NPT_ERROR_INVALID_PARAMETERS;
405 }
406 }
407 }
408
409 // check that the value was non empty
410 if (empty) {
411 return NPT_ERROR_INVALID_PARAMETERS;
412 }
413
414 // return the result
415 result = negative ? -value : value;
416 return NPT_SUCCESS;
417 }
418
419 /*----------------------------------------------------------------------
420 | NPT_ParseInteger64U
421 +---------------------------------------------------------------------*/
422 NPT_Result
423 NPT_ParseInteger64U(const char* str, NPT_UInt64& result, bool relaxed, NPT_Cardinal* chars_used)
424 {
425 // safe default value
426 result = 0;
427 if (chars_used) *chars_used = 0;
428
429 if (str == NULL) {
430 return NPT_ERROR_INVALID_PARAMETERS;
431 }
432
433 // ignore leading whitespace
434 if (relaxed) {
435 while (*str == ' ' || *str == '\t') {
436 str++;
437 if (chars_used) (*chars_used)++;
438 }
439 }
440 if (*str == '\0') {
441 return NPT_ERROR_INVALID_PARAMETERS;
442 }
443
444 // parse the digits
445 bool empty = true;
446 NPT_UInt64 value = 0;
447 char c;
448 while ((c = *str++)) {
449 if (c >= '0' && c <= '9') {
450 NPT_UInt64 new_value;
451 if (value > NPT_UINT64_MAX/10) return NPT_ERROR_OVERFLOW;
452 new_value = 10*value + (c-'0');
453 if (new_value < value) return NPT_ERROR_OVERFLOW;
454 value = new_value;
455 empty = false;
456 if (chars_used) (*chars_used)++;
457 } else {
458 if (relaxed) {
459 break;
460 } else {
461 return NPT_ERROR_INVALID_PARAMETERS;
462 }
463 }
464 }
465
466 // check that the value was non empty
467 if (empty) {
468 return NPT_ERROR_INVALID_PARAMETERS;
469 }
470
471 // return the result
472 result = value;
473 return NPT_SUCCESS;
474 }
475
476 /*----------------------------------------------------------------------
477 | NPT_ParseInteger32
478 +---------------------------------------------------------------------*/
479 NPT_Result
480 NPT_ParseInteger32(const char* str, NPT_Int32& value, bool relaxed, NPT_Cardinal* chars_used)
481 {
482 NPT_Int64 value_64;
483 NPT_Result result = NPT_ParseInteger64(str, value_64, relaxed, chars_used);
484 value = 0;
485 if (NPT_SUCCEEDED(result)) {
486 if (value_64 < NPT_INT32_MIN || value_64 > NPT_INT32_MAX) {
487 return NPT_ERROR_OVERFLOW;
488 }
489 value = (NPT_Int32)value_64;
490 }
491 return result;
492 }
493
494 /*----------------------------------------------------------------------
495 | NPT_ParseInteger32U
496 +---------------------------------------------------------------------*/
497 NPT_Result
498 NPT_ParseInteger32U(const char* str, NPT_UInt32& value, bool relaxed, NPT_Cardinal* chars_used)
499 {
500 NPT_UInt64 value_64;
501 NPT_Result result = NPT_ParseInteger64U(str, value_64, relaxed, chars_used);
502 value = 0;
503 if (NPT_SUCCEEDED(result)) {
504 if (value_64 > (NPT_UInt64)NPT_UINT32_MAX) return NPT_ERROR_OVERFLOW;
505 value = (NPT_UInt32)value_64;
506 }
507 return result;
508 }
509
510 /*----------------------------------------------------------------------
511 | NPT_ParseInteger
512 +---------------------------------------------------------------------*/
513 NPT_Result
514 NPT_ParseInteger(const char* str, int& value, bool relaxed, NPT_Cardinal* chars_used)
515 {
516 NPT_Int64 value_64;
517 NPT_Result result = NPT_ParseInteger64(str, value_64, relaxed, chars_used);
518 value = 0;
519 if (NPT_SUCCEEDED(result)) {
520 if (value_64 < NPT_INT_MIN || value_64 > NPT_INT_MAX) {
521 return NPT_ERROR_OVERFLOW;
522 }
523 value = (int)value_64;
524 }
525 return result;
526 }
527
528
529 #if !defined(NPT_CONFIG_HAVE_STRCPY)
530 /*----------------------------------------------------------------------
531 | NPT_CopyString
532 +---------------------------------------------------------------------*/
533 void
534 NPT_CopyString(char* dst, const char* src)
535 {
536 while(*dst++ = *src++);
537 }
538 #endif
539
540 /*----------------------------------------------------------------------
541 | NPT_FormatOutput
542 +---------------------------------------------------------------------*/
543 void
544 NPT_FormatOutput(void (*function)(void* parameter, const char* message),
545 void* function_parameter,
546 const char* format,
547 va_list args)
548 {
549 char local_buffer[NPT_FORMAT_LOCAL_BUFFER_SIZE];
550 unsigned int buffer_size = NPT_FORMAT_LOCAL_BUFFER_SIZE;
551 char* buffer = local_buffer;
552
553 for(;;) {
554 int result;
555
556 /* try to format the message (it might not fit) */
557 result = NPT_FormatStringVN(buffer, buffer_size-1, format, args);
558 buffer[buffer_size-1] = 0; /* force a NULL termination */
559 if (result >= 0) break;
560
561 /* the buffer was too small, try something bigger */
562 buffer_size = (buffer_size+NPT_FORMAT_BUFFER_INCREMENT)*2;
563 if (buffer_size > NPT_FORMAT_BUFFER_MAX_SIZE) break;
564 if (buffer != local_buffer) delete[] buffer;
565 buffer = new char[buffer_size];
566 if (buffer == NULL) return;
567 }
568
569 (*function)(function_parameter, buffer);
570 if (buffer != local_buffer) delete[] buffer;
571 }
572
573 /*----------------------------------------------------------------------
574 | local types
575 +---------------------------------------------------------------------*/
576 typedef enum {
577 NPT_MIME_PARAMETER_PARSER_STATE_NEED_NAME,
578 NPT_MIME_PARAMETER_PARSER_STATE_IN_NAME,
579 NPT_MIME_PARAMETER_PARSER_STATE_NEED_EQUALS,
580 NPT_MIME_PARAMETER_PARSER_STATE_NEED_VALUE,
581 NPT_MIME_PARAMETER_PARSER_STATE_IN_VALUE,
582 NPT_MIME_PARAMETER_PARSER_STATE_IN_QUOTED_VALUE,
583 NPT_MIME_PARAMETER_PARSER_STATE_NEED_SEPARATOR
584 } NPT_MimeParameterParserState;
585
586 /*----------------------------------------------------------------------
587 | NPT_ParseMimeParameters
588 |
589 | From RFC 822 and RFC 2045
590 |
591 | ; ( Octal, Decimal.)
592 | CHAR = <any ASCII character> ; ( 0-177, 0.-127.)
593 | ALPHA = <any ASCII alphabetic character>
594 | ; (101-132, 65.- 90.)
595 | ; (141-172, 97.-122.)
596 | DIGIT = <any ASCII decimal digit> ; ( 60- 71, 48.- 57.)
597 | CTL = <any ASCII control ; ( 0- 37, 0.- 31.)
598 | character and DEL> ; ( 177, 127.)
599 | CR = <ASCII CR, carriage return> ; ( 15, 13.)
600 | LF = <ASCII LF, linefeed> ; ( 12, 10.)
601 | SPACE = <ASCII SP, space> ; ( 40, 32.)
602 | HTAB = <ASCII HT, horizontal-tab> ; ( 11, 9.)
603 | <"> = <ASCII quote mark> ; ( 42, 34.)
604 | CRLF = CR LF
605 |
606 | LWSP-char = SPACE / HTAB ; semantics = SPACE
607 |
608 | linear-white-space = 1*([CRLF] LWSP-char) ; semantics = SPACE
609 | ; CRLF => folding
610 |
611 | parameter := attribute "=" value
612 |
613 | attribute := token
614 | ; Matching of attributes
615 | ; is ALWAYS case-insensitive.
616 |
617 | value := token / quoted-string
618 |
619 | token := 1*<any (US-ASCII) CHAR except SPACE, CTLs, or tspecials>
620 |
621 | tspecials := "(" / ")" / "<" / ">" / "@" /
622 | "," / ";" / ":" / "\" / <">
623 | "/" / "[" / "]" / "?" / "="
624 |
625 | quoted-string = <"> *(qtext/quoted-pair) <">; Regular qtext or
626 | ; quoted chars.
627 |
628 | qtext = <any CHAR excepting <">, ; => may be folded
629 | "\" & CR, and including
630 | linear-white-space>
631 |
632 | quoted-pair = "\" CHAR ; may quote any char
633 |
634 +---------------------------------------------------------------------*/
635 NPT_Result
636 NPT_ParseMimeParameters(const char* encoded,
637 NPT_Map<NPT_String, NPT_String>& parameters)
638 {
639 // check parameters
640 if (encoded == NULL) return NPT_ERROR_INVALID_PARAMETERS;
641
642 // reserve some space
643 NPT_String param_name;
644 NPT_String param_value;
645 param_name.Reserve(64);
646 param_value.Reserve(64);
647
648 NPT_MimeParameterParserState state = NPT_MIME_PARAMETER_PARSER_STATE_NEED_NAME;
649 bool quoted_char = false;
650 for (;;) {
651 char c = *encoded++;
652 if (!quoted_char && (c == 0x0A || c == 0x0D)) continue; // ignore EOL chars
653 switch (state) {
654 case NPT_MIME_PARAMETER_PARSER_STATE_NEED_NAME:
655 if (c == '\0') break; // END
656 if (c == ' ' || c == '\t') continue; // ignore leading whitespace
657 if (c < ' ') return NPT_ERROR_INVALID_SYNTAX; // CTLs are invalid
658 param_name += c; // we're not strict: accept all other chars
659 state = NPT_MIME_PARAMETER_PARSER_STATE_IN_NAME;
660 break;
661
662 case NPT_MIME_PARAMETER_PARSER_STATE_IN_NAME:
663 if (c < ' ') return NPT_ERROR_INVALID_SYNTAX; // END or CTLs are invalid
664 if (c == ' ') {
665 state = NPT_MIME_PARAMETER_PARSER_STATE_NEED_EQUALS;
666 } else if (c == '=') {
667 state = NPT_MIME_PARAMETER_PARSER_STATE_NEED_VALUE;
668 } else {
669 param_name += c; // we're not strict: accept all other chars
670 }
671 break;
672
673 case NPT_MIME_PARAMETER_PARSER_STATE_NEED_EQUALS:
674 if (c < ' ') return NPT_ERROR_INVALID_SYNTAX; // END or CTLs are invalid
675 if (c == ' ' || c == '\t') continue; // ignore leading whitespace
676 if (c != '=') return NPT_ERROR_INVALID_SYNTAX;
677 state = NPT_MIME_PARAMETER_PARSER_STATE_NEED_VALUE;
678 break;
679
680 case NPT_MIME_PARAMETER_PARSER_STATE_NEED_VALUE:
681 if (c < ' ') return NPT_ERROR_INVALID_SYNTAX; // END or CTLs are invalid
682 if (c == ' ' || c == '\t') continue; // ignore leading whitespace
683 if (c == '"') {
684 state = NPT_MIME_PARAMETER_PARSER_STATE_IN_QUOTED_VALUE;
685 } else {
686 param_value += c; // we're not strict: accept all other chars
687 state = NPT_MIME_PARAMETER_PARSER_STATE_IN_VALUE;
688 }
689 break;
690
691 case NPT_MIME_PARAMETER_PARSER_STATE_IN_QUOTED_VALUE:
692 if (quoted_char) {
693 quoted_char = false;
694 if (c == '\0') return NPT_ERROR_INVALID_SYNTAX;
695 param_value += c; // accept all chars
696 break;
697 } else if (c == '\\') {
698 quoted_char = true;
699 break;
700 } else if (c == '"') {
701 // add the parameter to the map
702 param_name.TrimRight();
703 param_value.TrimRight();
704 parameters[param_name] = param_value;
705 param_name.SetLength(0);
706 param_value.SetLength(0);
707 state = NPT_MIME_PARAMETER_PARSER_STATE_NEED_SEPARATOR;
708 } else if (c < ' ') {
709 return NPT_ERROR_INVALID_SYNTAX; // END or CTLs are invalid
710 } else {
711 param_value += c; // we're not strict: accept all other chars
712 }
713 break;
714
715 case NPT_MIME_PARAMETER_PARSER_STATE_IN_VALUE:
716 if (c == '\0' || c == ';') {
717 // add the parameter to the map
718 param_name.TrimRight();
719 param_value.TrimRight();
720 parameters[param_name] = param_value;
721 param_name.SetLength(0);
722 param_value.SetLength(0);
723 state = NPT_MIME_PARAMETER_PARSER_STATE_NEED_NAME;
724 } else if (c < ' ') {
725 // CTLs are invalid
726 return NPT_ERROR_INVALID_SYNTAX;
727 } else {
728 param_value += c; // we're not strict: accept all other chars
729 }
730 break;
731
732 case NPT_MIME_PARAMETER_PARSER_STATE_NEED_SEPARATOR:
733 if (c == '\0') break;
734 if (c < ' ') return NPT_ERROR_INVALID_SYNTAX; // CTLs are invalid
735 if (c == ' ' || c == '\t') continue; // ignore whitespace
736 if (c != ';') return NPT_ERROR_INVALID_SYNTAX;
737 state = NPT_MIME_PARAMETER_PARSER_STATE_NEED_NAME;
738 break;
739 }
740 if (c == '\0') break; // end of buffer
741 }
742
743 return NPT_SUCCESS;
744 }
745