Mercurial > projects > hoofbaby
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 |