mhd_str.c (65768B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2015-2024 Karlson2k (Evgeny Grin) 4 5 This library 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 This library 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_str.h" 27 28 #ifdef HAVE_STDBOOL_H 29 #include <stdbool.h> 30 #endif /* HAVE_STDBOOL_H */ 31 #include <string.h> 32 33 #include "mhd_assert.h" 34 #include "mhd_limits.h" 35 #include "mhd_assert.h" 36 37 #ifdef MHD_FAVOR_SMALL_CODE 38 #ifdef _MHD_static_inline 39 #undef _MHD_static_inline 40 #endif /* _MHD_static_inline */ 41 /* Do not force inlining and do not use macro functions, use normal static 42 functions instead. 43 This may give more flexibility for size optimizations. */ 44 #define _MHD_static_inline static 45 #ifndef HAVE_INLINE_FUNCS 46 #define HAVE_INLINE_FUNCS 1 47 #endif /* !INLINE_FUNC */ 48 #endif /* MHD_FAVOR_SMALL_CODE */ 49 50 /* 51 * Block of functions/macros that use US-ASCII charset as required by HTTP 52 * standards. Not affected by current locale settings. 53 */ 54 55 #ifdef HAVE_INLINE_FUNCS 56 57 #if 0 /* Disable unused functions. */ 58 /** 59 * Check whether character is lower case letter in US-ASCII 60 * 61 * @param c character to check 62 * @return non-zero if character is lower case letter, zero otherwise 63 */ 64 _MHD_static_inline bool 65 isasciilower (char c) 66 { 67 return (c >= 'a') && (c <= 'z'); 68 } 69 70 71 #endif /* Disable unused functions. */ 72 73 74 /** 75 * Check whether character is upper case letter in US-ASCII 76 * 77 * @param c character to check 78 * @return non-zero if character is upper case letter, zero otherwise 79 */ 80 _MHD_static_inline bool 81 isasciiupper (char c) 82 { 83 return (c >= 'A') && (c <= 'Z'); 84 } 85 86 87 #if 0 /* Disable unused functions. */ 88 /** 89 * Check whether character is letter in US-ASCII 90 * 91 * @param c character to check 92 * @return non-zero if character is letter in US-ASCII, zero otherwise 93 */ 94 _MHD_static_inline bool 95 isasciialpha (char c) 96 { 97 return isasciilower (c) || isasciiupper (c); 98 } 99 100 101 #endif /* Disable unused functions. */ 102 103 104 /** 105 * Check whether character is decimal digit in US-ASCII 106 * 107 * @param c character to check 108 * @return non-zero if character is decimal digit, zero otherwise 109 */ 110 _MHD_static_inline bool 111 isasciidigit (char c) 112 { 113 return (c >= '0') && (c <= '9'); 114 } 115 116 117 #if 0 /* Disable unused functions. */ 118 /** 119 * Check whether character is hexadecimal digit in US-ASCII 120 * 121 * @param c character to check 122 * @return non-zero if character is decimal digit, zero otherwise 123 */ 124 _MHD_static_inline bool 125 isasciixdigit (char c) 126 { 127 return isasciidigit (c) || 128 ( (c >= 'A') && (c <= 'F') ) || 129 ( (c >= 'a') && (c <= 'f') ); 130 } 131 132 133 /** 134 * Check whether character is decimal digit or letter in US-ASCII 135 * 136 * @param c character to check 137 * @return non-zero if character is decimal digit or letter, zero otherwise 138 */ 139 _MHD_static_inline bool 140 isasciialnum (char c) 141 { 142 return isasciialpha (c) || isasciidigit (c); 143 } 144 145 146 #endif /* Disable unused functions. */ 147 148 149 #if 0 /* Disable unused functions. */ 150 /** 151 * Convert US-ASCII character to lower case. 152 * If character is upper case letter in US-ASCII than it's converted to lower 153 * case analog. If character is NOT upper case letter than it's returned 154 * unmodified. 155 * 156 * @param c character to convert 157 * @return converted to lower case character 158 */ 159 _MHD_static_inline char 160 toasciilower (char c) 161 { 162 return isasciiupper (c) ? (c - 'A' + 'a') : c; 163 } 164 165 166 /** 167 * Convert US-ASCII character to upper case. 168 * If character is lower case letter in US-ASCII than it's converted to upper 169 * case analog. If character is NOT lower case letter than it's returned 170 * unmodified. 171 * 172 * @param c character to convert 173 * @return converted to upper case character 174 */ 175 _MHD_static_inline char 176 toasciiupper (char c) 177 { 178 return isasciilower (c) ? (c - 'a' + 'A') : c; 179 } 180 181 182 #endif /* Disable unused functions. */ 183 184 185 #if defined(MHD_FAVOR_SMALL_CODE) /* Used only in MHD_str_to_uvalue_n_() */ 186 /** 187 * Convert US-ASCII decimal digit to its value. 188 * 189 * @param c character to convert 190 * @return value of decimal digit or -1 if @ c is not decimal digit 191 */ 192 _MHD_static_inline int 193 todigitvalue (char c) 194 { 195 if (isasciidigit (c)) 196 return (unsigned char) (c - '0'); 197 198 return -1; 199 } 200 201 202 #endif /* MHD_FAVOR_SMALL_CODE */ 203 204 205 /** 206 * Convert US-ASCII hexadecimal digit to its value. 207 * 208 * @param c character to convert 209 * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit 210 */ 211 _MHD_static_inline int 212 toxdigitvalue (char c) 213 { 214 #if ! defined(MHD_FAVOR_SMALL_CODE) 215 switch ((unsigned char) c) 216 { 217 #if 0 /* Disabled to give the compiler a hint about low probability */ 218 case 0x00U: /* NUL */ 219 case 0x01U: /* SOH */ 220 case 0x02U: /* STX */ 221 case 0x03U: /* ETX */ 222 case 0x04U: /* EOT */ 223 case 0x05U: /* ENQ */ 224 case 0x06U: /* ACK */ 225 case 0x07U: /* BEL */ 226 case 0x08U: /* BS */ 227 case 0x09U: /* HT */ 228 case 0x0AU: /* LF */ 229 case 0x0BU: /* VT */ 230 case 0x0CU: /* FF */ 231 case 0x0DU: /* CR */ 232 case 0x0EU: /* SO */ 233 case 0x0FU: /* SI */ 234 case 0x10U: /* DLE */ 235 case 0x11U: /* DC1 */ 236 case 0x12U: /* DC2 */ 237 case 0x13U: /* DC3 */ 238 case 0x14U: /* DC4 */ 239 case 0x15U: /* NAK */ 240 case 0x16U: /* SYN */ 241 case 0x17U: /* ETB */ 242 case 0x18U: /* CAN */ 243 case 0x19U: /* EM */ 244 case 0x1AU: /* SUB */ 245 case 0x1BU: /* ESC */ 246 case 0x1CU: /* FS */ 247 case 0x1DU: /* GS */ 248 case 0x1EU: /* RS */ 249 case 0x1FU: /* US */ 250 case 0x20U: /* ' ' */ 251 case 0x21U: /* '!' */ 252 case 0x22U: /* '"' */ 253 case 0x23U: /* '#' */ 254 case 0x24U: /* '$' */ 255 case 0x25U: /* '%' */ 256 case 0x26U: /* '&' */ 257 case 0x27U: /* '\'' */ 258 case 0x28U: /* '(' */ 259 case 0x29U: /* ')' */ 260 case 0x2AU: /* '*' */ 261 case 0x2BU: /* '+' */ 262 case 0x2CU: /* ',' */ 263 case 0x2DU: /* '-' */ 264 case 0x2EU: /* '.' */ 265 case 0x2FU: /* '/' */ 266 return -1; 267 #endif 268 case 0x30U: /* '0' */ 269 return 0; 270 case 0x31U: /* '1' */ 271 return 1; 272 case 0x32U: /* '2' */ 273 return 2; 274 case 0x33U: /* '3' */ 275 return 3; 276 case 0x34U: /* '4' */ 277 return 4; 278 case 0x35U: /* '5' */ 279 return 5; 280 case 0x36U: /* '6' */ 281 return 6; 282 case 0x37U: /* '7' */ 283 return 7; 284 case 0x38U: /* '8' */ 285 return 8; 286 case 0x39U: /* '9' */ 287 return 9; 288 #if 0 /* Disabled to give the compiler a hint about low probability */ 289 case 0x3AU: /* ':' */ 290 case 0x3BU: /* ';' */ 291 case 0x3CU: /* '<' */ 292 case 0x3DU: /* '=' */ 293 case 0x3EU: /* '>' */ 294 case 0x3FU: /* '?' */ 295 case 0x40U: /* '@' */ 296 return -1; 297 #endif 298 case 0x41U: /* 'A' */ 299 return 0xAU; 300 case 0x42U: /* 'B' */ 301 return 0xBU; 302 case 0x43U: /* 'C' */ 303 return 0xCU; 304 case 0x44U: /* 'D' */ 305 return 0xDU; 306 case 0x45U: /* 'E' */ 307 return 0xEU; 308 case 0x46U: /* 'F' */ 309 return 0xFU; 310 #if 0 /* Disabled to give the compiler a hint about low probability */ 311 case 0x47U: /* 'G' */ 312 case 0x48U: /* 'H' */ 313 case 0x49U: /* 'I' */ 314 case 0x4AU: /* 'J' */ 315 case 0x4BU: /* 'K' */ 316 case 0x4CU: /* 'L' */ 317 case 0x4DU: /* 'M' */ 318 case 0x4EU: /* 'N' */ 319 case 0x4FU: /* 'O' */ 320 case 0x50U: /* 'P' */ 321 case 0x51U: /* 'Q' */ 322 case 0x52U: /* 'R' */ 323 case 0x53U: /* 'S' */ 324 case 0x54U: /* 'T' */ 325 case 0x55U: /* 'U' */ 326 case 0x56U: /* 'V' */ 327 case 0x57U: /* 'W' */ 328 case 0x58U: /* 'X' */ 329 case 0x59U: /* 'Y' */ 330 case 0x5AU: /* 'Z' */ 331 case 0x5BU: /* '[' */ 332 case 0x5CU: /* '\' */ 333 case 0x5DU: /* ']' */ 334 case 0x5EU: /* '^' */ 335 case 0x5FU: /* '_' */ 336 case 0x60U: /* '`' */ 337 return -1; 338 #endif 339 case 0x61U: /* 'a' */ 340 return 0xAU; 341 case 0x62U: /* 'b' */ 342 return 0xBU; 343 case 0x63U: /* 'c' */ 344 return 0xCU; 345 case 0x64U: /* 'd' */ 346 return 0xDU; 347 case 0x65U: /* 'e' */ 348 return 0xEU; 349 case 0x66U: /* 'f' */ 350 return 0xFU; 351 #if 0 /* Disabled to give the compiler a hint about low probability */ 352 case 0x67U: /* 'g' */ 353 case 0x68U: /* 'h' */ 354 case 0x69U: /* 'i' */ 355 case 0x6AU: /* 'j' */ 356 case 0x6BU: /* 'k' */ 357 case 0x6CU: /* 'l' */ 358 case 0x6DU: /* 'm' */ 359 case 0x6EU: /* 'n' */ 360 case 0x6FU: /* 'o' */ 361 case 0x70U: /* 'p' */ 362 case 0x71U: /* 'q' */ 363 case 0x72U: /* 'r' */ 364 case 0x73U: /* 's' */ 365 case 0x74U: /* 't' */ 366 case 0x75U: /* 'u' */ 367 case 0x76U: /* 'v' */ 368 case 0x77U: /* 'w' */ 369 case 0x78U: /* 'x' */ 370 case 0x79U: /* 'y' */ 371 case 0x7AU: /* 'z' */ 372 case 0x7BU: /* '{' */ 373 case 0x7CU: /* '|' */ 374 case 0x7DU: /* '}' */ 375 case 0x7EU: /* '~' */ 376 case 0x7FU: /* DEL */ 377 case 0x80U: /* EXT */ 378 case 0x81U: /* EXT */ 379 case 0x82U: /* EXT */ 380 case 0x83U: /* EXT */ 381 case 0x84U: /* EXT */ 382 case 0x85U: /* EXT */ 383 case 0x86U: /* EXT */ 384 case 0x87U: /* EXT */ 385 case 0x88U: /* EXT */ 386 case 0x89U: /* EXT */ 387 case 0x8AU: /* EXT */ 388 case 0x8BU: /* EXT */ 389 case 0x8CU: /* EXT */ 390 case 0x8DU: /* EXT */ 391 case 0x8EU: /* EXT */ 392 case 0x8FU: /* EXT */ 393 case 0x90U: /* EXT */ 394 case 0x91U: /* EXT */ 395 case 0x92U: /* EXT */ 396 case 0x93U: /* EXT */ 397 case 0x94U: /* EXT */ 398 case 0x95U: /* EXT */ 399 case 0x96U: /* EXT */ 400 case 0x97U: /* EXT */ 401 case 0x98U: /* EXT */ 402 case 0x99U: /* EXT */ 403 case 0x9AU: /* EXT */ 404 case 0x9BU: /* EXT */ 405 case 0x9CU: /* EXT */ 406 case 0x9DU: /* EXT */ 407 case 0x9EU: /* EXT */ 408 case 0x9FU: /* EXT */ 409 case 0xA0U: /* EXT */ 410 case 0xA1U: /* EXT */ 411 case 0xA2U: /* EXT */ 412 case 0xA3U: /* EXT */ 413 case 0xA4U: /* EXT */ 414 case 0xA5U: /* EXT */ 415 case 0xA6U: /* EXT */ 416 case 0xA7U: /* EXT */ 417 case 0xA8U: /* EXT */ 418 case 0xA9U: /* EXT */ 419 case 0xAAU: /* EXT */ 420 case 0xABU: /* EXT */ 421 case 0xACU: /* EXT */ 422 case 0xADU: /* EXT */ 423 case 0xAEU: /* EXT */ 424 case 0xAFU: /* EXT */ 425 case 0xB0U: /* EXT */ 426 case 0xB1U: /* EXT */ 427 case 0xB2U: /* EXT */ 428 case 0xB3U: /* EXT */ 429 case 0xB4U: /* EXT */ 430 case 0xB5U: /* EXT */ 431 case 0xB6U: /* EXT */ 432 case 0xB7U: /* EXT */ 433 case 0xB8U: /* EXT */ 434 case 0xB9U: /* EXT */ 435 case 0xBAU: /* EXT */ 436 case 0xBBU: /* EXT */ 437 case 0xBCU: /* EXT */ 438 case 0xBDU: /* EXT */ 439 case 0xBEU: /* EXT */ 440 case 0xBFU: /* EXT */ 441 case 0xC0U: /* EXT */ 442 case 0xC1U: /* EXT */ 443 case 0xC2U: /* EXT */ 444 case 0xC3U: /* EXT */ 445 case 0xC4U: /* EXT */ 446 case 0xC5U: /* EXT */ 447 case 0xC6U: /* EXT */ 448 case 0xC7U: /* EXT */ 449 case 0xC8U: /* EXT */ 450 case 0xC9U: /* EXT */ 451 case 0xCAU: /* EXT */ 452 case 0xCBU: /* EXT */ 453 case 0xCCU: /* EXT */ 454 case 0xCDU: /* EXT */ 455 case 0xCEU: /* EXT */ 456 case 0xCFU: /* EXT */ 457 case 0xD0U: /* EXT */ 458 case 0xD1U: /* EXT */ 459 case 0xD2U: /* EXT */ 460 case 0xD3U: /* EXT */ 461 case 0xD4U: /* EXT */ 462 case 0xD5U: /* EXT */ 463 case 0xD6U: /* EXT */ 464 case 0xD7U: /* EXT */ 465 case 0xD8U: /* EXT */ 466 case 0xD9U: /* EXT */ 467 case 0xDAU: /* EXT */ 468 case 0xDBU: /* EXT */ 469 case 0xDCU: /* EXT */ 470 case 0xDDU: /* EXT */ 471 case 0xDEU: /* EXT */ 472 case 0xDFU: /* EXT */ 473 case 0xE0U: /* EXT */ 474 case 0xE1U: /* EXT */ 475 case 0xE2U: /* EXT */ 476 case 0xE3U: /* EXT */ 477 case 0xE4U: /* EXT */ 478 case 0xE5U: /* EXT */ 479 case 0xE6U: /* EXT */ 480 case 0xE7U: /* EXT */ 481 case 0xE8U: /* EXT */ 482 case 0xE9U: /* EXT */ 483 case 0xEAU: /* EXT */ 484 case 0xEBU: /* EXT */ 485 case 0xECU: /* EXT */ 486 case 0xEDU: /* EXT */ 487 case 0xEEU: /* EXT */ 488 case 0xEFU: /* EXT */ 489 case 0xF0U: /* EXT */ 490 case 0xF1U: /* EXT */ 491 case 0xF2U: /* EXT */ 492 case 0xF3U: /* EXT */ 493 case 0xF4U: /* EXT */ 494 case 0xF5U: /* EXT */ 495 case 0xF6U: /* EXT */ 496 case 0xF7U: /* EXT */ 497 case 0xF8U: /* EXT */ 498 case 0xF9U: /* EXT */ 499 case 0xFAU: /* EXT */ 500 case 0xFBU: /* EXT */ 501 case 0xFCU: /* EXT */ 502 case 0xFDU: /* EXT */ 503 case 0xFEU: /* EXT */ 504 case 0xFFU: /* EXT */ 505 return -1; 506 default: 507 mhd_assert (0); 508 break; /* Should be unreachable */ 509 #else 510 default: 511 break; 512 #endif 513 } 514 return -1; 515 #else /* MHD_FAVOR_SMALL_CODE */ 516 if (isasciidigit (c)) 517 return (unsigned char) (c - '0'); 518 if ( (c >= 'A') && (c <= 'F') ) 519 return (unsigned char) (c - 'A' + 10); 520 if ( (c >= 'a') && (c <= 'f') ) 521 return (unsigned char) (c - 'a' + 10); 522 523 return -1; 524 #endif /* MHD_FAVOR_SMALL_CODE */ 525 } 526 527 528 /** 529 * Caseless compare two characters. 530 * 531 * @param c1 the first char to compare 532 * @param c2 the second char to compare 533 * @return boolean 'true' if chars are caseless equal, false otherwise 534 */ 535 _MHD_static_inline bool 536 charsequalcaseless (const char c1, const char c2) 537 { 538 return ( (c1 == c2) || 539 (isasciiupper (c1) ? 540 ((c1 - 'A' + 'a') == c2) : 541 ((c1 == (c2 - 'A' + 'a')) && isasciiupper (c2))) ); 542 } 543 544 545 #else /* !INLINE_FUNC */ 546 547 548 /** 549 * Checks whether character is lower case letter in US-ASCII 550 * 551 * @param c character to check 552 * @return boolean true if character is lower case letter, 553 * boolean false otherwise 554 */ 555 #define isasciilower(c) (((char) (c)) >= 'a' && ((char) (c)) <= 'z') 556 557 558 /** 559 * Checks whether character is upper case letter in US-ASCII 560 * 561 * @param c character to check 562 * @return boolean true if character is upper case letter, 563 * boolean false otherwise 564 */ 565 #define isasciiupper(c) (((char) (c)) >= 'A' && ((char) (c)) <= 'Z') 566 567 568 /** 569 * Checks whether character is letter in US-ASCII 570 * 571 * @param c character to check 572 * @return boolean true if character is letter, boolean false 573 * otherwise 574 */ 575 #define isasciialpha(c) (isasciilower (c) || isasciiupper (c)) 576 577 578 /** 579 * Check whether character is decimal digit in US-ASCII 580 * 581 * @param c character to check 582 * @return boolean true if character is decimal digit, boolean false 583 * otherwise 584 */ 585 #define isasciidigit(c) (((char) (c)) >= '0' && ((char) (c)) <= '9') 586 587 588 /** 589 * Check whether character is hexadecimal digit in US-ASCII 590 * 591 * @param c character to check 592 * @return boolean true if character is hexadecimal digit, 593 * boolean false otherwise 594 */ 595 #define isasciixdigit(c) (isasciidigit ((c)) || \ 596 (((char) (c)) >= 'A' && ((char) (c)) <= 'F') || \ 597 (((char) (c)) >= 'a' && ((char) (c)) <= 'f') ) 598 599 600 /** 601 * Check whether character is decimal digit or letter in US-ASCII 602 * 603 * @param c character to check 604 * @return boolean true if character is decimal digit or letter, 605 * boolean false otherwise 606 */ 607 #define isasciialnum(c) (isasciialpha (c) || isasciidigit (c)) 608 609 610 /** 611 * Convert US-ASCII character to lower case. 612 * If character is upper case letter in US-ASCII than it's converted to lower 613 * case analog. If character is NOT upper case letter than it's returned 614 * unmodified. 615 * 616 * @param c character to convert 617 * @return converted to lower case character 618 */ 619 #define toasciilower(c) ((isasciiupper (c)) ? (((char) (c)) - 'A' + 'a') : \ 620 ((char) (c))) 621 622 623 /** 624 * Convert US-ASCII character to upper case. 625 * If character is lower case letter in US-ASCII than it's converted to upper 626 * case analog. If character is NOT lower case letter than it's returned 627 * unmodified. 628 * 629 * @param c character to convert 630 * @return converted to upper case character 631 */ 632 #define toasciiupper(c) ((isasciilower (c)) ? (((char) (c)) - 'a' + 'A') : \ 633 ((char) (c))) 634 635 636 /** 637 * Convert US-ASCII decimal digit to its value. 638 * 639 * @param c character to convert 640 * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit 641 */ 642 #define todigitvalue(c) (isasciidigit (c) ? (int) (((char) (c)) - '0') : \ 643 (int) (-1)) 644 645 646 /** 647 * Convert US-ASCII hexadecimal digit to its value. 648 * @param c character to convert 649 * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit 650 */ 651 #define toxdigitvalue(c) (isasciidigit (c) ? (int) (((char) (c)) - '0') : \ 652 ( (((char) (c)) >= 'A' && ((char) (c)) <= 'F') ? \ 653 (int) (((unsigned char) (c)) - 'A' + 10) : \ 654 ( (((char) (c)) >= 'a' && ((char) (c)) <= 'f') ? \ 655 (int) (((unsigned char) (c)) - 'a' + 10) : \ 656 (int) (-1) ))) 657 658 /** 659 * Caseless compare two characters. 660 * 661 * @param c1 the first char to compare 662 * @param c2 the second char to compare 663 * @return boolean 'true' if chars are caseless equal, false otherwise 664 */ 665 #define charsequalcaseless(c1, c2) \ 666 ( ((c1) == (c2)) || \ 667 (isasciiupper (c1) ? \ 668 (((c1) - 'A' + 'a') == (c2)) : \ 669 (((c1) == ((c2) - 'A' + 'a')) && isasciiupper (c2))) ) 670 671 #endif /* !HAVE_INLINE_FUNCS */ 672 673 674 #ifndef MHD_FAVOR_SMALL_CODE 675 /** 676 * Check two strings for equality, ignoring case of US-ASCII letters. 677 * 678 * @param str1 first string to compare 679 * @param str2 second string to compare 680 * @return non-zero if two strings are equal, zero otherwise. 681 */ 682 int 683 MHD_str_equal_caseless_ (const char *str1, 684 const char *str2) 685 { 686 while (0 != (*str1)) 687 { 688 const char c1 = *str1; 689 const char c2 = *str2; 690 if (charsequalcaseless (c1, c2)) 691 { 692 str1++; 693 str2++; 694 } 695 else 696 return 0; 697 } 698 return 0 == (*str2); 699 } 700 701 702 #endif /* ! MHD_FAVOR_SMALL_CODE */ 703 704 705 /** 706 * Check two string for equality, ignoring case of US-ASCII letters and 707 * checking not more than @a maxlen characters. 708 * Compares up to first terminating null character, but not more than 709 * first @a maxlen characters. 710 * 711 * @param str1 first string to compare 712 * @param str2 second string to compare 713 * @param maxlen maximum number of characters to compare 714 * @return non-zero if two strings are equal, zero otherwise. 715 */ 716 int 717 MHD_str_equal_caseless_n_ (const char *const str1, 718 const char *const str2, 719 size_t maxlen) 720 { 721 size_t i; 722 723 for (i = 0; i < maxlen; ++i) 724 { 725 const char c1 = str1[i]; 726 const char c2 = str2[i]; 727 if (0 == c2) 728 return 0 == c1; 729 if (charsequalcaseless (c1, c2)) 730 continue; 731 else 732 return 0; 733 } 734 return ! 0; 735 } 736 737 738 /** 739 * Check two string for equality, ignoring case of US-ASCII letters and 740 * checking not more than @a len bytes. 741 * Compares not more first than @a len bytes, including binary zero characters. 742 * Comparison stops at first unmatched byte. 743 * @param str1 first string to compare 744 * @param str2 second string to compare 745 * @param len number of characters to compare 746 * @return non-zero if @a len bytes are equal, zero otherwise. 747 */ 748 bool 749 MHD_str_equal_caseless_bin_n_ (const char *const str1, 750 const char *const str2, 751 size_t len) 752 { 753 size_t i; 754 755 for (i = 0; i < len; ++i) 756 { 757 const char c1 = str1[i]; 758 const char c2 = str2[i]; 759 if (charsequalcaseless (c1, c2)) 760 continue; 761 else 762 return 0; 763 } 764 return ! 0; 765 } 766 767 768 /** 769 * Check whether @a str has case-insensitive @a token. 770 * Token could be surrounded by spaces and tabs and delimited by comma. 771 * Match succeed if substring between start, end (of string) or comma 772 * contains only case-insensitive token and optional spaces and tabs. 773 * @warning token must not contain null-characters except optional 774 * terminating null-character. 775 * @param str the string to check 776 * @param token the token to find 777 * @param token_len length of token, not including optional terminating 778 * null-character. 779 * @return non-zero if two strings are equal, zero otherwise. 780 */ 781 bool 782 MHD_str_has_token_caseless_ (const char *str, 783 const char *const token, 784 size_t token_len) 785 { 786 if (0 == token_len) 787 return false; 788 789 while (0 != *str) 790 { 791 size_t i; 792 /* Skip all whitespaces and empty tokens. */ 793 while (' ' == *str || '\t' == *str || ',' == *str) 794 str++; 795 796 /* Check for token match. */ 797 i = 0; 798 while (1) 799 { 800 const char sc = *(str++); 801 const char tc = token[i++]; 802 803 if (0 == sc) 804 return false; 805 if (! charsequalcaseless (sc, tc)) 806 break; 807 if (i >= token_len) 808 { 809 /* Check whether substring match token fully or 810 * has additional unmatched chars at tail. */ 811 while (' ' == *str || '\t' == *str) 812 str++; 813 /* End of (sub)string? */ 814 if ((0 == *str) || (',' == *str) ) 815 return true; 816 /* Unmatched chars at end of substring. */ 817 break; 818 } 819 } 820 /* Find next substring. */ 821 while (0 != *str && ',' != *str) 822 str++; 823 } 824 return false; 825 } 826 827 828 /** 829 * Remove case-insensitive @a token from the @a str and put result 830 * to the output @a buf. 831 * 832 * Tokens in @a str could be surrounded by spaces and tabs and delimited by 833 * comma. The token match succeed if substring between start, end (of string) 834 * or comma contains only case-insensitive token and optional spaces and tabs. 835 * The quoted strings and comments are not supported by this function. 836 * 837 * The output string is normalised: empty tokens and repeated whitespaces 838 * are removed, no whitespaces before commas, exactly one space is used after 839 * each comma. 840 * 841 * @param str the string to process 842 * @param str_len the length of the @a str, not including optional 843 * terminating null-character. 844 * @param token the token to find 845 * @param token_len the length of @a token, not including optional 846 * terminating null-character. 847 * @param[out] buf the output buffer, not null-terminated. 848 * @param[in,out] buf_size pointer to the size variable, at input it 849 * is the size of allocated buffer, at output 850 * it is the size of the resulting string (can 851 * be up to 50% larger than input) or negative value 852 * if there is not enough space for the result 853 * @return 'true' if token has been removed, 854 * 'false' otherwise. 855 */ 856 bool 857 MHD_str_remove_token_caseless_ (const char *str, 858 size_t str_len, 859 const char *const token, 860 const size_t token_len, 861 char *buf, 862 ssize_t *buf_size) 863 { 864 const char *s1; /**< the "input" string / character */ 865 char *s2; /**< the "output" string / character */ 866 size_t t_pos; /**< position of matched character in the token */ 867 bool token_removed; 868 869 mhd_assert (NULL == memchr (token, 0, token_len)); 870 mhd_assert (NULL == memchr (token, ' ', token_len)); 871 mhd_assert (NULL == memchr (token, '\t', token_len)); 872 mhd_assert (NULL == memchr (token, ',', token_len)); 873 mhd_assert (0 <= *buf_size); 874 875 if (SSIZE_MAX <= ((str_len / 2) * 3 + 3)) 876 { 877 /* The return value may overflow, refuse */ 878 *buf_size = (ssize_t) -1; 879 return false; 880 } 881 s1 = str; 882 s2 = buf; 883 token_removed = false; 884 885 while ((size_t) (s1 - str) < str_len) 886 { 887 const char *cur_token; /**< the first char of current token */ 888 size_t copy_size; 889 890 /* Skip any initial whitespaces and empty tokens */ 891 while ( ((size_t) (s1 - str) < str_len) && 892 ((' ' == *s1) || ('\t' == *s1) || (',' == *s1)) ) 893 s1++; 894 895 /* 's1' points to the first char of token in the input string or 896 * points just beyond the end of the input string */ 897 898 if ((size_t) (s1 - str) >= str_len) 899 break; /* Nothing to copy, end of the input string */ 900 901 /* 's1' points to the first char of token in the input string */ 902 903 cur_token = s1; /* the first char of input token */ 904 905 /* Check the token with case-insensetive match */ 906 t_pos = 0; 907 while ( ((size_t) (s1 - str) < str_len) && (token_len > t_pos) && 908 (charsequalcaseless (*s1, token[t_pos])) ) 909 { 910 s1++; 911 t_pos++; 912 } 913 /* s1 may point just beyond the end of the input string */ 914 if ( (token_len == t_pos) && (0 != token_len) ) 915 { 916 /* 'token' matched, check that current input token does not have 917 * any suffixes */ 918 while ( ((size_t) (s1 - str) < str_len) && 919 ((' ' == *s1) || ('\t' == *s1)) ) 920 s1++; 921 /* 's1' points to the first non-whitespace char after the token matched 922 * requested token or points just beyond the end of the input string after 923 * the requested token */ 924 if (((size_t) (s1 - str) == str_len) || (',' == *s1)) 925 {/* full token match, do not copy current token to the output */ 926 token_removed = true; 927 continue; 928 } 929 } 930 931 /* 's1' points to first non-whitespace char, to some char after 932 * first non-whitespace char in the token in the input string, to 933 * the ',', or just beyond the end of the input string */ 934 /* The current token in the input string does not match the token 935 * to exclude, it must be copied to the output string */ 936 /* the current token size excluding leading whitespaces and current char */ 937 copy_size = (size_t) (s1 - cur_token); 938 if (buf == s2) 939 { /* The first token to copy to the output */ 940 if ((size_t) *buf_size < copy_size) 941 { /* Not enough space in the output buffer */ 942 *buf_size = (ssize_t) -1; 943 return false; 944 } 945 } 946 else 947 { /* Some token was already copied to the output buffer */ 948 mhd_assert (s2 > buf); 949 if ((size_t) *buf_size < ((size_t) (s2 - buf)) + copy_size + 2) 950 { /* Not enough space in the output buffer */ 951 *buf_size = (ssize_t) -1; 952 return false; 953 } 954 *(s2++) = ','; 955 *(s2++) = ' '; 956 } 957 /* Copy non-matched token to the output */ 958 if (0 != copy_size) 959 { 960 memcpy (s2, cur_token, copy_size); 961 s2 += copy_size; 962 } 963 964 while ( ((size_t) (s1 - str) < str_len) && (',' != *s1)) 965 { 966 /* 's1' points to first non-whitespace char, to some char after 967 * first non-whitespace char in the token in the input string */ 968 /* Copy all non-whitespace chars from the current token in 969 * the input string */ 970 while ( ((size_t) (s1 - str) < str_len) && 971 (',' != *s1) && (' ' != *s1) && ('\t' != *s1) ) 972 { 973 mhd_assert (s2 >= buf); 974 if ((size_t) *buf_size <= (size_t) (s2 - buf)) /* '<= s2' equals '< s2 + 1' */ 975 { /* Not enough space in the output buffer */ 976 *buf_size = (ssize_t) -1; 977 return false; 978 } 979 *(s2++) = *(s1++); 980 } 981 /* 's1' points to some whitespace char in the token in the input 982 * string, to the ',', or just beyond the end of the input string */ 983 /* Skip all whitespaces */ 984 while ( ((size_t) (s1 - str) < str_len) && 985 ((' ' == *s1) || ('\t' == *s1)) ) 986 s1++; 987 988 /* 's1' points to the first non-whitespace char in the input string 989 * after whitespace chars, to the ',', or just beyond the end of 990 * the input string */ 991 if (((size_t) (s1 - str) < str_len) && (',' != *s1)) 992 { /* Not the end of the current token */ 993 mhd_assert (s2 >= buf); 994 if ((size_t) *buf_size <= (size_t) (s2 - buf)) /* '<= s2' equals '< s2 + 1' */ 995 { /* Not enough space in the output buffer */ 996 *buf_size = (ssize_t) -1; 997 return false; 998 } 999 *(s2++) = ' '; 1000 } 1001 } 1002 } 1003 mhd_assert (((ssize_t) (s2 - buf)) <= *buf_size); 1004 *buf_size = (ssize_t) (s2 - buf); 1005 return token_removed; 1006 } 1007 1008 1009 /** 1010 * Perform in-place case-insensitive removal of @a tokens from the @a str. 1011 * 1012 * Token could be surrounded by spaces and tabs and delimited by comma. 1013 * The token match succeed if substring between start, end (of the string), or 1014 * comma contains only case-insensitive token and optional spaces and tabs. 1015 * The quoted strings and comments are not supported by this function. 1016 * 1017 * The input string must be normalised: empty tokens and repeated whitespaces 1018 * are removed, no whitespaces before commas, exactly one space is used after 1019 * each comma. The string is updated in-place. 1020 * 1021 * Behavior is undefined is the input string in not normalised. 1022 * 1023 * @param[in,out] str the string to update 1024 * @param[in,out] str_len the length of the @a str, not including optional 1025 * terminating null-character, not null-terminated 1026 * @param tokens the token to find 1027 * @param tokens_len the length of @a tokens, not including optional 1028 * terminating null-character. 1029 * @return 'true' if any token has been removed, 1030 * 'false' otherwise. 1031 */ 1032 bool 1033 MHD_str_remove_tokens_caseless_ (char *str, 1034 size_t *str_len, 1035 const char *const tokens, 1036 const size_t tokens_len) 1037 { 1038 const char *const t = tokens; /**< a short alias for @a tokens */ 1039 size_t pt; /**< position in @a tokens */ 1040 bool token_removed; 1041 1042 mhd_assert (NULL == memchr (tokens, 0, tokens_len)); 1043 1044 token_removed = false; 1045 pt = 0; 1046 1047 while (pt < tokens_len && *str_len != 0) 1048 { 1049 const char *tkn; /**< the current token */ 1050 size_t tkn_len; 1051 1052 /* Skip any initial whitespaces and empty tokens in 'tokens' */ 1053 while ( (pt < tokens_len) && 1054 ((' ' == t[pt]) || ('\t' == t[pt]) || (',' == t[pt])) ) 1055 pt++; 1056 1057 if (pt >= tokens_len) 1058 break; /* No more tokens, nothing to remove */ 1059 1060 /* Found non-whitespace char which is not a comma */ 1061 tkn = t + pt; 1062 do 1063 { 1064 do 1065 { 1066 pt++; 1067 } while (pt < tokens_len && 1068 (' ' != t[pt] && '\t' != t[pt] && ',' != t[pt])); 1069 /* Found end of the token string, space, tab, or comma */ 1070 tkn_len = pt - (size_t) (tkn - t); 1071 1072 /* Skip all spaces and tabs */ 1073 while (pt < tokens_len && (' ' == t[pt] || '\t' == t[pt])) 1074 pt++; 1075 /* Found end of the token string or non-whitespace char */ 1076 } while (pt < tokens_len && ',' != t[pt]); 1077 1078 /* 'tkn' is the input token with 'tkn_len' chars */ 1079 mhd_assert (0 != tkn_len); 1080 1081 if (*str_len == tkn_len) 1082 { 1083 if (MHD_str_equal_caseless_bin_n_ (str, tkn, tkn_len)) 1084 { 1085 *str_len = 0; 1086 token_removed = true; 1087 } 1088 continue; 1089 } 1090 /* 'tkn' cannot match part of 'str' if length of 'tkn' is larger 1091 * than length of 'str'. 1092 * It's know that 'tkn' is not equal to the 'str' (was checked previously). 1093 * As 'str' is normalized when 'tkn' is not equal to the 'str' 1094 * it is required that 'str' to be at least 3 chars larger then 'tkn' 1095 * (the comma, the space and at least one additional character for the next 1096 * token) to remove 'tkn' from the 'str'. */ 1097 if (*str_len > tkn_len + 2) 1098 { /* Remove 'tkn' from the input string */ 1099 size_t pr; /**< the 'read' position in the @a str */ 1100 size_t pw; /**< the 'write' position in the @a str */ 1101 1102 pr = 0; 1103 pw = 0; 1104 1105 do 1106 { 1107 mhd_assert (pr >= pw); 1108 mhd_assert ((*str_len) >= (pr + tkn_len)); 1109 if ( ( ((*str_len) == (pr + tkn_len)) || (',' == str[pr + tkn_len]) ) && 1110 MHD_str_equal_caseless_bin_n_ (str + pr, tkn, tkn_len) ) 1111 { 1112 /* current token in the input string matches the 'tkn', skip it */ 1113 mhd_assert ((*str_len == pr + tkn_len) || \ 1114 (' ' == str[pr + tkn_len + 1])); /* 'str' must be normalized */ 1115 token_removed = true; 1116 /* Advance to the next token in the input string or beyond 1117 * the end of the input string. */ 1118 pr += tkn_len + 2; 1119 } 1120 else 1121 { 1122 /* current token in the input string does not match the 'tkn', 1123 * copy to the output */ 1124 if (0 != pw) 1125 { /* not the first output token, add ", " to separate */ 1126 if (pr != pw + 2) 1127 { 1128 str[pw++] = ','; 1129 str[pw++] = ' '; 1130 } 1131 else 1132 pw += 2; /* 'str' is not yet modified in this round */ 1133 } 1134 do 1135 { 1136 if (pr != pw) 1137 str[pw] = str[pr]; 1138 pr++; 1139 pw++; 1140 } while (pr < *str_len && ',' != str[pr]); 1141 /* Advance to the next token in the input string or beyond 1142 * the end of the input string. */ 1143 pr += 2; 1144 } 1145 /* 'pr' should point to the next token in the input string or beyond 1146 * the end of the input string */ 1147 if ((*str_len) < (pr + tkn_len)) 1148 { /* The rest of the 'str + pr' is too small to match 'tkn' */ 1149 if ((*str_len) > pr) 1150 { /* Copy the rest of the string */ 1151 size_t copy_size; 1152 copy_size = *str_len - pr; 1153 if (0 != pw) 1154 { /* not the first output token, add ", " to separate */ 1155 if (pr != pw + 2) 1156 { 1157 str[pw++] = ','; 1158 str[pw++] = ' '; 1159 } 1160 else 1161 pw += 2; /* 'str' is not yet modified in this round */ 1162 } 1163 if (pr != pw) 1164 memmove (str + pw, str + pr, copy_size); 1165 pw += copy_size; 1166 } 1167 *str_len = pw; 1168 break; 1169 } 1170 mhd_assert ((' ' != str[0]) && ('\t' != str[0])); 1171 mhd_assert ((0 == pr) || (3 <= pr)); 1172 mhd_assert ((0 == pr) || (' ' == str[pr - 1])); 1173 mhd_assert ((0 == pr) || (',' == str[pr - 2])); 1174 } while (1); 1175 } 1176 } 1177 1178 return token_removed; 1179 } 1180 1181 1182 #ifndef MHD_FAVOR_SMALL_CODE 1183 /* Use individual function for each case */ 1184 1185 /** 1186 * Convert decimal US-ASCII digits in string to number in uint64_t. 1187 * Conversion stopped at first non-digit character. 1188 * 1189 * @param str string to convert 1190 * @param[out] out_val pointer to uint64_t to store result of conversion 1191 * @return non-zero number of characters processed on succeed, 1192 * zero if no digit is found, resulting value is larger 1193 * then possible to store in uint64_t or @a out_val is NULL 1194 */ 1195 size_t 1196 MHD_str_to_uint64_ (const char *str, 1197 uint64_t *out_val) 1198 { 1199 const char *const start = str; 1200 uint64_t res; 1201 1202 if (! str || ! out_val || ! isasciidigit (str[0])) 1203 return 0; 1204 1205 res = 0; 1206 do 1207 { 1208 const int digit = (unsigned char) (*str) - '0'; 1209 if ( (res > (UINT64_MAX / 10)) || 1210 ( (res == (UINT64_MAX / 10)) && 1211 ((uint64_t) digit > (UINT64_MAX % 10)) ) ) 1212 return 0; 1213 1214 res *= 10; 1215 res += (unsigned int) digit; 1216 str++; 1217 } while (isasciidigit (*str)); 1218 1219 *out_val = res; 1220 return (size_t) (str - start); 1221 } 1222 1223 1224 /** 1225 * Convert not more then @a maxlen decimal US-ASCII digits in string to 1226 * number in uint64_t. 1227 * Conversion stopped at first non-digit character or after @a maxlen 1228 * digits. 1229 * 1230 * @param str string to convert 1231 * @param maxlen maximum number of characters to process 1232 * @param[out] out_val pointer to uint64_t to store result of conversion 1233 * @return non-zero number of characters processed on succeed, 1234 * zero if no digit is found, resulting value is larger 1235 * then possible to store in uint64_t or @a out_val is NULL 1236 */ 1237 size_t 1238 MHD_str_to_uint64_n_ (const char *str, 1239 size_t maxlen, 1240 uint64_t *out_val) 1241 { 1242 uint64_t res; 1243 size_t i; 1244 1245 if (! str || ! maxlen || ! out_val || ! isasciidigit (str[0])) 1246 return 0; 1247 1248 res = 0; 1249 i = 0; 1250 do 1251 { 1252 const int digit = (unsigned char) str[i] - '0'; 1253 1254 if ( (res > (UINT64_MAX / 10)) || 1255 ( (res == (UINT64_MAX / 10)) && 1256 ((uint64_t) digit > (UINT64_MAX % 10)) ) ) 1257 return 0; 1258 1259 res *= 10; 1260 res += (unsigned int) digit; 1261 i++; 1262 } while ( (i < maxlen) && 1263 isasciidigit (str[i]) ); 1264 1265 *out_val = res; 1266 return i; 1267 } 1268 1269 1270 /** 1271 * Convert hexadecimal US-ASCII digits in string to number in uint32_t. 1272 * Conversion stopped at first non-digit character. 1273 * 1274 * @param str string to convert 1275 * @param[out] out_val pointer to uint32_t to store result of conversion 1276 * @return non-zero number of characters processed on succeed, 1277 * zero if no digit is found, resulting value is larger 1278 * then possible to store in uint32_t or @a out_val is NULL 1279 */ 1280 size_t 1281 MHD_strx_to_uint32_ (const char *str, 1282 uint32_t *out_val) 1283 { 1284 const char *const start = str; 1285 uint32_t res; 1286 int digit; 1287 1288 if (! str || ! out_val) 1289 return 0; 1290 1291 res = 0; 1292 digit = toxdigitvalue (*str); 1293 while (digit >= 0) 1294 { 1295 if ( (res < (UINT32_MAX / 16)) || 1296 ((res == (UINT32_MAX / 16)) && 1297 ( (uint32_t) digit <= (UINT32_MAX % 16)) ) ) 1298 { 1299 res *= 16; 1300 res += (unsigned int) digit; 1301 } 1302 else 1303 return 0; 1304 str++; 1305 digit = toxdigitvalue (*str); 1306 } 1307 1308 if (str - start > 0) 1309 *out_val = res; 1310 return (size_t) (str - start); 1311 } 1312 1313 1314 /** 1315 * Convert not more then @a maxlen hexadecimal US-ASCII digits in string 1316 * to number in uint32_t. 1317 * Conversion stopped at first non-digit character or after @a maxlen 1318 * digits. 1319 * 1320 * @param str string to convert 1321 * @param maxlen maximum number of characters to process 1322 * @param[out] out_val pointer to uint32_t to store result of conversion 1323 * @return non-zero number of characters processed on succeed, 1324 * zero if no digit is found, resulting value is larger 1325 * then possible to store in uint32_t or @a out_val is NULL 1326 */ 1327 size_t 1328 MHD_strx_to_uint32_n_ (const char *str, 1329 size_t maxlen, 1330 uint32_t *out_val) 1331 { 1332 size_t i; 1333 uint32_t res; 1334 int digit; 1335 if (! str || ! out_val) 1336 return 0; 1337 1338 res = 0; 1339 i = 0; 1340 while (i < maxlen && (digit = toxdigitvalue (str[i])) >= 0) 1341 { 1342 if ( (res > (UINT32_MAX / 16)) || 1343 ((res == (UINT32_MAX / 16)) && 1344 ( (uint32_t) digit > (UINT32_MAX % 16)) ) ) 1345 return 0; 1346 1347 res *= 16; 1348 res += (unsigned int) digit; 1349 i++; 1350 } 1351 1352 if (i) 1353 *out_val = res; 1354 return i; 1355 } 1356 1357 1358 /** 1359 * Convert hexadecimal US-ASCII digits in string to number in uint64_t. 1360 * Conversion stopped at first non-digit character. 1361 * 1362 * @param str string to convert 1363 * @param[out] out_val pointer to uint64_t to store result of conversion 1364 * @return non-zero number of characters processed on succeed, 1365 * zero if no digit is found, resulting value is larger 1366 * then possible to store in uint64_t or @a out_val is NULL 1367 */ 1368 size_t 1369 MHD_strx_to_uint64_ (const char *str, 1370 uint64_t *out_val) 1371 { 1372 const char *const start = str; 1373 uint64_t res; 1374 int digit; 1375 if (! str || ! out_val) 1376 return 0; 1377 1378 res = 0; 1379 digit = toxdigitvalue (*str); 1380 while (digit >= 0) 1381 { 1382 if ( (res < (UINT64_MAX / 16)) || 1383 ((res == (UINT64_MAX / 16)) && 1384 ( (uint64_t) digit <= (UINT64_MAX % 16)) ) ) 1385 { 1386 res *= 16; 1387 res += (unsigned int) digit; 1388 } 1389 else 1390 return 0; 1391 str++; 1392 digit = toxdigitvalue (*str); 1393 } 1394 1395 if (str - start > 0) 1396 *out_val = res; 1397 return (size_t) (str - start); 1398 } 1399 1400 1401 /** 1402 * Convert not more then @a maxlen hexadecimal US-ASCII digits in string 1403 * to number in uint64_t. 1404 * Conversion stopped at first non-digit character or after @a maxlen 1405 * digits. 1406 * 1407 * @param str string to convert 1408 * @param maxlen maximum number of characters to process 1409 * @param[out] out_val pointer to uint64_t to store result of conversion 1410 * @return non-zero number of characters processed on succeed, 1411 * zero if no digit is found, resulting value is larger 1412 * then possible to store in uint64_t or @a out_val is NULL 1413 */ 1414 size_t 1415 MHD_strx_to_uint64_n_ (const char *str, 1416 size_t maxlen, 1417 uint64_t *out_val) 1418 { 1419 size_t i; 1420 uint64_t res; 1421 int digit; 1422 if (! str || ! out_val) 1423 return 0; 1424 1425 res = 0; 1426 i = 0; 1427 while (i < maxlen && (digit = toxdigitvalue (str[i])) >= 0) 1428 { 1429 if ( (res > (UINT64_MAX / 16)) || 1430 ((res == (UINT64_MAX / 16)) && 1431 ( (uint64_t) digit > (UINT64_MAX % 16)) ) ) 1432 return 0; 1433 1434 res *= 16; 1435 res += (unsigned int) digit; 1436 i++; 1437 } 1438 1439 if (i) 1440 *out_val = res; 1441 return i; 1442 } 1443 1444 1445 #else /* MHD_FAVOR_SMALL_CODE */ 1446 1447 /** 1448 * Generic function for converting not more then @a maxlen 1449 * hexadecimal or decimal US-ASCII digits in string to number. 1450 * Conversion stopped at first non-digit character or after @a maxlen 1451 * digits. 1452 * To be used only within macro. 1453 * 1454 * @param str the string to convert 1455 * @param maxlen the maximum number of characters to process 1456 * @param out_val the pointer to variable to store result of conversion 1457 * @param val_size the size of variable pointed by @a out_val, in bytes, 4 or 8 1458 * @param max_val the maximum decoded number 1459 * @param base the numeric base, 10 or 16 1460 * @return non-zero number of characters processed on succeed, 1461 * zero if no digit is found, resulting value is larger 1462 * then @a max_val, @a val_size is not 4/8 or @a out_val is NULL 1463 */ 1464 size_t 1465 MHD_str_to_uvalue_n_ (const char *str, 1466 size_t maxlen, 1467 void *out_val, 1468 size_t val_size, 1469 uint64_t max_val, 1470 unsigned int base) 1471 { 1472 size_t i; 1473 uint64_t res; 1474 const uint64_t max_v_div_b = max_val / base; 1475 const uint64_t max_v_mod_b = max_val % base; 1476 1477 if (! str || ! out_val || 1478 ((base != 16) && (base != 10)) ) 1479 return 0; 1480 1481 res = 0; 1482 i = 0; 1483 while (maxlen > i) 1484 { 1485 const int digit = (base == 16) ? 1486 toxdigitvalue (str[i]) : todigitvalue (str[i]); 1487 1488 if (0 > digit) 1489 break; 1490 if ( ((max_v_div_b) < res) || 1491 (( (max_v_div_b) == res) && ( (max_v_mod_b) < (uint64_t) digit) ) ) 1492 return 0; 1493 1494 res *= base; 1495 res += (unsigned int) digit; 1496 i++; 1497 } 1498 1499 if (i) 1500 { 1501 if (8 == val_size) 1502 *(uint64_t *) out_val = res; 1503 else if (4 == val_size) 1504 *(uint32_t *) out_val = (uint32_t) res; 1505 else 1506 return 0; 1507 } 1508 return i; 1509 } 1510 1511 1512 #endif /* MHD_FAVOR_SMALL_CODE */ 1513 1514 1515 size_t 1516 MHD_uint32_to_strx (uint32_t val, 1517 char *buf, 1518 size_t buf_size) 1519 { 1520 size_t o_pos = 0; /**< position of the output character */ 1521 int digit_pos = 8; /** zero-based, digit position in @a 'val' */ 1522 int digit; 1523 1524 /* Skip leading zeros */ 1525 do 1526 { 1527 digit_pos--; 1528 digit = (int) (val >> 28); 1529 val <<= 4; 1530 } while ((0 == digit) && (0 != digit_pos)); 1531 1532 while (o_pos < buf_size) 1533 { 1534 buf[o_pos++] = 1535 (char) ((digit <= 9) ? 1536 ('0' + (char) digit) : 1537 ('A' + (char) digit - 10)); 1538 if (0 == digit_pos) 1539 return o_pos; 1540 digit_pos--; 1541 digit = (int) (val >> 28); 1542 val <<= 4; 1543 } 1544 return 0; /* The buffer is too small */ 1545 } 1546 1547 1548 #ifndef MHD_FAVOR_SMALL_CODE 1549 size_t 1550 MHD_uint16_to_str (uint16_t val, 1551 char *buf, 1552 size_t buf_size) 1553 { 1554 char *chr; /**< pointer to the current printed digit */ 1555 /* The biggest printable number is 65535 */ 1556 uint16_t divisor = UINT16_C (10000); 1557 int digit; 1558 1559 chr = buf; 1560 digit = (int) (val / divisor); 1561 mhd_assert (digit < 10); 1562 1563 /* Do not print leading zeros */ 1564 while ((0 == digit) && (1 < divisor)) 1565 { 1566 divisor /= 10; 1567 digit = (int) (val / divisor); 1568 mhd_assert (digit < 10); 1569 } 1570 1571 while (0 != buf_size) 1572 { 1573 *chr = (char) ((char) digit + '0'); 1574 chr++; 1575 buf_size--; 1576 if (1 == divisor) 1577 return (size_t) (chr - buf); 1578 val = (uint16_t) (val % divisor); 1579 divisor /= 10; 1580 digit = (int) (val / divisor); 1581 mhd_assert (digit < 10); 1582 } 1583 return 0; /* The buffer is too small */ 1584 } 1585 1586 1587 #endif /* !MHD_FAVOR_SMALL_CODE */ 1588 1589 1590 size_t 1591 MHD_uint64_to_str (uint64_t val, 1592 char *buf, 1593 size_t buf_size) 1594 { 1595 char *chr; /**< pointer to the current printed digit */ 1596 /* The biggest printable number is 18446744073709551615 */ 1597 uint64_t divisor = UINT64_C (10000000000000000000); 1598 int digit; 1599 1600 chr = buf; 1601 digit = (int) (val / divisor); 1602 mhd_assert (digit < 10); 1603 1604 /* Do not print leading zeros */ 1605 while ((0 == digit) && (1 < divisor)) 1606 { 1607 divisor /= 10; 1608 digit = (int) (val / divisor); 1609 mhd_assert (digit < 10); 1610 } 1611 1612 while (0 != buf_size) 1613 { 1614 *chr = (char) ((char) digit + '0'); 1615 chr++; 1616 buf_size--; 1617 if (1 == divisor) 1618 return (size_t) (chr - buf); 1619 val %= divisor; 1620 divisor /= 10; 1621 digit = (int) (val / divisor); 1622 mhd_assert (digit < 10); 1623 } 1624 return 0; /* The buffer is too small */ 1625 } 1626 1627 1628 size_t 1629 MHD_uint8_to_str_pad (uint8_t val, 1630 uint8_t min_digits, 1631 char *buf, 1632 size_t buf_size) 1633 { 1634 size_t pos; /**< the position of the current printed digit */ 1635 int digit; 1636 mhd_assert (3 >= min_digits); 1637 if (0 == buf_size) 1638 return 0; 1639 1640 pos = 0; 1641 digit = val / 100; 1642 if (0 == digit) 1643 { 1644 if (3 <= min_digits) 1645 buf[pos++] = '0'; 1646 } 1647 else 1648 { 1649 buf[pos++] = (char) ('0' + (char) digit); 1650 val %= 100; 1651 min_digits = 2; 1652 } 1653 1654 if (buf_size <= pos) 1655 return 0; 1656 digit = val / 10; 1657 if (0 == digit) 1658 { 1659 if (2 <= min_digits) 1660 buf[pos++] = '0'; 1661 } 1662 else 1663 { 1664 buf[pos++] = (char) ('0' + (char) digit); 1665 val %= 10; 1666 } 1667 1668 if (buf_size <= pos) 1669 return 0; 1670 buf[pos++] = (char) ('0' + (char) val); 1671 return pos; 1672 } 1673 1674 1675 size_t 1676 MHD_bin_to_hex (const void *bin, 1677 size_t size, 1678 char *hex) 1679 { 1680 size_t i; 1681 1682 for (i = 0; i < size; ++i) 1683 { 1684 uint8_t j; 1685 const uint8_t b = ((const uint8_t *) bin)[i]; 1686 j = b >> 4; 1687 hex[i * 2] = (char) ((j < 10) ? (j + '0') : (j - 10 + 'a')); 1688 j = b & 0x0f; 1689 hex[i * 2 + 1] = (char) ((j < 10) ? (j + '0') : (j - 10 + 'a')); 1690 } 1691 return i * 2; 1692 } 1693 1694 1695 size_t 1696 MHD_bin_to_hex_z (const void *bin, 1697 size_t size, 1698 char *hex) 1699 { 1700 size_t res; 1701 1702 res = MHD_bin_to_hex (bin, size, hex); 1703 hex[res] = 0; 1704 1705 return res; 1706 } 1707 1708 1709 size_t 1710 MHD_hex_to_bin (const char *hex, 1711 size_t len, 1712 void *bin) 1713 { 1714 uint8_t *const out = (uint8_t *) bin; 1715 size_t r; 1716 size_t w; 1717 1718 if (0 == len) 1719 return 0; 1720 r = 0; 1721 w = 0; 1722 if (0 != len % 2) 1723 { 1724 /* Assume the first byte is encoded with single digit */ 1725 const char c2 = hex[r++]; 1726 const int l = toxdigitvalue (c2); 1727 if (0 > l) 1728 return 0; 1729 out[w++] = (uint8_t) ((unsigned int) l); 1730 } 1731 while (r < len) 1732 { 1733 const char c1 = hex[r++]; 1734 const char c2 = hex[r++]; 1735 const int h = toxdigitvalue (c1); 1736 const int l = toxdigitvalue (c2); 1737 if ((0 > h) || (0 > l)) 1738 return 0; 1739 out[w++] = (uint8_t) ( ((uint8_t) (((uint8_t) ((unsigned int) h)) << 4)) 1740 | ((uint8_t) ((unsigned int) l)) ); 1741 } 1742 mhd_assert (len == r); 1743 mhd_assert ((len + 1) / 2 == w); 1744 return w; 1745 } 1746 1747 1748 size_t 1749 MHD_str_pct_decode_strict_n_ (const char *pct_encoded, 1750 size_t pct_encoded_len, 1751 char *decoded, 1752 size_t buf_size) 1753 { 1754 #ifdef MHD_FAVOR_SMALL_CODE 1755 bool broken; 1756 size_t res; 1757 1758 res = MHD_str_pct_decode_lenient_n_ (pct_encoded, pct_encoded_len, decoded, 1759 buf_size, &broken); 1760 if (broken) 1761 return 0; 1762 return res; 1763 #else /* ! MHD_FAVOR_SMALL_CODE */ 1764 size_t r; 1765 size_t w; 1766 r = 0; 1767 w = 0; 1768 1769 if (buf_size >= pct_encoded_len) 1770 { 1771 while (r < pct_encoded_len) 1772 { 1773 const char chr = pct_encoded[r]; 1774 if ('%' == chr) 1775 { 1776 if (2 > pct_encoded_len - r) 1777 return 0; 1778 else 1779 { 1780 const char c1 = pct_encoded[++r]; 1781 const char c2 = pct_encoded[++r]; 1782 const int h = toxdigitvalue (c1); 1783 const int l = toxdigitvalue (c2); 1784 unsigned char out; 1785 if ((0 > h) || (0 > l)) 1786 return 0; 1787 out = 1788 (unsigned char) (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4)) 1789 | ((uint8_t) ((unsigned int) l))); 1790 decoded[w] = (char) out; 1791 } 1792 } 1793 else 1794 decoded[w] = chr; 1795 ++r; 1796 ++w; 1797 } 1798 return w; 1799 } 1800 1801 while (r < pct_encoded_len) 1802 { 1803 const char chr = pct_encoded[r]; 1804 if (w >= buf_size) 1805 return 0; 1806 if ('%' == chr) 1807 { 1808 if (2 > pct_encoded_len - r) 1809 return 0; 1810 else 1811 { 1812 const char c1 = pct_encoded[++r]; 1813 const char c2 = pct_encoded[++r]; 1814 const int h = toxdigitvalue (c1); 1815 const int l = toxdigitvalue (c2); 1816 unsigned char out; 1817 if ((0 > h) || (0 > l)) 1818 return 0; 1819 out = 1820 (unsigned char) (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4)) 1821 | ((uint8_t) ((unsigned int) l))); 1822 decoded[w] = (char) out; 1823 } 1824 } 1825 else 1826 decoded[w] = chr; 1827 ++r; 1828 ++w; 1829 } 1830 return w; 1831 #endif /* ! MHD_FAVOR_SMALL_CODE */ 1832 } 1833 1834 1835 size_t 1836 MHD_str_pct_decode_lenient_n_ (const char *pct_encoded, 1837 size_t pct_encoded_len, 1838 char *decoded, 1839 size_t buf_size, 1840 bool *broken_encoding) 1841 { 1842 size_t r; 1843 size_t w; 1844 r = 0; 1845 w = 0; 1846 if (NULL != broken_encoding) 1847 *broken_encoding = false; 1848 #ifndef MHD_FAVOR_SMALL_CODE 1849 if (buf_size >= pct_encoded_len) 1850 { 1851 while (r < pct_encoded_len) 1852 { 1853 const char chr = pct_encoded[r]; 1854 if ('%' == chr) 1855 { 1856 if (2 > pct_encoded_len - r) 1857 { 1858 if (NULL != broken_encoding) 1859 *broken_encoding = true; 1860 decoded[w] = chr; /* Copy "as is" */ 1861 } 1862 else 1863 { 1864 const char c1 = pct_encoded[++r]; 1865 const char c2 = pct_encoded[++r]; 1866 const int h = toxdigitvalue (c1); 1867 const int l = toxdigitvalue (c2); 1868 unsigned char out; 1869 if ((0 > h) || (0 > l)) 1870 { 1871 r -= 2; 1872 if (NULL != broken_encoding) 1873 *broken_encoding = true; 1874 decoded[w] = chr; /* Copy "as is" */ 1875 } 1876 else 1877 { 1878 out = 1879 (unsigned char) (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4)) 1880 | ((uint8_t) ((unsigned int) l))); 1881 decoded[w] = (char) out; 1882 } 1883 } 1884 } 1885 else 1886 decoded[w] = chr; 1887 ++r; 1888 ++w; 1889 } 1890 return w; 1891 } 1892 #endif /* ! MHD_FAVOR_SMALL_CODE */ 1893 while (r < pct_encoded_len) 1894 { 1895 const char chr = pct_encoded[r]; 1896 if (w >= buf_size) 1897 return 0; 1898 if ('%' == chr) 1899 { 1900 if (2 > pct_encoded_len - r) 1901 { 1902 if (NULL != broken_encoding) 1903 *broken_encoding = true; 1904 decoded[w] = chr; /* Copy "as is" */ 1905 } 1906 else 1907 { 1908 const char c1 = pct_encoded[++r]; 1909 const char c2 = pct_encoded[++r]; 1910 const int h = toxdigitvalue (c1); 1911 const int l = toxdigitvalue (c2); 1912 if ((0 > h) || (0 > l)) 1913 { 1914 r -= 2; 1915 if (NULL != broken_encoding) 1916 *broken_encoding = true; 1917 decoded[w] = chr; /* Copy "as is" */ 1918 } 1919 else 1920 { 1921 unsigned char out; 1922 out = 1923 (unsigned char) (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4)) 1924 | ((uint8_t) ((unsigned int) l))); 1925 decoded[w] = (char) out; 1926 } 1927 } 1928 } 1929 else 1930 decoded[w] = chr; 1931 ++r; 1932 ++w; 1933 } 1934 return w; 1935 } 1936 1937 1938 size_t 1939 MHD_str_pct_decode_in_place_strict_ (char *str) 1940 { 1941 #ifdef MHD_FAVOR_SMALL_CODE 1942 size_t res; 1943 bool broken; 1944 1945 res = MHD_str_pct_decode_in_place_lenient_ (str, &broken); 1946 if (broken) 1947 { 1948 res = 0; 1949 str[0] = 0; 1950 } 1951 return res; 1952 #else /* ! MHD_FAVOR_SMALL_CODE */ 1953 size_t r; 1954 size_t w; 1955 r = 0; 1956 w = 0; 1957 1958 while (0 != str[r]) 1959 { 1960 const char chr = str[r++]; 1961 if ('%' == chr) 1962 { 1963 const char d1 = str[r++]; 1964 if (0 == d1) 1965 return 0; 1966 else 1967 { 1968 const char d2 = str[r++]; 1969 if (0 == d2) 1970 return 0; 1971 else 1972 { 1973 const int h = toxdigitvalue (d1); 1974 const int l = toxdigitvalue (d2); 1975 unsigned char out; 1976 if ((0 > h) || (0 > l)) 1977 return 0; 1978 out = 1979 (unsigned char) (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4)) 1980 | ((uint8_t) ((unsigned int) l))); 1981 str[w++] = (char) out; 1982 } 1983 } 1984 } 1985 else 1986 str[w++] = chr; 1987 } 1988 str[w] = 0; 1989 return w; 1990 #endif /* ! MHD_FAVOR_SMALL_CODE */ 1991 } 1992 1993 1994 size_t 1995 MHD_str_pct_decode_in_place_lenient_ (char *str, 1996 bool *broken_encoding) 1997 { 1998 #ifdef MHD_FAVOR_SMALL_CODE 1999 size_t len; 2000 size_t res; 2001 2002 len = strlen (str); 2003 res = MHD_str_pct_decode_lenient_n_ (str, len, str, len, broken_encoding); 2004 str[res] = 0; 2005 2006 return res; 2007 #else /* ! MHD_FAVOR_SMALL_CODE */ 2008 size_t r; 2009 size_t w; 2010 if (NULL != broken_encoding) 2011 *broken_encoding = false; 2012 r = 0; 2013 w = 0; 2014 while (0 != str[r]) 2015 { 2016 const char chr = str[r++]; 2017 if ('%' == chr) 2018 { 2019 const char d1 = str[r++]; 2020 if (0 == d1) 2021 { 2022 if (NULL != broken_encoding) 2023 *broken_encoding = true; 2024 str[w++] = chr; /* Copy "as is" */ 2025 str[w] = 0; 2026 return w; 2027 } 2028 else 2029 { 2030 const char d2 = str[r++]; 2031 if (0 == d2) 2032 { 2033 if (NULL != broken_encoding) 2034 *broken_encoding = true; 2035 str[w++] = chr; /* Copy "as is" */ 2036 str[w++] = d1; /* Copy "as is" */ 2037 str[w] = 0; 2038 return w; 2039 } 2040 else 2041 { 2042 const int h = toxdigitvalue (d1); 2043 const int l = toxdigitvalue (d2); 2044 unsigned char out; 2045 if ((0 > h) || (0 > l)) 2046 { 2047 if (NULL != broken_encoding) 2048 *broken_encoding = true; 2049 str[w++] = chr; /* Copy "as is" */ 2050 str[w++] = d1; 2051 str[w++] = d2; 2052 continue; 2053 } 2054 out = 2055 (unsigned char) (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4)) 2056 | ((uint8_t) ((unsigned int) l))); 2057 str[w++] = (char) out; 2058 continue; 2059 } 2060 } 2061 } 2062 str[w++] = chr; 2063 } 2064 str[w] = 0; 2065 return w; 2066 #endif /* ! MHD_FAVOR_SMALL_CODE */ 2067 } 2068 2069 2070 #ifdef DAUTH_SUPPORT 2071 bool 2072 MHD_str_equal_quoted_bin_n (const char *quoted, 2073 size_t quoted_len, 2074 const char *unquoted, 2075 size_t unquoted_len) 2076 { 2077 size_t i; 2078 size_t j; 2079 if (unquoted_len < quoted_len / 2) 2080 return false; 2081 2082 j = 0; 2083 for (i = 0; quoted_len > i && unquoted_len > j; ++i, ++j) 2084 { 2085 if ('\\' == quoted[i]) 2086 { 2087 i++; /* Advance to the next character */ 2088 if (quoted_len == i) 2089 return false; /* No character after escaping backslash */ 2090 } 2091 if (quoted[i] != unquoted[j]) 2092 return false; /* Different characters */ 2093 } 2094 if ((quoted_len != i) || (unquoted_len != j)) 2095 return false; /* The strings have different length */ 2096 2097 return true; 2098 } 2099 2100 2101 bool 2102 MHD_str_equal_caseless_quoted_bin_n (const char *quoted, 2103 size_t quoted_len, 2104 const char *unquoted, 2105 size_t unquoted_len) 2106 { 2107 size_t i; 2108 size_t j; 2109 if (unquoted_len < quoted_len / 2) 2110 return false; 2111 2112 j = 0; 2113 for (i = 0; quoted_len > i && unquoted_len > j; ++i, ++j) 2114 { 2115 if ('\\' == quoted[i]) 2116 { 2117 i++; /* Advance to the next character */ 2118 if (quoted_len == i) 2119 return false; /* No character after escaping backslash */ 2120 } 2121 if (! charsequalcaseless (quoted[i], unquoted[j])) 2122 return false; /* Different characters */ 2123 } 2124 if ((quoted_len != i) || (unquoted_len != j)) 2125 return false; /* The strings have different length */ 2126 2127 return true; 2128 } 2129 2130 2131 size_t 2132 MHD_str_unquote (const char *quoted, 2133 size_t quoted_len, 2134 char *result) 2135 { 2136 size_t r; 2137 size_t w; 2138 2139 r = 0; 2140 w = 0; 2141 2142 while (quoted_len > r) 2143 { 2144 if ('\\' == quoted[r]) 2145 { 2146 ++r; 2147 if (quoted_len == r) 2148 return 0; /* Last backslash is not followed by char to unescape */ 2149 } 2150 result[w++] = quoted[r++]; 2151 } 2152 return w; 2153 } 2154 2155 2156 #endif /* DAUTH_SUPPORT */ 2157 2158 #if defined(DAUTH_SUPPORT) || defined(BAUTH_SUPPORT) 2159 2160 size_t 2161 MHD_str_quote (const char *unquoted, 2162 size_t unquoted_len, 2163 char *result, 2164 size_t buf_size) 2165 { 2166 size_t r; 2167 size_t w; 2168 2169 r = 0; 2170 w = 0; 2171 2172 #ifndef MHD_FAVOR_SMALL_CODE 2173 if (unquoted_len * 2 <= buf_size) 2174 { 2175 /* Fast loop: the output will fit the buffer with any input string content */ 2176 while (unquoted_len > r) 2177 { 2178 const char chr = unquoted[r++]; 2179 if (('\\' == chr) || ('\"' == chr)) 2180 result[w++] = '\\'; /* Escape current char */ 2181 result[w++] = chr; 2182 } 2183 } 2184 else 2185 { 2186 if (unquoted_len > buf_size) 2187 return 0; /* Quick fail: the output buffer is too small */ 2188 #else /* MHD_FAVOR_SMALL_CODE */ 2189 if (1) 2190 { 2191 #endif /* MHD_FAVOR_SMALL_CODE */ 2192 2193 while (unquoted_len > r) 2194 { 2195 if (buf_size <= w) 2196 return 0; /* The output buffer is too small */ 2197 else 2198 { 2199 const char chr = unquoted[r++]; 2200 if (('\\' == chr) || ('\"' == chr)) 2201 { 2202 result[w++] = '\\'; /* Escape current char */ 2203 if (buf_size <= w) 2204 return 0; /* The output buffer is too small */ 2205 } 2206 result[w++] = chr; 2207 } 2208 } 2209 } 2210 2211 mhd_assert (w >= r); 2212 mhd_assert (w <= r * 2); 2213 return w; 2214 } 2215 2216 2217 #endif /* DAUTH_SUPPORT || BAUTH_SUPPORT */ 2218 2219 #ifdef BAUTH_SUPPORT 2220 2221 /* 2222 * MHD_BASE64_FUNC_VERSION 2223 * 1 = smallest, 2224 * 2 = medium, 2225 * 3 = fastest 2226 */ 2227 #ifndef MHD_BASE64_FUNC_VERSION 2228 #ifdef MHD_FAVOR_SMALL_CODE 2229 #define MHD_BASE64_FUNC_VERSION 1 2230 #else /* ! MHD_FAVOR_SMALL_CODE */ 2231 #define MHD_BASE64_FUNC_VERSION 3 2232 #endif /* ! MHD_FAVOR_SMALL_CODE */ 2233 #endif /* ! MHD_BASE64_FUNC_VERSION */ 2234 2235 #if MHD_BASE64_FUNC_VERSION < 1 || MHD_BASE64_FUNC_VERSION > 3 2236 #error Wrong MHD_BASE64_FUNC_VERSION value 2237 #endif /* MHD_BASE64_FUNC_VERSION < 1 || MHD_BASE64_FUNC_VERSION > 3 */ 2238 2239 #if MHD_BASE64_FUNC_VERSION == 3 2240 #define MHD_base64_map_type_ int 2241 #else /* MHD_BASE64_FUNC_VERSION < 3 */ 2242 #define MHD_base64_map_type_ int8_t 2243 #endif /* MHD_BASE64_FUNC_VERSION < 3 */ 2244 2245 #if MHD_BASE64_FUNC_VERSION == 1 2246 static MHD_base64_map_type_ 2247 base64_char_to_value_ (uint8_t c) 2248 { 2249 if ('Z' >= c) 2250 { 2251 if ('A' <= c) 2252 return (MHD_base64_map_type_) ((c - 'A') + 0); 2253 if ('0' <= c) 2254 { 2255 if ('9' >= c) 2256 return (MHD_base64_map_type_) ((c - '0') + 52); 2257 if ('=' == c) 2258 return -2; 2259 return -1; 2260 } 2261 if ('+' == c) 2262 return 62; 2263 if ('/' == c) 2264 return 63; 2265 return -1; 2266 } 2267 if (('z' >= c) && ('a' <= c)) 2268 return (MHD_base64_map_type_) ((c - 'a') + 26); 2269 return -1; 2270 } 2271 2272 2273 #endif /* MHD_BASE64_FUNC_VERSION == 1 */ 2274 2275 2276 MHD_DATA_TRUNCATION_RUNTIME_CHECK_DISABLE_ 2277 2278 2279 size_t 2280 MHD_base64_to_bin_n (const char *base64, 2281 size_t base64_len, 2282 void *bin, 2283 size_t bin_size) 2284 { 2285 #if MHD_BASE64_FUNC_VERSION >= 2 2286 static const MHD_base64_map_type_ map[] = { 2287 /* -1 = invalid char, -2 = padding 2288 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 2289 NUL, SOH, STX, ETX, EOT, ENQ, ACK, BEL, */ 2290 -1, -1, -1, -1, -1, -1, -1, -1, 2291 /* 2292 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 2293 BS, HT, LF, VT, FF, CR, SO, SI, */ 2294 -1, -1, -1, -1, -1, -1, -1, -1, 2295 /* 2296 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 2297 DLE, DC1, DC2, DC3, DC4, NAK, SYN, ETB, */ 2298 -1, -1, -1, -1, -1, -1, -1, -1, 2299 /* 2300 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 2301 CAN, EM, SUB, ESC, FS, GS, RS, US, */ 2302 -1, -1, -1, -1, -1, -1, -1, -1, 2303 /* 2304 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 2305 ' ', '!', '"', '#', '$', '%', '&', '\'', */ 2306 -1, -1, -1, -1, -1, -1, -1, -1, 2307 /* 2308 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 2309 '(', ')', '*', '+', ',', '-', '.', '/', */ 2310 -1, -1, -1, 62, -1, -1, -1, 63, 2311 /* 2312 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 2313 '0', '1', '2', '3', '4', '5', '6', '7', */ 2314 52, 53, 54, 55, 56, 57, 58, 59, 2315 /* 2316 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 2317 '8', '9', ':', ';', '<', '=', '>', '?', */ 2318 60, 61, -1, -1, -1, -2, -1, -1, 2319 /* 2320 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 2321 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', */ 2322 -1, 0, 1, 2, 3, 4, 5, 6, 2323 /* 2324 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 2325 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', */ 2326 7, 8, 9, 10, 11, 12, 13, 14, 2327 /* 2328 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 2329 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', */ 2330 15, 16, 17, 18, 19, 20, 21, 22, 2331 /* 2332 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 2333 'X', 'Y', 'Z', '[', '\', ']', '^', '_', */ 2334 23, 24, 25, -1, -1, -1, -1, -1, 2335 /* 2336 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 2337 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', */ 2338 -1, 26, 27, 28, 29, 30, 31, 32, 2339 /* 2340 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 2341 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', */ 2342 33, 34, 35, 36, 37, 38, 39, 40, 2343 /* 2344 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 2345 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', */ 2346 41, 42, 43, 44, 45, 46, 47, 48, 2347 /* 2348 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 2349 'x', 'y', 'z', '{', '|', '}', '~', DEL, */ 2350 49, 50, 51, -1, -1, -1, -1, -1 2351 2352 #if MHD_BASE64_FUNC_VERSION == 3 2353 , 2354 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80..8F */ 2355 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 90..9F */ 2356 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A0..AF */ 2357 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* B0..BF */ 2358 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* C0..CF */ 2359 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* D0..DF */ 2360 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* E0..EF */ 2361 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* F0..FF */ 2362 #endif /* ! MHD_BASE64_FUNC_VERSION == 3 */ 2363 }; 2364 #define base64_char_to_value_(c) map[(c)] 2365 #endif /* MHD_BASE64_FUNC_VERSION >= 2 */ 2366 const uint8_t *const in = (const uint8_t *) base64; 2367 uint8_t *const out = (uint8_t *) bin; 2368 size_t i; 2369 size_t j; 2370 if (0 == base64_len) 2371 return 0; /* Nothing to decode */ 2372 if (0 != base64_len % 4) 2373 return 0; /* Wrong input length */ 2374 if (base64_len / 4 * 3 - 2 > bin_size) 2375 return 0; 2376 2377 j = 0; 2378 for (i = 0; i < (base64_len - 4); i += 4) 2379 { 2380 #if MHD_BASE64_FUNC_VERSION == 2 2381 if (0 != (0x80 & (in[i] | in[i + 1] | in[i + 2] | in[i + 3]))) 2382 return 0; 2383 #endif /* MHD_BASE64_FUNC_VERSION == 2 */ 2384 if (1) 2385 { 2386 const MHD_base64_map_type_ v1 = base64_char_to_value_ (in[i + 0]); 2387 const MHD_base64_map_type_ v2 = base64_char_to_value_ (in[i + 1]); 2388 const MHD_base64_map_type_ v3 = base64_char_to_value_ (in[i + 2]); 2389 const MHD_base64_map_type_ v4 = base64_char_to_value_ (in[i + 3]); 2390 if ((0 > v1) || (0 > v2) || (0 > v3) || (0 > v4)) 2391 return 0; 2392 out[j + 0] = (uint8_t) (((uint8_t) (((uint8_t) v1) << 2)) 2393 | ((uint8_t) (((uint8_t) v2) >> 4))); 2394 out[j + 1] = (uint8_t) (((uint8_t) (((uint8_t) v2) << 4)) 2395 | ((uint8_t) (((uint8_t) v3) >> 2))); 2396 out[j + 2] = (uint8_t) (((uint8_t) (((uint8_t) v3) << 6)) 2397 | ((uint8_t) v4)); 2398 } 2399 j += 3; 2400 } 2401 #if MHD_BASE64_FUNC_VERSION == 2 2402 if (0 != (0x80 & (in[i] | in[i + 1] | in[i + 2] | in[i + 3]))) 2403 return 0; 2404 #endif /* MHD_BASE64_FUNC_VERSION == 2 */ 2405 if (1) 2406 { /* The last four chars block */ 2407 const MHD_base64_map_type_ v1 = base64_char_to_value_ (in[i + 0]); 2408 const MHD_base64_map_type_ v2 = base64_char_to_value_ (in[i + 1]); 2409 const MHD_base64_map_type_ v3 = base64_char_to_value_ (in[i + 2]); 2410 const MHD_base64_map_type_ v4 = base64_char_to_value_ (in[i + 3]); 2411 if ((0 > v1) || (0 > v2)) 2412 return 0; /* Invalid char or padding at first two positions */ 2413 mhd_assert (j < bin_size); 2414 out[j++] = (uint8_t) (((uint8_t) (((uint8_t) v1) << 2)) 2415 | ((uint8_t) (((uint8_t) v2) >> 4))); 2416 if (0 > v3) 2417 { /* Third char is either padding or invalid */ 2418 if ((-2 != v3) || (-2 != v4)) 2419 return 0; /* Both two last chars must be padding */ 2420 if (0 != (uint8_t) (((uint8_t) v2) << 4)) 2421 return 0; /* Wrong last char */ 2422 return j; 2423 } 2424 if (j >= bin_size) 2425 return 0; /* Not enough space */ 2426 out[j++] = (uint8_t) (((uint8_t) (((uint8_t) v2) << 4)) 2427 | ((uint8_t) (((uint8_t) v3) >> 2))); 2428 if (0 > v4) 2429 { /* Fourth char is either padding or invalid */ 2430 if (-2 != v4) 2431 return 0; /* The char must be padding */ 2432 if (0 != (uint8_t) (((uint8_t) v3) << 6)) 2433 return 0; /* Wrong last char */ 2434 return j; 2435 } 2436 if (j >= bin_size) 2437 return 0; /* Not enough space */ 2438 out[j++] = (uint8_t) (((uint8_t) (((uint8_t) v3) << 6)) 2439 | ((uint8_t) v4)); 2440 } 2441 return j; 2442 #if MHD_BASE64_FUNC_VERSION >= 2 2443 #undef base64_char_to_value_ 2444 #endif /* MHD_BASE64_FUNC_VERSION >= 2 */ 2445 } 2446 2447 2448 MHD_DATA_TRUNCATION_RUNTIME_CHECK_RESTORE_ 2449 2450 2451 #undef MHD_base64_map_type_ 2452 2453 #endif /* BAUTH_SUPPORT */