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