text:
// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
*   Copyright (C) 2013-2016, International Business Machines
*   Corporation and others.  All Rights Reserved.
*******************************************************************************
*   file name:  uscript_props.cpp
*   encoding:   UTF-8
*   tab size:   8 (not used)
*   indentation:4
*
*   created on: 2013feb16
*   created by: Markus W. Scherer
*/

#include "unicode/utypes.h"
#include "unicode/unistr.h"
#include "unicode/uscript.h"
#include "unicode/utf16.h"
#include "ustr_imp.h"
#include "cmemory.h"

namespace {

// Script metadata (script properties).
// See http://unicode.org/cldr/trac/browser/trunk/common/properties/scriptMetadata.txt

// 0 = NOT_ENCODED, no sample character, default false script properties.
// Bits 20.. 0: sample character

// Bits 23..21: usage
const int32_t UNKNOWN = 1 << 21;
const int32_t EXCLUSION = 2 << 21;
const int32_t LIMITED_USE = 3 << 21;
// st int32_t ASPIRATIONAL = 4 << 21; -- not used any more since Unicode 10
const int32_t RECOMMENDED = 5 << 21;

// Bits 31..24: Single-bit flags
const int32_t RTL = 1 << 24;
const int32_t LB_LETTERS = 1 << 25;
const int32_t CASED = 1 << 26;

const int32_t SCRIPT_PROPS[] = {
    // Begin copy-paste output from
    // tools/trunk/unicode/py/parsescriptmetadata.py
    0x0040 | RECOMMENDED,  // Zyyy
    0x0308 | RECOMMENDED,  // Zinh
    0x0628 | RECOMMENDED | RTL,  // Arab
    0x0531 | RECOMMENDED | CASED,  // Armn
    0x0995 | RECOMMENDED,  // Beng
    0x3105 | RECOMMENDED | LB_LETTERS,  // Bopo
    0x13C4 | LIMITED_USE | CASED,  // Cher
    0x03E2 | EXCLUSION | CASED,  // Copt
    0x042F | RECOMMENDED | CASED,  // Cyrl
    0x10414 | EXCLUSION | CASED,  // Dsrt
    0x0905 | RECOMMENDED,  // Deva
    0x12A0 | RECOMMENDED,  // Ethi
    0x10D3 | RECOMMENDED,  // Geor
    0x10330 | EXCLUSION,  // Goth
    0x03A9 | RECOMMENDED | CASED,  // Grek
    0x0A95 | RECOMMENDED,  // Gujr
    0x0A15 | RECOMMENDED,  // Guru
    0x5B57 | RECOMMENDED | LB_LETTERS,  // Hani
    0xAC00 | RECOMMENDED,  // Hang
    0x05D0 | RECOMMENDED | RTL,  // Hebr
    0x304B | RECOMMENDED | LB_LETTERS,  // Hira
    0x0C95 | RECOMMENDED,  // Knda
    0x30AB | RECOMMENDED | LB_LETTERS,  // Kana
    0x1780 | RECOMMENDED | LB_LETTERS,  // Khmr
    0x0EA5 | RECOMMENDED | LB_LETTERS,  // Laoo
    0x004C | RECOMMENDED | CASED,  // Latn
    0x0D15 | RECOMMENDED,  // Mlym
    0x1826 | EXCLUSION,  // Mong
    0x1000 | RECOMMENDED | LB_LETTERS,  // Mymr
    0x168F | EXCLUSION,  // Ogam
    0x10300 | EXCLUSION,  // Ital
    0x0B15 | RECOMMENDED,  // Orya
    0x16A0 | EXCLUSION,  // Runr
    0x0D85 | RECOMMENDED,  // Sinh
    0x0710 | LIMITED_USE | RTL,  // Syrc
    0x0B95 | RECOMMENDED,  // Taml
    0x0C15 | RECOMMENDED,  // Telu
    0x078C | RECOMMENDED | RTL,  // Thaa
    0x0E17 | RECOMMENDED | LB_LETTERS,  // Thai
    0x0F40 | RECOMMENDED,  // Tibt
    0x14C0 | LIMITED_USE,  // Cans
    0xA288 | LIMITED_USE | LB_LETTERS,  // Yiii
    0x1703 | EXCLUSION,  // Tglg
    0x1723 | EXCLUSION,  // Hano
    0x1743 | EXCLUSION,  // Buhd
    0x1763 | EXCLUSION,  // Tagb
    0x280E | UNKNOWN,  // Brai
    0x10800 | EXCLUSION | RTL,  // Cprt
    0x1900 | LIMITED_USE,  // Limb
    0x10000 | EXCLUSION,  // Linb
    0x10480 | EXCLUSION,  // Osma
    0x10450 | EXCLUSION,  // Shaw
    0x1950 | LIMITED_USE | LB_LETTERS,  // Tale
    0x10380 | EXCLUSION,  // Ugar
    0,
    0x1A00 | EXCLUSION,  // Bugi
    0x2C00 | EXCLUSION | CASED,  // Glag
    0x10A00 | EXCLUSION | RTL,  // Khar
    0xA800 | LIMITED_USE,  // Sylo
    0x1980 | LIMITED_USE | LB_LETTERS,  // Talu
    0x2D30 | LIMITED_USE,  // Tfng
    0x103A0 | EXCLUSION,  // Xpeo
    0x1B05 | LIMITED_USE,  // Bali
    0x1BC0 | LIMITED_USE,  // Batk
    0,
    0x11005 | EXCLUSION,  // Brah
    0xAA00 | LIMITED_USE,  // Cham
    0,
    0,
    0,
    0,
    0x13153 | EXCLUSION,  // Egyp
    0,
    0x5B57 | RECOMMENDED | LB_LETTERS,  // Hans
    0x5B57 | RECOMMENDED | LB_LETTERS,  // Hant
    0x16B1C | EXCLUSION,  // Hmng
    0x10CA1 | EXCLUSION | RTL | CASED,  // Hung
    0,
    0xA984 | LIMITED_USE,  // Java
    0xA90A | LIMITED_USE,  // Kali
    0,
    0,
    0x1C00 | LIMITED_USE,  // Lepc
    0x10647 | EXCLUSION,  // Lina
    0x0840 | LIMITED_USE | RTL,  // Mand
    0,
    0x10980 | EXCLUSION | RTL,  // Mero
    0x07CA | LIMITED_USE | RTL,  // Nkoo
    0x10C00 | EXCLUSION | RTL,  // Orkh
    0x1036B | EXCLUSION,  // Perm
    0xA840 | EXCLUSION,  // Phag
    0x10900 | EXCLUSION | RTL,  // Phnx
    0x16F00 | LIMITED_USE,  // Plrd
    0,
    0,
    0,
    0,
    0,
    0,
    0xA549 | LIMITED_USE,  // Vaii
    0,
    0x12000 | EXCLUSION,  // Xsux
    0,
    0xFDD0 | UNKNOWN,  // Zzzz
    0x102A0 | EXCLUSION,  // Cari
    0x304B | RECOMMENDED | LB_LETTERS,  // Jpan
    0x1A20 | LIMITED_USE | LB_LETTERS,  // Lana
    0x10280 | EXCLUSION,  // Lyci
    0x10920 | EXCLUSION | RTL,  // Lydi
    0x1C5A | LIMITED_USE,  // Olck
    0xA930 | EXCLUSION,  // Rjng
    0xA882 | LIMITED_USE,  // Saur
    0x1D850 | EXCLUSION,  // Sgnw
    0x1B83 | LIMITED_USE,  // Sund
    0,
    0xABC0 | LIMITED_USE,  // Mtei
    0x10840 | EXCLUSION | RTL,  // Armi
    0x10B00 | EXCLUSION | RTL,  // Avst
    0x11103 | LIMITED_USE,  // Cakm
    0xAC00 | RECOMMENDED,  // Kore
    0x11083 | EXCLUSION,  // Kthi
    0x10AD8 | EXCLUSION | RTL,  // Mani
    0x10B60 | EXCLUSION | RTL,  // Phli
    0x10B8F | EXCLUSION | RTL,  // Phlp
    0,
    0x10B40 | EXCLUSION | RTL,  // Prti
    0x0800 | EXCLUSION | RTL,  // Samr
    0xAA80 | LIMITED_USE | LB_LETTERS,  // Tavt
    0,
    0,
    0xA6A0 | LIMITED_USE,  // Bamu
    0xA4D0 | LIMITED_USE,  // Lisu
    0,
    0x10A60 | EXCLUSION | RTL,  // Sarb
    0x16AE6 | EXCLUSION,  // Bass
    0x1BC20 | EXCLUSION,  // Dupl
    0x10500 | EXCLUSION,  // Elba
    0x11315 | EXCLUSION,  // Gran
    0,
    0,
    0x1E802 | EXCLUSION | RTL,  // Mend
    0x109A0 | EXCLUSION | RTL,  // Merc
    0x10A95 | EXCLUSION | RTL,  // Narb
    0x10896 | EXCLUSION | RTL,  // Nbat
    0x10873 | EXCLUSION | RTL,  // Palm
    0x112BE | EXCLUSION,  // Sind
    0x118B4 | EXCLUSION | CASED,  // Wara
    0,
    0,
    0x16A4F | EXCLUSION,  // Mroo
    0x1B1C4 | EXCLUSION | LB_LETTERS,  // Nshu
    0x11183 | EXCLUSION,  // Shrd
    0x110D0 | EXCLUSION,  // Sora
    0x11680 | EXCLUSION,  // Takr
    0x18229 | EXCLUSION | LB_LETTERS,  // Tang
    0,
    0x14400 | EXCLUSION,  // Hluw
    0x11208 | EXCLUSION,  // Khoj
    0x11484 | EXCLUSION,  // Tirh
    0x10537 | EXCLUSION,  // Aghb
    0x11152 | EXCLUSION,  // Mahj
    0x11717 | EXCLUSION | LB_LETTERS,  // Ahom
    0x108F4 | EXCLUSION | RTL,  // Hatr
    0x1160E | EXCLUSION,  // Modi
    0x1128F | EXCLUSION,  // Mult
    0x11AC0 | EXCLUSION,  // Pauc
    0x1158E | EXCLUSION,  // Sidd
    0x1E909 | LIMITED_USE | RTL | CASED,  // Adlm
    0x11C0E | EXCLUSION,  // Bhks
    0x11C72 | EXCLUSION,  // Marc
    0x11412 | LIMITED_USE,  // Newa
    0x104B5 | LIMITED_USE | CASED,  // Osge
    0x5B57 | RECOMMENDED | LB_LETTERS,  // Hanb
    0x1112 | RECOMMENDED,  // Jamo
    0,
    0x11D10 | EXCLUSION,  // Gonm
    0x11A5C | EXCLUSION,  // Soyo
    0x11A0B | EXCLUSION,  // Zanb
    0x1180B | EXCLUSION,  // Dogr
    0x11D71 | LIMITED_USE,  // Gong
    0x11EE5 | EXCLUSION,  // Maka
    0x16E40 | EXCLUSION | CASED,  // Medf
    0x10D12 | LIMITED_USE | RTL,  // Rohg
    0x10F42 | EXCLUSION | RTL,  // Sogd
    0x10F19 | EXCLUSION | RTL,  // Sogo
    0x10FF1 | EXCLUSION | RTL,  // Elym
    0x1E108 | LIMITED_USE,  // Hmnp
    0x119CE | EXCLUSION,  // Nand
    0x1E2E1 | LIMITED_USE,  // Wcho
    0x10FBF | EXCLUSION | RTL,  // Chrs
    0x1190C | EXCLUSION,  // Diak
    0x18C65 | EXCLUSION | LB_LETTERS,  // Kits
    0x10E88 | EXCLUSION | RTL,  // Yezi
    // End copy-paste from parsescriptmetadata.py
};

int32_t getScriptProps(UScriptCode script) {
    if (0 <= script && script < UPRV_LENGTHOF(SCRIPT_PROPS)) {
        return SCRIPT_PROPS[script];
    } else {
        return 0;
    }
}

}  // namespace

