1*0e209d39SAndroid Build Coastguard Worker // © 2017 and later: Unicode, Inc. and others. 2*0e209d39SAndroid Build Coastguard Worker // License & terms of use: http://www.unicode.org/copyright.html 3*0e209d39SAndroid Build Coastguard Worker 4*0e209d39SAndroid Build Coastguard Worker // bytesinkutil.h 5*0e209d39SAndroid Build Coastguard Worker // created: 2017sep14 Markus W. Scherer 6*0e209d39SAndroid Build Coastguard Worker 7*0e209d39SAndroid Build Coastguard Worker #ifndef BYTESINKUTIL_H 8*0e209d39SAndroid Build Coastguard Worker #define BYTESINKUTIL_H 9*0e209d39SAndroid Build Coastguard Worker 10*0e209d39SAndroid Build Coastguard Worker #include <type_traits> 11*0e209d39SAndroid Build Coastguard Worker 12*0e209d39SAndroid Build Coastguard Worker #include "unicode/utypes.h" 13*0e209d39SAndroid Build Coastguard Worker #include "unicode/bytestream.h" 14*0e209d39SAndroid Build Coastguard Worker #include "unicode/edits.h" 15*0e209d39SAndroid Build Coastguard Worker #include "charstr.h" 16*0e209d39SAndroid Build Coastguard Worker #include "cmemory.h" 17*0e209d39SAndroid Build Coastguard Worker #include "uassert.h" 18*0e209d39SAndroid Build Coastguard Worker #include "ustr_imp.h" 19*0e209d39SAndroid Build Coastguard Worker 20*0e209d39SAndroid Build Coastguard Worker U_NAMESPACE_BEGIN 21*0e209d39SAndroid Build Coastguard Worker 22*0e209d39SAndroid Build Coastguard Worker class ByteSink; 23*0e209d39SAndroid Build Coastguard Worker class Edits; 24*0e209d39SAndroid Build Coastguard Worker 25*0e209d39SAndroid Build Coastguard Worker class U_COMMON_API CharStringByteSink : public ByteSink { 26*0e209d39SAndroid Build Coastguard Worker public: 27*0e209d39SAndroid Build Coastguard Worker CharStringByteSink(CharString* dest); 28*0e209d39SAndroid Build Coastguard Worker ~CharStringByteSink() override; 29*0e209d39SAndroid Build Coastguard Worker 30*0e209d39SAndroid Build Coastguard Worker CharStringByteSink() = delete; 31*0e209d39SAndroid Build Coastguard Worker CharStringByteSink(const CharStringByteSink&) = delete; 32*0e209d39SAndroid Build Coastguard Worker CharStringByteSink& operator=(const CharStringByteSink&) = delete; 33*0e209d39SAndroid Build Coastguard Worker 34*0e209d39SAndroid Build Coastguard Worker void Append(const char* bytes, int32_t n) override; 35*0e209d39SAndroid Build Coastguard Worker 36*0e209d39SAndroid Build Coastguard Worker char* GetAppendBuffer(int32_t min_capacity, 37*0e209d39SAndroid Build Coastguard Worker int32_t desired_capacity_hint, 38*0e209d39SAndroid Build Coastguard Worker char* scratch, 39*0e209d39SAndroid Build Coastguard Worker int32_t scratch_capacity, 40*0e209d39SAndroid Build Coastguard Worker int32_t* result_capacity) override; 41*0e209d39SAndroid Build Coastguard Worker 42*0e209d39SAndroid Build Coastguard Worker private: 43*0e209d39SAndroid Build Coastguard Worker CharString& dest_; 44*0e209d39SAndroid Build Coastguard Worker }; 45*0e209d39SAndroid Build Coastguard Worker 46*0e209d39SAndroid Build Coastguard Worker // CharString doesn't provide the public API that StringByteSink requires a 47*0e209d39SAndroid Build Coastguard Worker // string class to have so this template specialization replaces the default 48*0e209d39SAndroid Build Coastguard Worker // implementation of StringByteSink<CharString> with CharStringByteSink. 49*0e209d39SAndroid Build Coastguard Worker template<> 50*0e209d39SAndroid Build Coastguard Worker class StringByteSink<CharString> : public CharStringByteSink { 51*0e209d39SAndroid Build Coastguard Worker public: StringByteSink(CharString * dest)52*0e209d39SAndroid Build Coastguard Worker StringByteSink(CharString* dest) : CharStringByteSink(dest) { } StringByteSink(CharString * dest,int32_t)53*0e209d39SAndroid Build Coastguard Worker StringByteSink(CharString* dest, int32_t /*initialAppendCapacity*/) : CharStringByteSink(dest) { } 54*0e209d39SAndroid Build Coastguard Worker }; 55*0e209d39SAndroid Build Coastguard Worker 56*0e209d39SAndroid Build Coastguard Worker class U_COMMON_API ByteSinkUtil { 57*0e209d39SAndroid Build Coastguard Worker public: 58*0e209d39SAndroid Build Coastguard Worker ByteSinkUtil() = delete; // all static 59*0e209d39SAndroid Build Coastguard Worker 60*0e209d39SAndroid Build Coastguard Worker /** (length) bytes were mapped to valid (s16, s16Length). */ 61*0e209d39SAndroid Build Coastguard Worker static UBool appendChange(int32_t length, 62*0e209d39SAndroid Build Coastguard Worker const char16_t *s16, int32_t s16Length, 63*0e209d39SAndroid Build Coastguard Worker ByteSink &sink, Edits *edits, UErrorCode &errorCode); 64*0e209d39SAndroid Build Coastguard Worker 65*0e209d39SAndroid Build Coastguard Worker /** The bytes at [s, limit[ were mapped to valid (s16, s16Length). */ 66*0e209d39SAndroid Build Coastguard Worker static UBool appendChange(const uint8_t *s, const uint8_t *limit, 67*0e209d39SAndroid Build Coastguard Worker const char16_t *s16, int32_t s16Length, 68*0e209d39SAndroid Build Coastguard Worker ByteSink &sink, Edits *edits, UErrorCode &errorCode); 69*0e209d39SAndroid Build Coastguard Worker 70*0e209d39SAndroid Build Coastguard Worker /** (length) bytes were mapped/changed to valid code point c. */ 71*0e209d39SAndroid Build Coastguard Worker static void appendCodePoint(int32_t length, UChar32 c, ByteSink &sink, Edits *edits = nullptr); 72*0e209d39SAndroid Build Coastguard Worker 73*0e209d39SAndroid Build Coastguard Worker /** The few bytes at [src, nextSrc[ were mapped/changed to valid code point c. */ 74*0e209d39SAndroid Build Coastguard Worker static inline void appendCodePoint(const uint8_t *src, const uint8_t *nextSrc, UChar32 c, 75*0e209d39SAndroid Build Coastguard Worker ByteSink &sink, Edits *edits = nullptr) { 76*0e209d39SAndroid Build Coastguard Worker appendCodePoint((int32_t)(nextSrc - src), c, sink, edits); 77*0e209d39SAndroid Build Coastguard Worker } 78*0e209d39SAndroid Build Coastguard Worker 79*0e209d39SAndroid Build Coastguard Worker /** Append the two-byte character (U+0080..U+07FF). */ 80*0e209d39SAndroid Build Coastguard Worker static void appendTwoBytes(UChar32 c, ByteSink &sink); 81*0e209d39SAndroid Build Coastguard Worker appendUnchanged(const uint8_t * s,int32_t length,ByteSink & sink,uint32_t options,Edits * edits,UErrorCode & errorCode)82*0e209d39SAndroid Build Coastguard Worker static UBool appendUnchanged(const uint8_t *s, int32_t length, 83*0e209d39SAndroid Build Coastguard Worker ByteSink &sink, uint32_t options, Edits *edits, 84*0e209d39SAndroid Build Coastguard Worker UErrorCode &errorCode) { 85*0e209d39SAndroid Build Coastguard Worker if (U_FAILURE(errorCode)) { return false; } 86*0e209d39SAndroid Build Coastguard Worker if (length > 0) { appendNonEmptyUnchanged(s, length, sink, options, edits); } 87*0e209d39SAndroid Build Coastguard Worker return true; 88*0e209d39SAndroid Build Coastguard Worker } 89*0e209d39SAndroid Build Coastguard Worker 90*0e209d39SAndroid Build Coastguard Worker static UBool appendUnchanged(const uint8_t *s, const uint8_t *limit, 91*0e209d39SAndroid Build Coastguard Worker ByteSink &sink, uint32_t options, Edits *edits, 92*0e209d39SAndroid Build Coastguard Worker UErrorCode &errorCode); 93*0e209d39SAndroid Build Coastguard Worker 94*0e209d39SAndroid Build Coastguard Worker /** 95*0e209d39SAndroid Build Coastguard Worker * Calls a lambda that writes to a ByteSink with a CheckedArrayByteSink 96*0e209d39SAndroid Build Coastguard Worker * and then returns through u_terminateChars(), in order to implement 97*0e209d39SAndroid Build Coastguard Worker * the classic ICU4C C API writing to a fix sized buffer on top of a 98*0e209d39SAndroid Build Coastguard Worker * contemporary C++ API. 99*0e209d39SAndroid Build Coastguard Worker * 100*0e209d39SAndroid Build Coastguard Worker * @param buffer receiving buffer 101*0e209d39SAndroid Build Coastguard Worker * @param capacity capacity of receiving buffer 102*0e209d39SAndroid Build Coastguard Worker * @param lambda that gets called with the sink as an argument 103*0e209d39SAndroid Build Coastguard Worker * @param status set to U_BUFFER_OVERFLOW_ERROR on overflow 104*0e209d39SAndroid Build Coastguard Worker * @return number of bytes written, or needed (in case of overflow) 105*0e209d39SAndroid Build Coastguard Worker * @internal 106*0e209d39SAndroid Build Coastguard Worker */ 107*0e209d39SAndroid Build Coastguard Worker template <typename F, 108*0e209d39SAndroid Build Coastguard Worker typename = std::enable_if_t< 109*0e209d39SAndroid Build Coastguard Worker std::is_invocable_r_v<void, F, ByteSink&, UErrorCode&>>> viaByteSinkToTerminatedChars(char * buffer,int32_t capacity,F && lambda,UErrorCode & status)110*0e209d39SAndroid Build Coastguard Worker static int32_t viaByteSinkToTerminatedChars(char* buffer, int32_t capacity, 111*0e209d39SAndroid Build Coastguard Worker F&& lambda, 112*0e209d39SAndroid Build Coastguard Worker UErrorCode& status) { 113*0e209d39SAndroid Build Coastguard Worker if (U_FAILURE(status)) { return 0; } 114*0e209d39SAndroid Build Coastguard Worker CheckedArrayByteSink sink(buffer, capacity); 115*0e209d39SAndroid Build Coastguard Worker lambda(sink, status); 116*0e209d39SAndroid Build Coastguard Worker if (U_FAILURE(status)) { return 0; } 117*0e209d39SAndroid Build Coastguard Worker 118*0e209d39SAndroid Build Coastguard Worker int32_t reslen = sink.NumberOfBytesAppended(); 119*0e209d39SAndroid Build Coastguard Worker 120*0e209d39SAndroid Build Coastguard Worker if (sink.Overflowed()) { 121*0e209d39SAndroid Build Coastguard Worker status = U_BUFFER_OVERFLOW_ERROR; 122*0e209d39SAndroid Build Coastguard Worker return reslen; 123*0e209d39SAndroid Build Coastguard Worker } 124*0e209d39SAndroid Build Coastguard Worker 125*0e209d39SAndroid Build Coastguard Worker return u_terminateChars(buffer, capacity, reslen, &status); 126*0e209d39SAndroid Build Coastguard Worker } 127*0e209d39SAndroid Build Coastguard Worker 128*0e209d39SAndroid Build Coastguard Worker /** 129*0e209d39SAndroid Build Coastguard Worker * Calls a lambda that writes to a ByteSink with a CharStringByteSink and 130*0e209d39SAndroid Build Coastguard Worker * then returns a CharString, in order to implement a contemporary C++ API 131*0e209d39SAndroid Build Coastguard Worker * on top of a C/C++ compatibility ByteSink API. 132*0e209d39SAndroid Build Coastguard Worker * 133*0e209d39SAndroid Build Coastguard Worker * @param lambda that gets called with the sink as an argument 134*0e209d39SAndroid Build Coastguard Worker * @param status to check and report 135*0e209d39SAndroid Build Coastguard Worker * @return the resulting string, or an empty string (in case of error) 136*0e209d39SAndroid Build Coastguard Worker * @internal 137*0e209d39SAndroid Build Coastguard Worker */ 138*0e209d39SAndroid Build Coastguard Worker template <typename F, 139*0e209d39SAndroid Build Coastguard Worker typename = std::enable_if_t< 140*0e209d39SAndroid Build Coastguard Worker std::is_invocable_r_v<void, F, ByteSink&, UErrorCode&>>> viaByteSinkToCharString(F && lambda,UErrorCode & status)141*0e209d39SAndroid Build Coastguard Worker static CharString viaByteSinkToCharString(F&& lambda, UErrorCode& status) { 142*0e209d39SAndroid Build Coastguard Worker if (U_FAILURE(status)) { return {}; } 143*0e209d39SAndroid Build Coastguard Worker CharString result; 144*0e209d39SAndroid Build Coastguard Worker CharStringByteSink sink(&result); 145*0e209d39SAndroid Build Coastguard Worker lambda(sink, status); 146*0e209d39SAndroid Build Coastguard Worker return result; 147*0e209d39SAndroid Build Coastguard Worker } 148*0e209d39SAndroid Build Coastguard Worker 149*0e209d39SAndroid Build Coastguard Worker private: 150*0e209d39SAndroid Build Coastguard Worker static void appendNonEmptyUnchanged(const uint8_t *s, int32_t length, 151*0e209d39SAndroid Build Coastguard Worker ByteSink &sink, uint32_t options, Edits *edits); 152*0e209d39SAndroid Build Coastguard Worker }; 153*0e209d39SAndroid Build Coastguard Worker 154*0e209d39SAndroid Build Coastguard Worker U_NAMESPACE_END 155*0e209d39SAndroid Build Coastguard Worker 156*0e209d39SAndroid Build Coastguard Worker #endif //BYTESINKUTIL_H 157