Convert an utf8 string to its corresponding uppercase string
| 287 | |
| 288 | // Convert an utf8 string to its corresponding uppercase string |
| 289 | GANDIVA_EXPORT |
| 290 | const char* gdv_fn_upper_utf8(int64_t context, const char* data, int32_t data_len, |
| 291 | int32_t* out_len) { |
| 292 | if (data_len == 0) { |
| 293 | *out_len = 0; |
| 294 | return ""; |
| 295 | } |
| 296 | |
| 297 | // If it is a single-byte character (ASCII), corresponding uppercase is always 1-byte |
| 298 | // long; if it is >= 2 bytes long, uppercase can be at most 4 bytes long, so length of |
| 299 | // the output can be at most twice the length of the input |
| 300 | char* out = reinterpret_cast<char*>(gdv_fn_context_arena_malloc(context, 2 * data_len)); |
| 301 | if (out == nullptr) { |
| 302 | gdv_fn_context_set_error_msg(context, "Could not allocate memory for output string"); |
| 303 | *out_len = 0; |
| 304 | return ""; |
| 305 | } |
| 306 | |
| 307 | int32_t char_len, out_char_len, out_idx = 0; |
| 308 | uint32_t char_codepoint; |
| 309 | |
| 310 | for (int32_t i = 0; i < data_len; i += char_len) { |
| 311 | char_len = gdv_fn_utf8_char_length(data[i]); |
| 312 | // For single byte characters: |
| 313 | // If it is a lowercase ASCII character, set the output to its corresponding uppercase |
| 314 | // character; else, set the output to the read character |
| 315 | if (char_len == 1) { |
| 316 | char cur = data[i]; |
| 317 | // 'A' - 'Z' : 0x41 - 0x5a |
| 318 | // 'a' - 'z' : 0x61 - 0x7a |
| 319 | if (cur >= 0x61 && cur <= 0x7a) { |
| 320 | out[out_idx++] = static_cast<char>(cur - 0x20); |
| 321 | } else { |
| 322 | out[out_idx++] = cur; |
| 323 | } |
| 324 | continue; |
| 325 | } |
| 326 | |
| 327 | // Control reaches here when we encounter a multibyte character |
| 328 | const auto* in_char = (const uint8_t*)(data + i); |
| 329 | |
| 330 | // Decode the multibyte character |
| 331 | bool is_valid_utf8_char = |
| 332 | arrow::util::UTF8Decode((const uint8_t**)&in_char, &char_codepoint); |
| 333 | |
| 334 | // If it is an invalid utf8 character, UTF8Decode evaluates to false |
| 335 | if (!is_valid_utf8_char) { |
| 336 | gdv_fn_set_error_for_invalid_utf8(context, data[i]); |
| 337 | *out_len = 0; |
| 338 | return ""; |
| 339 | } |
| 340 | |
| 341 | // Convert the encoded codepoint to its uppercase codepoint |
| 342 | int32_t upper_codepoint = utf8proc_toupper(char_codepoint); |
| 343 | |
| 344 | // UTF8Encode advances the pointer by the number of bytes present in the uppercase |
| 345 | // character |
| 346 | auto* out_char = (uint8_t*)(out + out_idx); |