U_CAPI int32_t U_EXPORT2
uscript_getSampleString(UScriptCode script, UChar *dest, int32_t capacity, UErrorCode *pErrorCode) {
    if(U_FAILURE(*pErrorCode)) { return 0; }
    if(capacity < 0 || (capacity > 0 && dest == NULL)) {
        *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
        return 0;
    }
    int32_t sampleChar = getScriptProps(script) & 0x1fffff;
    int32_t length;
    if(sampleChar == 0) {
        length = 0;
    } else {
        length = U16_LENGTH(sampleChar);
        if(length <= capacity) {
            int32_t i = 0;
            U16_APPEND_UNSAFE(dest, i, sampleChar);
        }
    }
    return u_terminateUChars(dest, capacity, length, pErrorCode);
}

U_COMMON_API icu::UnicodeString U_EXPORT2
uscript_getSampleUnicodeString(UScriptCode script) {
    icu::UnicodeString sample;
    int32_t sampleChar = getScriptProps(script) & 0x1fffff;
    if(sampleChar != 0) {
        sample.append(sampleChar);
    }
    return sample;
}

U_CAPI UScriptUsage U_EXPORT2
uscript_getUsage(UScriptCode script) {
    return (UScriptUsage)((getScriptProps(script) >> 21) & 7);
}

