1 // © 2017 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
5 // created: 2017sep14 Markus W. Scherer
7 #include "unicode/utypes.h"
8 #include "unicode/bytestream.h"
9 #include "unicode/edits.h"
10 #include "unicode/stringoptions.h"
11 #include "unicode/utf8.h"
12 #include "unicode/utf16.h"
13 #include "bytesinkutil.h"
21 ByteSinkUtil::appendChange(int32_t length
, const char16_t *s16
, int32_t s16Length
,
22 ByteSink
&sink
, Edits
*edits
, UErrorCode
&errorCode
) {
23 if (U_FAILURE(errorCode
)) { return FALSE
; }
26 for (int32_t i
= 0; i
< s16Length
;) {
28 int32_t desiredCapacity
= s16Length
- i
;
29 if (desiredCapacity
< (INT32_MAX
/ 3)) {
30 desiredCapacity
*= 3; // max 3 UTF-8 bytes per UTF-16 code unit
31 } else if (desiredCapacity
< (INT32_MAX
/ 2)) {
34 desiredCapacity
= INT32_MAX
;
36 char *buffer
= sink
.GetAppendBuffer(U8_MAX_LENGTH
, desiredCapacity
,
37 scratch
, UPRV_LENGTHOF(scratch
), &capacity
);
38 capacity
-= U8_MAX_LENGTH
- 1;
40 for (; i
< s16Length
&& j
< capacity
;) {
42 U16_NEXT_UNSAFE(s16
, i
, c
);
43 U8_APPEND_UNSAFE(buffer
, j
, c
);
45 if (j
> (INT32_MAX
- s8Length
)) {
46 errorCode
= U_INDEX_OUTOFBOUNDS_ERROR
;
49 sink
.Append(buffer
, j
);
52 if (edits
!= nullptr) {
53 edits
->addReplace(length
, s8Length
);
59 ByteSinkUtil::appendChange(const uint8_t *s
, const uint8_t *limit
,
60 const char16_t *s16
, int32_t s16Length
,
61 ByteSink
&sink
, Edits
*edits
, UErrorCode
&errorCode
) {
62 if (U_FAILURE(errorCode
)) { return FALSE
; }
63 if ((limit
- s
) > INT32_MAX
) {
64 errorCode
= U_INDEX_OUTOFBOUNDS_ERROR
;
67 return appendChange((int32_t)(limit
- s
), s16
, s16Length
, sink
, edits
, errorCode
);
71 ByteSinkUtil::appendCodePoint(int32_t length
, UChar32 c
, ByteSink
&sink
, Edits
*edits
) {
72 char s8
[U8_MAX_LENGTH
];
74 U8_APPEND_UNSAFE(s8
, s8Length
, c
);
75 if (edits
!= nullptr) {
76 edits
->addReplace(length
, s8Length
);
78 sink
.Append(s8
, s8Length
);
83 // See unicode/utf8.h U8_APPEND_UNSAFE().
84 inline uint8_t getTwoByteLead(UChar32 c
) { return (uint8_t)((c
>> 6) | 0xc0); }
85 inline uint8_t getTwoByteTrail(UChar32 c
) { return (uint8_t)((c
& 0x3f) | 0x80); }
90 ByteSinkUtil::appendTwoBytes(UChar32 c
, ByteSink
&sink
) {
91 U_ASSERT(0x80 <= c
&& c
<= 0x7ff); // 2-byte UTF-8
92 char s8
[2] = { (char)getTwoByteLead(c
), (char)getTwoByteTrail(c
) };
97 ByteSinkUtil::appendNonEmptyUnchanged(const uint8_t *s
, int32_t length
,
98 ByteSink
&sink
, uint32_t options
, Edits
*edits
) {
100 if (edits
!= nullptr) {
101 edits
->addUnchanged(length
);
103 if ((options
& U_OMIT_UNCHANGED_TEXT
) == 0) {
104 sink
.Append(reinterpret_cast<const char *>(s
), length
);
109 ByteSinkUtil::appendUnchanged(const uint8_t *s
, const uint8_t *limit
,
110 ByteSink
&sink
, uint32_t options
, Edits
*edits
,
111 UErrorCode
&errorCode
) {
112 if (U_FAILURE(errorCode
)) { return FALSE
; }
113 if ((limit
- s
) > INT32_MAX
) {
114 errorCode
= U_INDEX_OUTOFBOUNDS_ERROR
;
117 int32_t length
= (int32_t)(limit
- s
);
119 appendNonEmptyUnchanged(s
, length
, sink
, options
, edits
);
124 CharStringByteSink::CharStringByteSink(CharString
* dest
) : dest_(*dest
) {
127 CharStringByteSink::~CharStringByteSink() = default;
130 CharStringByteSink::Append(const char* bytes
, int32_t n
) {
131 UErrorCode status
= U_ZERO_ERROR
;
132 dest_
.append(bytes
, n
, status
);
133 // Any errors are silently ignored.
137 CharStringByteSink::GetAppendBuffer(int32_t min_capacity
,
138 int32_t desired_capacity_hint
,
140 int32_t scratch_capacity
,
141 int32_t* result_capacity
) {
142 if (min_capacity
< 1 || scratch_capacity
< min_capacity
) {
143 *result_capacity
= 0;
147 UErrorCode status
= U_ZERO_ERROR
;
148 char* result
= dest_
.getAppendBuffer(
150 desired_capacity_hint
,
153 if (U_SUCCESS(status
)) {
157 *result_capacity
= scratch_capacity
;