Decode UTF-32 encoded bytes to Unicode string.
(data, size, errors, byteorder="little", final=0)
| 534 | |
| 535 | |
| 536 | def PyUnicode_DecodeUTF32Stateful(data, size, errors, byteorder="little", final=0): |
| 537 | """Decode UTF-32 encoded bytes to Unicode string.""" |
| 538 | if size == 0: |
| 539 | return [], 0, 0 |
| 540 | |
| 541 | result = [] |
| 542 | pos = 0 |
| 543 | aligned_size = (size // 4) * 4 |
| 544 | |
| 545 | while pos + 3 < aligned_size: |
| 546 | if byteorder == "little": |
| 547 | ch = ( |
| 548 | data[pos] |
| 549 | | (data[pos + 1] << 8) |
| 550 | | (data[pos + 2] << 16) |
| 551 | | (data[pos + 3] << 24) |
| 552 | ) |
| 553 | else: # big-endian |
| 554 | ch = ( |
| 555 | (data[pos] << 24) |
| 556 | | (data[pos + 1] << 16) |
| 557 | | (data[pos + 2] << 8) |
| 558 | | data[pos + 3] |
| 559 | ) |
| 560 | |
| 561 | # Validate code point |
| 562 | if ch > 0x10FFFF: |
| 563 | if errors == "strict": |
| 564 | raise UnicodeDecodeError( |
| 565 | "utf-32", |
| 566 | bytes(data), |
| 567 | pos, |
| 568 | pos + 4, |
| 569 | "codepoint not in range(0x110000)", |
| 570 | ) |
| 571 | elif errors == "replace": |
| 572 | result.append("\ufffd") |
| 573 | # 'ignore' - skip this character |
| 574 | pos += 4 |
| 575 | elif 0xD800 <= ch <= 0xDFFF: |
| 576 | if errors == "surrogatepass": |
| 577 | result.append(chr(ch)) |
| 578 | pos += 4 |
| 579 | else: |
| 580 | msg = "code point in surrogate code point range(0xd800, 0xe000)" |
| 581 | res, pos = unicode_call_errorhandler( |
| 582 | errors, "utf-32", msg, data, pos, pos + 4, True |
| 583 | ) |
| 584 | result.append(res) |
| 585 | else: |
| 586 | result.append(chr(ch)) |
| 587 | pos += 4 |
| 588 | |
| 589 | # Handle trailing incomplete bytes |
| 590 | if pos < size: |
| 591 | if final: |
| 592 | res, pos = unicode_call_errorhandler( |
| 593 | errors, "utf-32", "truncated data", data, pos, size, True |
no test coverage detected