U_CAPI UBool U_EXPORT2
uscript_isRightToLeft(UScriptCode script) {
    return (getScriptProps(script) & RTL) != 0;
}

U_CAPI UBool U_EXPORT2
uscript_breaksBetweenLetters(UScriptCode script) {
    return (getScriptProps(script) & LB_LETTERS) != 0;
}

U_CAPI UBool U_EXPORT2
uscript_isCased(UScriptCode script) {
    return (getScriptProps(script) & CASED) != 0;
}


text:
// © 2017 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html

// bytesinkutil.cpp
// created: 2017sep14 Markus W. Scherer

#include "unicode/utypes.h"
#include "unicode/bytestream.h"
#include "unicode/edits.h"
#include "unicode/stringoptions.h"
#include "unicode/utf8.h"
#include "unicode/utf16.h"
#include "bytesinkutil.h"
#include "charstr.h"
#include "cmemory.h"
#include "uassert.h"

U_NAMESPACE_BEGIN

UBool
ByteSinkUtil::appendChange(int32_t length, const char16_t *s16, int32_t s16Length,
                           ByteSink &sink, Edits *edits, UErrorCode &errorCode) {
    if (U_FAILURE(errorCode)) { return FALSE; }
    char scratch[200];
    int32_t s8Length = 0;
    for (int32_t i = 0; i < s16Length;) {
        int32_t capacity;
        int32_t desiredCapacity = s16Length - i;
        if (desiredCapacity < (INT32_MAX / 3)) {
            desiredCapacity *= 3;  // max 3 UTF-8 bytes per UTF-16 code unit
        } else if (desiredCapacity < (INT32_MAX / 2)) {
            desiredCapacity *= 2;
        } else {
            desiredCapacity = INT32_MAX;
        }
        char *buffer = sink.GetAppendBuffer(U8_MAX_LENGTH, desiredCapacity,
                                            scratch, UPRV_LENGTHOF(scratch), &capacity);
        capacity -= U8_MAX_LENGTH - 1;
        int32_t j = 0;
        for (; i < s16Length && j < capacity;) {
            UChar32 c;
            U16_NEXT_UNSAFE(s16, i, c);
            U8_APPEND_UNSAFE(buffer, j, c);
        }
        if (j > (INT32_MAX - s8Length)) {
            errorCode = U_INDEX_OUTOFBOUNDS_ERROR;
            return FALSE;
        }
        sink.Append(buffer, j);
        s8Length += j;
    }
    if (edits != nullptr) {
        edits->addReplace(length, s8Length);
    }
    return TRUE;
}

UBool
ByteSinkUtil::appendChange(const uint8_t *s, const uint8_t *limit,
                           const char16_t *s16, int32_t s16Length,
                           ByteSink &sink, Edits *edits, UErrorCode &errorCode) {
    if (U_FAILURE(errorCode)) { return FALSE; }
    if ((limit - s) > INT32_MAX) {
        errorCode = U_INDEX_OUTOFBOUNDS_ERROR;
        return FALSE;
    }
    return appendChange((int32_t)(limit - s), s16, s16Length, sink, edits, errorCode);
}

void
ByteSinkUtil::appendCodePoint(int32_t length, UChar32 c, ByteSink &sink, Edits *edits) {
    char s8[U8_MAX_LENGTH];
    int32_t s8Length = 0;
    U8_APPEND_UNSAFE(s8, s8Length, c);
    if (edits != nullptr) {
        edits->addReplace(length, s8Length);
    }
    sink.Append(s8, s8Length);
}

namespace {

// See unicode/utf8.h U8_APPEND_UNSAFE().
inline uint8_t getTwoByteLead(UChar32 c) { return (uint8_t)((c >> 6) | 0xc0); }
inline uint8_t getTwoByteTrail(UChar32 c) { return (uint8_t)((c & 0x3f) | 0x80); }

}  // namespace

void
ByteSinkUtil::appendTwoBytes(UChar32 c, ByteSink &sink) {
    U_ASSERT(0x80 <= c && c <= 0x7ff);  // 2-byte UTF-8
    char s8[2] = { (char)getTwoByteLead(c), (char)getTwoByteTrail(c) };
    sink.Append(s8, 2);
}

void
ByteSinkUtil::appendNonEmptyUnchanged(const uint8_t *s, int32_t length,
                                      ByteSink &sink, uint32_t options, Edits *edits) {
    U_ASSERT(length > 0);
    if (edits != nullptr) {
        edits->addUnchanged(length);
    }
    if ((options & U_OMIT_UNCHANGED_TEXT) == 0) {
        sink.Append(reinterpret_cast<const char *>(s), length);
    }
}

UBool
ByteSinkUtil::appendUnchanged(const uint8_t *s, const uint8_t *limit,
                              ByteSink &sink, uint32_t options, Edits *edits,
                              UErrorCode &errorCode) {
    if (U_FAILURE(errorCode)) { return FALSE; }
    if ((limit - s) > INT32_MAX) {
        errorCode = U_INDEX_OUTOFBOUNDS_ERROR;
        return FALSE;
    }
    int32_t length = (int32_t)(limit - s);
    if (length > 0) {
        appendNonEmptyUnchanged(s, length, sink, options, edits);
    }
    return TRUE;
}

CharStringByteSink::CharStringByteSink(CharString* dest) : dest_(*dest) {
}

CharStringByteSink::~CharStringByteSink() = default;

void
CharStringByteSink::Append(const char* bytes, int32_t n) {
    UErrorCode status = U_ZERO_ERROR;
    dest_.append(bytes, n, status);
    // Any errors are silently ignored.
}

