We follow Oracle semantics for offset: - If position is positive, then the first glyph in the substring is determined by counting that many glyphs forward from the beginning of the input. (i.e., for position == 1 the first glyph in the substring will be identical to the first glyph in the input) - If position is negative, then the first glyph in the substring is determined by counting that m
| 771 | - If position is 0 then it is treated as 1. |
| 772 | */ |
| 773 | FORCE_INLINE |
| 774 | const char* substr_utf8_int64_int64(gdv_int64 context, const char* input, |
| 775 | gdv_int32 in_data_len, gdv_int64 position, |
| 776 | gdv_int64 substring_length, gdv_int32* out_data_len) { |
| 777 | if (substring_length <= 0 || input == nullptr || in_data_len <= 0) { |
| 778 | *out_data_len = 0; |
| 779 | return ""; |
| 780 | } |
| 781 | |
| 782 | gdv_int64 in_glyphs_count = |
| 783 | static_cast<gdv_int64>(utf8_length(context, input, in_data_len)); |
| 784 | |
| 785 | // in_glyphs_count is zero if input has invalid glyphs |
| 786 | if (in_glyphs_count == 0) { |
| 787 | *out_data_len = 0; |
| 788 | return ""; |
| 789 | } |
| 790 | |
| 791 | gdv_int64 from_glyph; // from_glyph==0 indicates the first glyph of the input |
| 792 | if (position > 0) { |
| 793 | from_glyph = position - 1; |
| 794 | } else if (position < 0) { |
| 795 | from_glyph = in_glyphs_count + position; |
| 796 | } else { |
| 797 | from_glyph = 0; |
| 798 | } |
| 799 | |
| 800 | if (from_glyph < 0 || from_glyph >= in_glyphs_count) { |
| 801 | *out_data_len = 0; |
| 802 | return ""; |
| 803 | } |
| 804 | |
| 805 | gdv_int64 out_glyphs_count = substring_length; |
| 806 | if (substring_length > in_glyphs_count - from_glyph) { |
| 807 | out_glyphs_count = in_glyphs_count - from_glyph; |
| 808 | } |
| 809 | |
| 810 | gdv_int64 in_data_len64 = static_cast<gdv_int64>(in_data_len); |
| 811 | gdv_int64 start_pos = 0; |
| 812 | gdv_int64 end_pos = in_data_len64; |
| 813 | |
| 814 | gdv_int64 current_glyph = 0; |
| 815 | gdv_int64 pos = 0; |
| 816 | while (pos < in_data_len64) { |
| 817 | if (current_glyph == from_glyph) { |
| 818 | start_pos = pos; |
| 819 | } |
| 820 | pos += static_cast<gdv_int64>(utf8_char_length(input[pos])); |
| 821 | if (current_glyph - from_glyph + 1 == out_glyphs_count) { |
| 822 | end_pos = pos; |
| 823 | } |
| 824 | current_glyph++; |
| 825 | } |
| 826 | |
| 827 | if (end_pos > in_data_len64 || end_pos > INT_MAX) { |
| 828 | end_pos = in_data_len64; |
| 829 | } |
| 830 |