| 437 | } |
| 438 | |
| 439 | void TNlpParser::Execute(const wchar16* text, size_t len, const wchar16** textStart) { |
| 440 | if (!len) |
| 441 | return; |
| 442 | const wchar16* p = text; |
| 443 | const wchar16* e = p + len; |
| 444 | wchar16* data = nullptr; |
| 445 | wchar16* dest = nullptr; |
| 446 | ExtraLen.clear(); |
| 447 | ExtraLenIndex = 0; |
| 448 | |
| 449 | while (p != e) { |
| 450 | if (UrlDecode && *p == PERCENT_CHAR && (p + 3) <= e && IsHexdigit(p[1]) && IsHexdigit(p[2])) { |
| 451 | if (!dest) { |
| 452 | Buffer = TTempArray<wchar16>(len + 1); |
| 453 | data = Buffer.Data(); |
| 454 | dest = data; |
| 455 | const size_t n = p - text; |
| 456 | std::char_traits<wchar16>::copy(dest, text, n); |
| 457 | dest += n; |
| 458 | } |
| 459 | |
| 460 | const wchar16* start = p; // in case if UTF8 is bad |
| 461 | TTempBuf buf(e - p); // for UTF8 |
| 462 | char* const utf8 = buf.Data(); |
| 463 | size_t i = 0; |
| 464 | while (p != e && *p == PERCENT_CHAR && (p + 3) <= e && IsHexdigit(p[1]) && IsHexdigit(p[2])) { |
| 465 | const char c = (HexToChar(char(p[1])) << 4) | HexToChar(char(p[2])); |
| 466 | utf8[i++] = ((unsigned char)c < 0x20 ? ' ' : c); // replace all controlling characters with ' ' |
| 467 | p += 3; |
| 468 | } |
| 469 | |
| 470 | bool decoded = false; |
| 471 | // convert at least 2 UTF8 bytes |
| 472 | if (i > 1) { |
| 473 | decoded = true; |
| 474 | Y_ABORT_UNLESS(size_t(p - start) == 3 * i); |
| 475 | size_t written = 0; |
| 476 | const size_t extraLenRollback = ExtraLen.size(); |
| 477 | for (size_t j = 0; j < i;) { |
| 478 | size_t stepRead = 0; |
| 479 | if (RECODE_OK != GetUTF8CharLen(stepRead, reinterpret_cast<const unsigned char*>(utf8) + j, reinterpret_cast<const unsigned char*>(utf8) + i)) { |
| 480 | decoded = false; |
| 481 | break; |
| 482 | } |
| 483 | Y_ABORT_UNLESS(stepRead && j + stepRead <= i); |
| 484 | size_t stepWritten = 0; |
| 485 | if (!UTF8ToWide(utf8 + j, stepRead, dest + written, stepWritten)) { |
| 486 | decoded = false; |
| 487 | break; |
| 488 | } |
| 489 | written += stepWritten; |
| 490 | ExtraLen.push_back(std::make_pair<ui32>(dest + written - data, 3 * stepRead - stepWritten)); |
| 491 | j += stepRead; |
| 492 | } |
| 493 | if (decoded) { |
| 494 | dest += written; |
| 495 | } else { |
| 496 | ExtraLen.resize(extraLenRollback); |
no test coverage detected