char*
CharStringByteSink::GetAppendBuffer(int32_t min_capacity,
                                    int32_t desired_capacity_hint,
                                    char* scratch,
                                    int32_t scratch_capacity,
                                    int32_t* result_capacity) {
    if (min_capacity < 1 || scratch_capacity < min_capacity) {
        *result_capacity = 0;
        return nullptr;
    }

    UErrorCode status = U_ZERO_ERROR;
    char* result = dest_.getAppendBuffer(
            min_capacity,
            desired_capacity_hint,
            *result_capacity,
            status);
    if (U_SUCCESS(status)) {
        return result;
    }

    *result_capacity = scratch_capacity;
    return scratch;
}

U_NAMESPACE_END

repo_language: C

mime_type: text/x-c


text:
// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
*   Copyright (C) 1999-2011, International Business Machines
*   Corporation and others.  All Rights Reserved.
**********************************************************************
*
*   ucnv_cnv.h:
*   Definitions for converter implementations.
*
* Modification History:
*
*   Date        Name        Description
*   05/09/00    helena      Added implementation to handle fallback mappings.
*   06/29/2000  helena      Major rewrite of the callback APIs.
*/

#ifndef UCNV_CNV_H
#define UCNV_CNV_H

#include "unicode/utypes.h"

#if !UCONFIG_NO_CONVERSION

#include "unicode/ucnv.h"
#include "unicode/ucnv_err.h"
#include "unicode/uset.h"
#include "uset_imp.h"

U_CDECL_BEGIN

/* this is used in fromUnicode DBCS tables as an "unassigned" marker */
#define missingCharMarker 0xFFFF

/*
 * #define missingUCharMarker 0xfffe
 *
 * commented out because there are actually two values used in toUnicode tables:
 * U+fffe "unassigned"
 * U+ffff "illegal"
 */

/** Forward declaration, see ucnv_bld.h */
struct UConverterSharedData;
typedef struct UConverterSharedData UConverterSharedData;

/* function types for UConverterImpl ---------------------------------------- */

/* struct with arguments for UConverterLoad and ucnv_load() */
typedef struct {
    int32_t size;               /* sizeof(UConverterLoadArgs) */
    int32_t nestedLoads;        /* count nested ucnv_load() calls */
    UBool onlyTestIsLoadable;   /* input: don't actually load */
    UBool reserved0;            /* reserved - for good alignment of the pointers */
    int16_t reserved;           /* reserved - for good alignment of the pointers */
    uint32_t options;
    const char *pkg, *name, *locale;
} UConverterLoadArgs;

#define UCNV_LOAD_ARGS_INITIALIZER \
    { (int32_t)sizeof(UConverterLoadArgs), 0, FALSE, FALSE, 0, 0, NULL, NULL, NULL }

typedef void (*UConverterLoad) (UConverterSharedData *sharedData,
                                UConverterLoadArgs *pArgs,
                                const uint8_t *raw, UErrorCode *pErrorCode);
typedef void (*UConverterUnload) (UConverterSharedData *sharedData);

typedef void (*UConverterOpen) (UConverter *cnv, UConverterLoadArgs *pArgs, UErrorCode *pErrorCode);
typedef void (*UConverterClose) (UConverter *cnv);

typedef enum UConverterResetChoice {
    UCNV_RESET_BOTH,
    UCNV_RESET_TO_UNICODE,
    UCNV_RESET_FROM_UNICODE
} UConverterResetChoice;

typedef void (*UConverterReset) (UConverter *cnv, UConverterResetChoice choice);

/*
 * Converter implementation function(s) for ucnv_toUnicode().
 * If the toUnicodeWithOffsets function pointer is NULL,
 * then the toUnicode function will be used and the offsets will be set to -1.
 *
 * Must maintain state across buffers. Use toUBytes[toULength] for partial input
 * sequences; it will be checked in ucnv.c at the end of the input stream
 * to detect truncated input.
 * Some converters may need additional detection and may then set U_TRUNCATED_CHAR_FOUND.
 *
 * The toUnicodeWithOffsets must write exactly as many offset values as target
 * units. Write offset values of -1 for when the source index corresponding to
 * the output unit is not known (e.g., the character started in an earlier buffer).
 * The pArgs->offsets pointer need not be moved forward.
 *
 * At function return, either one of the following conditions must be true:
 * - U_BUFFER_OVERFLOW_ERROR and the target is full: target==targetLimit
 * - another error code with toUBytes[toULength] set to the offending input
 * - no error, and the source is consumed: source==sourceLimit
 *
 * The ucnv.c code will handle the end of the input (reset)
 * (reset, and truncation detection) and callbacks.
 */
typedef void (*UConverterToUnicode) (UConverterToUnicodeArgs *, UErrorCode *);

/*
 * Same rules as for UConverterToUnicode.
 * A lead surrogate is kept in fromUChar32 across buffers, and if an error
 * occurs, then the offending input code point must be put into fromUChar32
 * as well.
 */
typedef void (*UConverterFromUnicode) (UConverterFromUnicodeArgs *, UErrorCode *);

/*
 * Converter implementation function for ucnv_convertEx(), for direct conversion
 * between two charsets without pivoting through UTF-16.
 * The rules are the same as for UConverterToUnicode and UConverterFromUnicode.
 * In addition,
 * - The toUnicode side must behave and keep state exactly like the
 *   UConverterToUnicode implementation for the same source charset.
 * - A U_USING_DEFAULT_WARNING can be set to request to temporarily fall back
 *   to pivoting. When this function is called, the conversion framework makes
 *   sure that this warning is not set on input.
 * - Continuing a partial match and flushing the toUnicode replay buffer
 *   are handled by pivoting, using the toUnicode and fromUnicode functions.
 */
typedef void (*UConverterConvert) (UConverterFromUnicodeArgs *pFromUArgs,
                                   UConverterToUnicodeArgs *pToUArgs,
                                   UErrorCode *pErrorCode);

