| 853 | } |
| 854 | |
| 855 | static NODISCARD demangle_status parser_ident(struct parser *parser, struct ident *out) { |
| 856 | bool is_punycode = parser_eat(parser, 'u'); |
| 857 | size_t len; |
| 858 | uint8_t d; |
| 859 | demangle_status status = parser_digit_10(parser, &d); |
| 860 | len = d; |
| 861 | if (status != DemangleOk) { |
| 862 | return status; |
| 863 | } |
| 864 | if (len) { |
| 865 | for (;;) { |
| 866 | status = parser_digit_10(parser, &d); |
| 867 | if (status != DemangleOk) { |
| 868 | break; |
| 869 | } |
| 870 | if (len > SIZE_MAX / 10) { |
| 871 | return DemangleInvalid; |
| 872 | } |
| 873 | len *= 10; |
| 874 | if (len > SIZE_MAX - d) { |
| 875 | return DemangleInvalid; |
| 876 | } |
| 877 | len += d; |
| 878 | } |
| 879 | } |
| 880 | |
| 881 | // Skip past the optional `_` separator. |
| 882 | parser_eat(parser, '_'); |
| 883 | |
| 884 | size_t start = parser->next; |
| 885 | if (parser->sym_len - parser->next < len) { |
| 886 | return DemangleInvalid; |
| 887 | } |
| 888 | parser->next += len; |
| 889 | |
| 890 | const char *ident = &parser->sym[start]; |
| 891 | |
| 892 | if (is_punycode) { |
| 893 | const char *underscore = (const char *)demangle_memrchr(ident, '_', (size_t)len); |
| 894 | if (underscore == NULL) { |
| 895 | *out = (struct ident){ |
| 896 | .ascii_start="", |
| 897 | .ascii_len=0, |
| 898 | .punycode_start=ident, |
| 899 | .punycode_len=len |
| 900 | }; |
| 901 | } else { |
| 902 | size_t ascii_len = underscore - ident; |
| 903 | // ascii_len <= len - 1 since `_` is in the first len bytes |
| 904 | size_t punycode_len = len - 1 - ascii_len; |
| 905 | *out = (struct ident){ |
| 906 | .ascii_start=ident, |
| 907 | .ascii_len=ascii_len, |
| 908 | .punycode_start=underscore + 1, |
| 909 | .punycode_len=punycode_len |
| 910 | }; |
| 911 | } |
| 912 | if (out->punycode_len == 0) { |
nothing calls this directly
no test coverage detected