Path: blob/master/thirdparty/icu4c/common/bytesinkutil.cpp
9902 views
// © 2017 and later: Unicode, Inc. and others.1// License & terms of use: http://www.unicode.org/copyright.html23// bytesinkutil.cpp4// created: 2017sep14 Markus W. Scherer56#include "unicode/utypes.h"7#include "unicode/bytestream.h"8#include "unicode/edits.h"9#include "unicode/stringoptions.h"10#include "unicode/utf8.h"11#include "unicode/utf16.h"12#include "bytesinkutil.h"13#include "charstr.h"14#include "cmemory.h"15#include "uassert.h"1617U_NAMESPACE_BEGIN1819UBool20ByteSinkUtil::appendChange(int32_t length, const char16_t *s16, int32_t s16Length,21ByteSink &sink, Edits *edits, UErrorCode &errorCode) {22if (U_FAILURE(errorCode)) { return false; }23char scratch[200];24int32_t s8Length = 0;25for (int32_t i = 0; i < s16Length;) {26int32_t capacity;27int32_t desiredCapacity = s16Length - i;28if (desiredCapacity < (INT32_MAX / 3)) {29desiredCapacity *= 3; // max 3 UTF-8 bytes per UTF-16 code unit30} else if (desiredCapacity < (INT32_MAX / 2)) {31desiredCapacity *= 2;32} else {33desiredCapacity = INT32_MAX;34}35char *buffer = sink.GetAppendBuffer(U8_MAX_LENGTH, desiredCapacity,36scratch, UPRV_LENGTHOF(scratch), &capacity);37capacity -= U8_MAX_LENGTH - 1;38int32_t j = 0;39for (; i < s16Length && j < capacity;) {40UChar32 c;41U16_NEXT_UNSAFE(s16, i, c);42U8_APPEND_UNSAFE(buffer, j, c);43}44if (j > (INT32_MAX - s8Length)) {45errorCode = U_INDEX_OUTOFBOUNDS_ERROR;46return false;47}48sink.Append(buffer, j);49s8Length += j;50}51if (edits != nullptr) {52edits->addReplace(length, s8Length);53}54return true;55}5657UBool58ByteSinkUtil::appendChange(const uint8_t *s, const uint8_t *limit,59const char16_t *s16, int32_t s16Length,60ByteSink &sink, Edits *edits, UErrorCode &errorCode) {61if (U_FAILURE(errorCode)) { return false; }62if ((limit - s) > INT32_MAX) {63errorCode = U_INDEX_OUTOFBOUNDS_ERROR;64return false;65}66return appendChange(static_cast<int32_t>(limit - s), s16, s16Length, sink, edits, errorCode);67}6869void70ByteSinkUtil::appendCodePoint(int32_t length, UChar32 c, ByteSink &sink, Edits *edits) {71char s8[U8_MAX_LENGTH];72int32_t s8Length = 0;73U8_APPEND_UNSAFE(s8, s8Length, c);74if (edits != nullptr) {75edits->addReplace(length, s8Length);76}77sink.Append(s8, s8Length);78}7980namespace {8182// See unicode/utf8.h U8_APPEND_UNSAFE().83inline uint8_t getTwoByteLead(UChar32 c) { return static_cast<uint8_t>((c >> 6) | 0xc0); }84inline uint8_t getTwoByteTrail(UChar32 c) { return static_cast<uint8_t>((c & 0x3f) | 0x80); }8586} // namespace8788void89ByteSinkUtil::appendTwoBytes(UChar32 c, ByteSink &sink) {90U_ASSERT(0x80 <= c && c <= 0x7ff); // 2-byte UTF-891char s8[2] = {static_cast<char>(getTwoByteLead(c)), static_cast<char>(getTwoByteTrail(c))};92sink.Append(s8, 2);93}9495void96ByteSinkUtil::appendNonEmptyUnchanged(const uint8_t *s, int32_t length,97ByteSink &sink, uint32_t options, Edits *edits) {98U_ASSERT(length > 0);99if (edits != nullptr) {100edits->addUnchanged(length);101}102if ((options & U_OMIT_UNCHANGED_TEXT) == 0) {103sink.Append(reinterpret_cast<const char *>(s), length);104}105}106107UBool108ByteSinkUtil::appendUnchanged(const uint8_t *s, const uint8_t *limit,109ByteSink &sink, uint32_t options, Edits *edits,110UErrorCode &errorCode) {111if (U_FAILURE(errorCode)) { return false; }112if ((limit - s) > INT32_MAX) {113errorCode = U_INDEX_OUTOFBOUNDS_ERROR;114return false;115}116int32_t length = static_cast<int32_t>(limit - s);117if (length > 0) {118appendNonEmptyUnchanged(s, length, sink, options, edits);119}120return true;121}122123CharStringByteSink::CharStringByteSink(CharString* dest) : dest_(*dest) {124}125126CharStringByteSink::~CharStringByteSink() = default;127128void129CharStringByteSink::Append(const char* bytes, int32_t n) {130UErrorCode status = U_ZERO_ERROR;131dest_.append(bytes, n, status);132// Any errors are silently ignored.133}134135char*136CharStringByteSink::GetAppendBuffer(int32_t min_capacity,137int32_t desired_capacity_hint,138char* scratch,139int32_t scratch_capacity,140int32_t* result_capacity) {141if (min_capacity < 1 || scratch_capacity < min_capacity) {142*result_capacity = 0;143return nullptr;144}145146UErrorCode status = U_ZERO_ERROR;147char* result = dest_.getAppendBuffer(148min_capacity,149desired_capacity_hint,150*result_capacity,151status);152if (U_SUCCESS(status)) {153return result;154}155156*result_capacity = scratch_capacity;157return scratch;158}159160U_NAMESPACE_END161162163