/*
 * Converter implementation function for ucnv_getNextUChar().
 * If the function pointer is NULL, then the toUnicode function will be used.
 *
 * Will be called at a character boundary (toULength==0).
 * May return with
 * - U_INDEX_OUTOFBOUNDS_ERROR if there was no output for the input
 *   (the return value will be ignored)
 * - U_TRUNCATED_CHAR_FOUND or another error code (never U_BUFFER_OVERFLOW_ERROR!)
 *   with toUBytes[toULength] set to the offending input
 *   (the return value will be ignored)
 * - return UCNV_GET_NEXT_UCHAR_USE_TO_U, without moving the source pointer,
 *   to indicate that the ucnv.c code shall call the toUnicode function instead
 * - return a real code point result
 *
 * Unless UCNV_GET_NEXT_UCHAR_USE_TO_U is returned, the source bytes must be consumed.
 *
 * The ucnv.c code will handle the end of the input (reset)
 * (except for truncation detection!) and callbacks.
 */
typedef UChar32 (*UConverterGetNextUChar) (UConverterToUnicodeArgs *, UErrorCode *);

typedef void (*UConverterGetStarters)(const UConverter* converter,
                                      UBool starters[256],
                                      UErrorCode *pErrorCode);

/* If this function pointer is null or if the function returns null
 * the name field in static data struct should be returned by
 * ucnv_getName() API function
 */
typedef const char * (*UConverterGetName) (const UConverter *cnv);

/**
 * Write the codepage substitution character.
 * If this function is not set, then ucnv_cbFromUWriteSub() writes
 * the substitution character from UConverter.
 * For stateful converters, it is typically necessary to handle this
 * specificially for the converter in order to properly maintain the state.
 */
typedef void (*UConverterWriteSub) (UConverterFromUnicodeArgs *pArgs, int32_t offsetIndex, UErrorCode *pErrorCode);

/**
 * For converter-specific safeClone processing
 * If this function is not set, then ucnv_safeClone assumes that the converter has no private data that changes
 * after the converter is done opening.
 * If this function is set, then it is called just after a memcpy() of
 * converter data to the new, empty converter, and is expected to set up
 * the initial state of the converter.  It is not expected to increment the
 * reference counts of the standard data types such as the shared data.
 */
typedef UConverter * (*UConverterSafeClone) (const UConverter   *cnv,
                                             void               *stackBuffer,
                                             int32_t            *pBufferSize,
                                             UErrorCode         *status);

/**
 * Filters for some ucnv_getUnicodeSet() implementation code.
 */
typedef enum UConverterSetFilter {
    UCNV_SET_FILTER_NONE,
    UCNV_SET_FILTER_DBCS_ONLY,
    UCNV_SET_FILTER_2022_CN,
    UCNV_SET_FILTER_SJIS,
    UCNV_SET_FILTER_GR94DBCS,
    UCNV_SET_FILTER_HZ,
    UCNV_SET_FILTER_COUNT
} UConverterSetFilter;

/**
 * Fills the set of Unicode code points that can be converted by an ICU converter.
 * The API function ucnv_getUnicodeSet() clears the USet before calling
 * the converter's getUnicodeSet() implementation; the converter should only
 * add the appropriate code points to allow recursive use.
 * For example, the ISO-2022-JP converter will call each subconverter's
 * getUnicodeSet() implementation to consecutively add code points to
 * the same USet, which will result in a union of the sets of all subconverters.
 *
 * For more documentation, see ucnv_getUnicodeSet() in ucnv.h.
 */
typedef void (*UConverterGetUnicodeSet) (const UConverter *cnv,
                                         const USetAdder *sa,
                                         UConverterUnicodeSet which,
                                         UErrorCode *pErrorCode);

UBool CONVERSION_U_SUCCESS (UErrorCode err);

/**
 * UConverterImpl contains all the data and functions for a converter type.
 * Its function pointers work much like a C++ vtable.
 * Many converter types need to define only a subset of the functions;
 * when a function pointer is NULL, then a default action will be performed.
 *
 * Every converter type must implement toUnicode, fromUnicode, and getNextUChar,
 * otherwise the converter may crash.
 * Every converter type that has variable-length codepage sequences should
 * also implement toUnicodeWithOffsets and fromUnicodeWithOffsets for
 * correct offset handling.
 * All other functions may or may not be implemented - it depends only on
 * whether the converter type needs them.
 *
 * When open() fails, then close() will be called, if present.
 */
struct UConverterImpl {
    UConverterType type;

    UConverterLoad load;
    UConverterUnload unload;

    UConverterOpen open;
    UConverterClose close;
    UConverterReset reset;

    UConverterToUnicode toUnicode;
    UConverterToUnicode toUnicodeWithOffsets;
    UConverterFromUnicode fromUnicode;
    UConverterFromUnicode fromUnicodeWithOffsets;
    UConverterGetNextUChar getNextUChar;

    UConverterGetStarters getStarters;
    UConverterGetName getName;
    UConverterWriteSub writeSub;
    UConverterSafeClone safeClone;
    UConverterGetUnicodeSet getUnicodeSet;

    UConverterConvert toUTF8;
    UConverterConvert fromUTF8;
};

extern const UConverterSharedData
    _MBCSData, _Latin1Data,
    _UTF8Data, _UTF16BEData, _UTF16LEData, _UTF32BEData, _UTF32LEData,
    _ISO2022Data,
    _LMBCSData1,_LMBCSData2, _LMBCSData3, _LMBCSData4, _LMBCSData5, _LMBCSData6,
    _LMBCSData8,_LMBCSData11,_LMBCSData16,_LMBCSData17,_LMBCSData18,_LMBCSData19,
    _HZData,_ISCIIData, _SCSUData, _ASCIIData,
    _UTF7Data, _Bocu1Data, _UTF16Data, _UTF32Data, _CESU8Data, _IMAPData, _CompoundTextData;

U_CDECL_END

/** Always use fallbacks from codepage to Unicode */
#define TO_U_USE_FALLBACK(useFallback) TRUE
#define UCNV_TO_U_USE_FALLBACK(cnv) TRUE

/** Use fallbacks from Unicode to codepage when cnv->useFallback or for private-use code points */
#define IS_PRIVATE_USE(c) ((uint32_t)((c)-0xe000)<0x1900 || (uint32_t)((c)-0xf0000)<0x20000)
#define FROM_U_USE_FALLBACK(useFallback, c) ((useFallback) || IS_PRIVATE_USE(c))
#define UCNV_FROM_U_USE_FALLBACK(cnv, c) FROM_U_USE_FALLBACK((cnv)->useFallback, c)

