| 204 | } |
| 205 | |
| 206 | void TruncateUTF8ToByteSize(const std::string& input, |
| 207 | const size_t byte_size, |
| 208 | std::string* output) { |
| 209 | DCHECK(output); |
| 210 | if (byte_size > input.length()) { |
| 211 | *output = input; |
| 212 | return; |
| 213 | } |
| 214 | DCHECK_LE(byte_size, static_cast<uint32_t>(kint32max)); |
| 215 | // Note: This cast is necessary because CBU8_NEXT uses int32s. |
| 216 | int32_t truncation_length = static_cast<int32_t>(byte_size); |
| 217 | int32_t char_index = truncation_length - 1; |
| 218 | const char* data = input.data(); |
| 219 | |
| 220 | // Using CBU8, we will move backwards from the truncation point |
| 221 | // to the beginning of the string looking for a valid UTF8 |
| 222 | // character. Once a full UTF8 character is found, we will |
| 223 | // truncate the string to the end of that character. |
| 224 | while (char_index >= 0) { |
| 225 | int32_t prev = char_index; |
| 226 | uint32_t code_point = 0; |
| 227 | CBU8_NEXT(data, char_index, truncation_length, code_point); |
| 228 | if (!IsValidCharacter(code_point) || |
| 229 | !IsValidCodepoint(code_point)) { |
| 230 | char_index = prev - 1; |
| 231 | } else { |
| 232 | break; |
| 233 | } |
| 234 | } |
| 235 | |
| 236 | if (char_index >= 0 ) |
| 237 | *output = input.substr(0, char_index); |
| 238 | else |
| 239 | output->clear(); |
| 240 | } |
| 241 | |
| 242 | TrimPositions TrimWhitespace(const string16& input, |
| 243 | TrimPositions positions, |