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