/**
 * Magic number for ucnv_getNextUChar(), returned by a
 * getNextUChar() implementation to indicate to use the converter's toUnicode()
 * instead of the native function.
 * @internal
 */
#define UCNV_GET_NEXT_UCHAR_USE_TO_U -9

U_CFUNC void
ucnv_getCompleteUnicodeSet(const UConverter *cnv,
                   const USetAdder *sa,
                   UConverterUnicodeSet which,
                   UErrorCode *pErrorCode);

U_CFUNC void
ucnv_getNonSurrogateUnicodeSet(const UConverter *cnv,
                               const USetAdder *sa,
                               UConverterUnicodeSet which,
                               UErrorCode *pErrorCode);

U_CFUNC void
ucnv_fromUWriteBytes(UConverter *cnv,
                     const char *bytes, int32_t length,
                     char **target, const char *targetLimit,
                     int32_t **offsets,
                     int32_t sourceIndex,
                     UErrorCode *pErrorCode);
U_CFUNC void
ucnv_toUWriteUChars(UConverter *cnv,
                    const UChar *uchars, int32_t length,
                    UChar **target, const UChar *targetLimit,
                    int32_t **offsets,
                    int32_t sourceIndex,
                    UErrorCode *pErrorCode);

U_CFUNC void
ucnv_toUWriteCodePoint(UConverter *cnv,
                       UChar32 c,
                       UChar **target, const UChar *targetLimit,
                       int32_t **offsets,
                       int32_t sourceIndex,
                       UErrorCode *pErrorCode);

#endif

#endif /* UCNV_CNV */


text:
// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
*
*   Copyright (C) 1997-2016, International Business Machines
*   Corporation and others.  All Rights Reserved.
*
******************************************************************************
*
* File umutex.cpp
*
* Modification History:
*
*   Date        Name        Description
*   04/02/97    aliu        Creation.
*   04/07/99    srl         updated
*   05/13/99    stephen     Changed to umutex (from cmutex).
*   11/22/99    aliu        Make non-global mutex autoinitialize [j151]
******************************************************************************
*/

#include "umutex.h"

#include "unicode/utypes.h"
#include "uassert.h"
#include "ucln_cmn.h"
#include "cmemory.h"

U_NAMESPACE_BEGIN

#if defined(U_USER_MUTEX_CPP)
// Support for including an alternate implementation of mutexes has been withdrawn.
// See issue ICU-20185.
#error U_USER_MUTEX_CPP not supported
#endif

/*************************************************************************************************
 *
 *  ICU Mutex wrappers.
 *
 *************************************************************************************************/

namespace {
std::mutex *initMutex;
std::condition_variable *initCondition;

// The ICU global mutex.
// Used when ICU implementation code passes nullptr for the mutex pointer.
UMutex globalMutex;

std::once_flag initFlag;
std::once_flag *pInitFlag = &initFlag;

}  // Anonymous namespace

U_CDECL_BEGIN
static UBool U_CALLCONV umtx_cleanup() {
    initMutex->~mutex();
    initCondition->~condition_variable();
    UMutex::cleanup();

    // Reset the once_flag, by destructing it and creating a fresh one in its place.
    // Do not use this trick anywhere else in ICU; use umtx_initOnce, not std::call_once().
    pInitFlag->~once_flag();
    pInitFlag = new(&initFlag) std::once_flag();
    return true;
}

static void U_CALLCONV umtx_init() {
    initMutex = STATIC_NEW(std::mutex);
    initCondition = STATIC_NEW(std::condition_variable);
    ucln_common_registerCleanup(UCLN_COMMON_MUTEX, umtx_cleanup);
}
U_CDECL_END

std::mutex *UMutex::getMutex() {
    std::mutex *retPtr = fMutex.load(std::memory_order_acquire);
    if (retPtr == nullptr) {
        std::call_once(*pInitFlag, umtx_init);
        std::lock_guard<std::mutex> guard(*initMutex);
        retPtr = fMutex.load(std::memory_order_acquire);
        if (retPtr == nullptr) {
            fMutex = new(fStorage) std::mutex();
            retPtr = fMutex;
            fListLink = gListHead;
            gListHead = this;
        }
    }
    U_ASSERT(retPtr != nullptr);
    return retPtr;
}

UMutex *UMutex::gListHead = nullptr;

void UMutex::cleanup() {
    UMutex *next = nullptr;
    for (UMutex *m = gListHead; m != nullptr; m = next) {
        (*m->fMutex).~mutex();
        m->fMutex = nullptr;
        next = m->fListLink;
        m->fListLink = nullptr;
    }
    gListHead = nullptr;
}

U_CAPI void  U_EXPORT2
umtx_lock(UMutex *mutex) {
    if (mutex == nullptr) {
        mutex = &globalMutex;
    }
    mutex->lock();
}

U_CAPI void  U_EXPORT2
umtx_unlock(UMutex* mutex)
{
    if (mutex == nullptr) {
        mutex = &globalMutex;
    }
    mutex->unlock();
}

/*************************************************************************************************
 *
 *  UInitOnce Implementation
 *
 *************************************************************************************************/

// This function is called when a test of a UInitOnce::fState reveals that
//   initialization has not completed, that we either need to call the init
//   function on this thread, or wait for some other thread to complete.
//
// The actual call to the init function is made inline by template code
//   that knows the C++ types involved. This function returns true if
//   the caller needs to call the Init function.
//
U_COMMON_API UBool U_EXPORT2
umtx_initImplPreInit(UInitOnce &uio) {
    std::call_once(*pInitFlag, umtx_init);
    std::unique_lock<std::mutex> lock(*initMutex);
    if (umtx_loadAcquire(uio.fState) == 0) {
        umtx_storeRelease(uio.fState, 1);
        return true;      // Caller will next call the init function.
    } else {
        while (umtx_loadAcquire(uio.fState) == 1) {
            // Another thread is currently running the initialization.
            // Wait until it completes.
            initCondition->wait(lock);
        }
        U_ASSERT(uio.fState == 2);
        return false;
    }
}

// This function is called by the thread that ran an initialization function,
// just after completing the function.
//   Some threads may be waiting on the condition, requiring the broadcast wakeup.
//   Some threads may be racing to test the fState variable outside of the mutex,
//   requiring the use of store/release when changing its value.

U_COMMON_API void U_EXPORT2
umtx_initImplPostInit(UInitOnce &uio) {
    {
        std::unique_lock<std::mutex> lock(*initMutex);
        umtx_storeRelease(uio.fState, 2);
    }
    initCondition->notify_all();
}

U_NAMESPACE_END

/*************************************************************************************************
 *
 *  Deprecated functions for setting user mutexes.
 *
 *************************************************************************************************/

U_DEPRECATED void U_EXPORT2
u_setMutexFunctions(const void * /*context */, UMtxInitFn *, UMtxFn *,
                    UMtxFn *,  UMtxFn *, UErrorCode *status) {
    if (U_SUCCESS(*status)) {
        *status = U_UNSUPPORTED_ERROR;
    }
    return;
}

U_DEPRECATED void U_EXPORT2
u_setAtomicIncDecFunctions(const void * /*context */, UMtxAtomicFn *, UMtxAtomicFn *,
                           UErrorCode *status) {
    if (U_SUCCESS(*status)) {
        *status = U_UNSUPPORTED_ERROR;
    }
    return;
}


text:
// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
 ************************************************************************************
 * Copyright (C) 2006-2016, International Business Machines Corporation
 * and others. All Rights Reserved.
 ************************************************************************************
 */

#include "unicode/utypes.h"

#if !UCONFIG_NO_BREAK_ITERATION

#include "unicode/uchar.h"
#include "unicode/uniset.h"
#include "unicode/chariter.h"
#include "unicode/ures.h"
#include "unicode/udata.h"
#include "unicode/putil.h"
#include "unicode/ustring.h"
#include "unicode/uscript.h"
#include "unicode/ucharstrie.h"
#include "unicode/bytestrie.h"

#include "brkeng.h"
#include "cmemory.h"
#include "dictbe.h"
#include "charstr.h"
#include "dictionarydata.h"
#include "mutex.h"
#include "uvector.h"
#include "umutex.h"
#include "uresimp.h"
#include "ubrkimpl.h"

U_NAMESPACE_BEGIN

/*
 ******************************************************************
 */

LanguageBreakEngine::LanguageBreakEngine() {
}

LanguageBreakEngine::~LanguageBreakEngine() {
}

/*
 ******************************************************************
 */

LanguageBreakFactory::LanguageBreakFactory() {
}

LanguageBreakFactory::~LanguageBreakFactory() {
}

/*
 ******************************************************************
 */

UnhandledEngine::UnhandledEngine(UErrorCode &status) : fHandled(nullptr) {
    (void)status;
}

UnhandledEngine::~UnhandledEngine() {
    delete fHandled;
    fHandled = nullptr;
}

UBool
UnhandledEngine::handles(UChar32 c) const {
    return fHandled && fHandled->contains(c);
}

int32_t
UnhandledEngine::findBreaks( UText *text,
                             int32_t /* startPos */,
                             int32_t endPos,
                             UVector32 &/*foundBreaks*/ ) const {
    UChar32 c = utext_current32(text);
    while((int32_t)utext_getNativeIndex(text) < endPos && fHandled->contains(c)) {
        utext_next32(text);            // TODO:  recast loop to work with post-increment operations.
        c = utext_current32(text);
    }
    return 0;
}

void
UnhandledEngine::handleCharacter(UChar32 c) {
    if (fHandled == nullptr) {
        fHandled = new UnicodeSet();
        if (fHandled == nullptr) {
            return;
        }
    }
    if (!fHandled->contains(c)) {
        UErrorCode status = U_ZERO_ERROR;
        // Apply the entire script of the character.
        int32_t script = u_getIntPropertyValue(c, UCHAR_SCRIPT);
        fHandled->applyIntPropertyValue(UCHAR_SCRIPT, script, status);
    }
}

/*
 ******************************************************************
 */

ICULanguageBreakFactory::ICULanguageBreakFactory(UErrorCode &/*status*/) {
    fEngines = 0;
}

ICULanguageBreakFactory::~ICULanguageBreakFactory() {
    if (fEngines != 0) {
        delete fEngines;
    }
}

U_NAMESPACE_END
U_CDECL_BEGIN
static void U_CALLCONV _deleteEngine(void *obj) {
    delete (const icu::LanguageBreakEngine *) obj;
}
U_CDECL_END
U_NAMESPACE_BEGIN

const LanguageBreakEngine *
ICULanguageBreakFactory::getEngineFor(UChar32 c) {
    const LanguageBreakEngine *lbe = NULL;
    UErrorCode  status = U_ZERO_ERROR;

    static UMutex gBreakEngineMutex;
    Mutex m(&gBreakEngineMutex);

    if (fEngines == NULL) {
        UStack  *engines = new UStack(_deleteEngine, NULL, status);
        if (U_FAILURE(status) || engines == NULL) {
            // Note: no way to return error code to caller.
            delete engines;
            return NULL;
        }
        fEngines = engines;
    } else {
        int32_t i = fEngines->size();
        while (--i >= 0) {
            lbe = (const LanguageBreakEngine *)(fEngines->elementAt(i));
            if (lbe != NULL && lbe->handles(c)) {
                return lbe;
            }
        }
    }

    // We didn't find an engine. Create one.
    lbe = loadEngineFor(c);
    if (lbe != NULL) {
        fEngines->push((void *)lbe, status);
    }
    return lbe;
}

const LanguageBreakEngine *
ICULanguageBreakFactory::loadEngineFor(UChar32 c) {
    UErrorCode status = U_ZERO_ERROR;
    UScriptCode code = uscript_getScript(c, &status);
    if (U_SUCCESS(status)) {
        DictionaryMatcher *m = loadDictionaryMatcherFor(code);
        if (m != NULL) {
            const LanguageBreakEngine *engine = NULL;
            switch(code) {
            case USCRIPT_THAI:
                engine = new ThaiBreakEngine(m, status);
                break;
            case USCRIPT_LAO:
                engine = new LaoBreakEngine(m, status);
                break;
            case USCRIPT_MYANMAR:
                engine = new BurmeseBreakEngine(m, status);
                break;
            case USCRIPT_KHMER:
                engine = new KhmerBreakEngine(m, status);
                break;

#if !UCONFIG_NO_NORMALIZATION
                // CJK not available w/o normalization
            case USCRIPT_HANGUL:
                engine = new CjkBreakEngine(m, kKorean, status);
                break;

            // use same BreakEngine and dictionary for both Chinese and Japanese
            case USCRIPT_HIRAGANA:
            case USCRIPT_KATAKANA:
            case USCRIPT_HAN:
                engine = new CjkBreakEngine(m, kChineseJapanese, status);
                break;
#if 0
            // TODO: Have to get some characters with script=common handled
            // by CjkBreakEngine (e.g. U+309B). Simply subjecting
            // them to CjkBreakEngine does not work. The engine has to
            // special-case them.
            case USCRIPT_COMMON:
            {
                UBlockCode block = ublock_getCode(code);
                if (block == UBLOCK_HIRAGANA || block == UBLOCK_KATAKANA)
                   engine = new CjkBreakEngine(dict, kChineseJapanese, status);
                break;
            }
#endif
#endif

            default:
                break;
            }
            if (engine == NULL) {
                delete m;
            }
            else if (U_FAILURE(status)) {
                delete engine;
                engine = NULL;
            }
            return engine;
        }
    }
    return NULL;
}

DictionaryMatcher *
ICULanguageBreakFactory::loadDictionaryMatcherFor(UScriptCode script) {
    UErrorCode status = U_ZERO_ERROR;
    // open root from brkitr tree.
    UResourceBundle *b = ures_open(U_ICUDATA_BRKITR, "", &status);
    b = ures_getByKeyWithFallback(b, "dictionaries", b, &status);
    int32_t dictnlength = 0;
    const UChar *dictfname =
        ures_getStringByKeyWithFallback(b, uscript_getShortName(script), &dictnlength, &status);
    if (U_FAILURE(status)) {
        ures_close(b);
        return NULL;
    }
    CharString dictnbuf;
    CharString ext;
    const UChar *extStart = u_memrchr(dictfname, 0x002e, dictnlength);  // last dot
    if (extStart != NULL) {
        int32_t len = (int32_t)(extStart - dictfname);
        ext.appendInvariantChars(UnicodeString(FALSE, extStart + 1, dictnlength - len - 1), status);
        dictnlength = len;
    }
    dictnbuf.appendInvariantChars(UnicodeString(FALSE, dictfname, dictnlength), status);
    ures_close(b);

    UDataMemory *file = udata_open(U_ICUDATA_BRKITR, ext.data(), dictnbuf.data(), &status);
    if (U_SUCCESS(status)) {
        // build trie
        const uint8_t *data = (const uint8_t *)udata_getMemory(file);
        const int32_t *indexes = (const int32_t *)data;
        const int32_t offset = indexes[DictionaryData::IX_STRING_TRIE_OFFSET];
        const int32_t trieType = indexes[DictionaryData::IX_TRIE_TYPE] & DictionaryData::TRIE_TYPE_MASK;
        DictionaryMatcher *m = NULL;
        if (trieType == DictionaryData::TRIE_TYPE_BYTES) {
            const int32_t transform = indexes[DictionaryData::IX_TRANSFORM];
            const char *characters = (const char *)(data + offset);
            m = new BytesDictionaryMatcher(characters, transform, file);
        }
        else if (trieType == DictionaryData::TRIE_TYPE_UCHARS) {
            const UChar *characters = (const UChar *)(data + offset);
            m = new UCharsDictionaryMatcher(characters, file);
        }
        if (m == NULL) {
            // no matcher exists to take ownership - either we are an invalid
            // type or memory allocation failed
            udata_close(file);
        }
        return m;
    } else if (dictfname != NULL) {
        // we don't have a dictionary matcher.
        // returning NULL here will cause us to fail to find a dictionary break engine, as expected
        status = U_ZERO_ERROR;
        return NULL;
    }
    return NULL;
}

U_NAMESPACE_END

#endif /* #if !UCONFIG_NO_BREAK_ITERATION */


text:
// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
// Copyright (C) 2009-2011, International Business Machines
// Corporation and others. All Rights Reserved.
//
// Copyright 2007 Google Inc. All Rights Reserved.
// Author: sanjay@google.com (Sanjay Ghemawat)

#include "unicode/utypes.h"
#include "unicode/bytestream.h"
#include "cmemory.h"

U_NAMESPACE_BEGIN

ByteSink::~ByteSink() {}

char* ByteSink::GetAppendBuffer(int32_t min_capacity,
                                int32_t /*desired_capacity_hint*/,
                                char* scratch, int32_t scratch_capacity,
                                int32_t* result_capacity) {
  if (min_capacity < 1 || scratch_capacity < min_capacity) {
    *result_capacity = 0;
    return NULL;
  }
  *result_capacity = scratch_capacity;
  return scratch;
}

void ByteSink::Flush() {}

CheckedArrayByteSink::CheckedArrayByteSink(char* outbuf, int32_t capacity)
    : outbuf_(outbuf), capacity_(capacity < 0 ? 0 : capacity),
      size_(0), appended_(0), overflowed_(FALSE) {
}

CheckedArrayByteSink::~CheckedArrayByteSink() {}

CheckedArrayByteSink& CheckedArrayByteSink::Reset() {
  size_ = appended_ = 0;
  overflowed_ = FALSE;
  return *this;
}

void CheckedArrayByteSink::Append(const char* bytes, int32_t n) {
  if (n <= 0) {
    return;
  }
  if (n > (INT32_MAX - appended_)) {
    // TODO: Report as integer overflow, not merely buffer overflow.
    appended_ = INT32_MAX;
    overflowed_ = TRUE;
    return;
  }
  appended_ += n;
  int32_t available = capacity_ - size_;
  if (n > available) {
    n = available;
    overflowed_ = TRUE;
  }
  if (n > 0 && bytes != (outbuf_ + size_)) {
    uprv_memcpy(outbuf_ + size_, bytes, n);
  }
  size_ += n;
}

char* CheckedArrayByteSink::GetAppendBuffer(int32_t min_capacity,
                                            int32_t /*desired_capacity_hint*/,
                                            char* scratch,
                                            int32_t scratch_capacity,
                                            int32_t* result_capacity) {
  if (min_capacity < 1 || scratch_capacity < min_capacity) {
    *result_capacity = 0;
    return NULL;
  }
  int32_t available = capacity_ - size_;
  if (available >= min_capacity) {
    *result_capacity = available;
    return outbuf_ + size_;
  } else {
    *result_capacity = scratch_capacity;
    return scratch;
  }
}

U_NAMESPACE_END