12e5b6d6dSopenharmony_ci// © 2016 and later: Unicode, Inc. and others.
22e5b6d6dSopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html
32e5b6d6dSopenharmony_ci/*
42e5b6d6dSopenharmony_ci**********************************************************************
52e5b6d6dSopenharmony_ci*   Copyright (C) 2002-2016, International Business Machines
62e5b6d6dSopenharmony_ci*   Corporation and others.  All Rights Reserved.
72e5b6d6dSopenharmony_ci**********************************************************************
82e5b6d6dSopenharmony_ci*   file name:  ucnv_u7.c
92e5b6d6dSopenharmony_ci*   encoding:   UTF-8
102e5b6d6dSopenharmony_ci*   tab size:   8 (not used)
112e5b6d6dSopenharmony_ci*   indentation:4
122e5b6d6dSopenharmony_ci*
132e5b6d6dSopenharmony_ci*   created on: 2002jul01
142e5b6d6dSopenharmony_ci*   created by: Markus W. Scherer
152e5b6d6dSopenharmony_ci*
162e5b6d6dSopenharmony_ci*   UTF-7 converter implementation. Used to be in ucnv_utf.c.
172e5b6d6dSopenharmony_ci*/
182e5b6d6dSopenharmony_ci
192e5b6d6dSopenharmony_ci#include "unicode/utypes.h"
202e5b6d6dSopenharmony_ci
212e5b6d6dSopenharmony_ci#if !UCONFIG_NO_CONVERSION && !UCONFIG_ONLY_HTML_CONVERSION
222e5b6d6dSopenharmony_ci
232e5b6d6dSopenharmony_ci#include "cmemory.h"
242e5b6d6dSopenharmony_ci#include "unicode/ucnv.h"
252e5b6d6dSopenharmony_ci#include "ucnv_bld.h"
262e5b6d6dSopenharmony_ci#include "ucnv_cnv.h"
272e5b6d6dSopenharmony_ci#include "uassert.h"
282e5b6d6dSopenharmony_ci
292e5b6d6dSopenharmony_ci/* UTF-7 -------------------------------------------------------------------- */
302e5b6d6dSopenharmony_ci
312e5b6d6dSopenharmony_ci/*
322e5b6d6dSopenharmony_ci * UTF-7 is a stateful encoding of Unicode.
332e5b6d6dSopenharmony_ci * It is defined in RFC 2152. (http://www.ietf.org/rfc/rfc2152.txt)
342e5b6d6dSopenharmony_ci * It was intended for use in Internet email systems, using in its bytewise
352e5b6d6dSopenharmony_ci * encoding only a subset of 7-bit US-ASCII.
362e5b6d6dSopenharmony_ci * UTF-7 is deprecated in favor of UTF-8/16/32 and SCSU, but still
372e5b6d6dSopenharmony_ci * occasionally used.
382e5b6d6dSopenharmony_ci *
392e5b6d6dSopenharmony_ci * For converting Unicode to UTF-7, the RFC allows to encode some US-ASCII
402e5b6d6dSopenharmony_ci * characters directly or in base64. Especially, the characters in set O
412e5b6d6dSopenharmony_ci * as defined in the RFC (see below) may be encoded directly but are not
422e5b6d6dSopenharmony_ci * allowed in, e.g., email headers.
432e5b6d6dSopenharmony_ci * By default, the ICU UTF-7 converter encodes set O directly.
442e5b6d6dSopenharmony_ci * By choosing the option "version=1", set O will be escaped instead.
452e5b6d6dSopenharmony_ci * For example:
462e5b6d6dSopenharmony_ci *     utf7Converter=ucnv_open("UTF-7,version=1");
472e5b6d6dSopenharmony_ci *
482e5b6d6dSopenharmony_ci * For details about email headers see RFC 2047.
492e5b6d6dSopenharmony_ci */
502e5b6d6dSopenharmony_ci
512e5b6d6dSopenharmony_ci/*
522e5b6d6dSopenharmony_ci * Tests for US-ASCII characters belonging to character classes
532e5b6d6dSopenharmony_ci * defined in UTF-7.
542e5b6d6dSopenharmony_ci *
552e5b6d6dSopenharmony_ci * Set D (directly encoded characters) consists of the following
562e5b6d6dSopenharmony_ci * characters: the upper and lower case letters A through Z
572e5b6d6dSopenharmony_ci * and a through z, the 10 digits 0-9, and the following nine special
582e5b6d6dSopenharmony_ci * characters (note that "+" and "=" are omitted):
592e5b6d6dSopenharmony_ci *     '(),-./:?
602e5b6d6dSopenharmony_ci *
612e5b6d6dSopenharmony_ci * Set O (optional direct characters) consists of the following
622e5b6d6dSopenharmony_ci * characters (note that "\" and "~" are omitted):
632e5b6d6dSopenharmony_ci *     !"#$%&*;<=>@[]^_`{|}
642e5b6d6dSopenharmony_ci *
652e5b6d6dSopenharmony_ci * According to the rules in RFC 2152, the byte values for the following
662e5b6d6dSopenharmony_ci * US-ASCII characters are not used in UTF-7 and are therefore illegal:
672e5b6d6dSopenharmony_ci * - all C0 control codes except for CR LF TAB
682e5b6d6dSopenharmony_ci * - BACKSLASH
692e5b6d6dSopenharmony_ci * - TILDE
702e5b6d6dSopenharmony_ci * - DEL
712e5b6d6dSopenharmony_ci * - all codes beyond US-ASCII, i.e. all >127
722e5b6d6dSopenharmony_ci */
732e5b6d6dSopenharmony_ci#define inSetD(c) \
742e5b6d6dSopenharmony_ci    ((uint8_t)((c)-97)<26 || (uint8_t)((c)-65)<26 || /* letters */ \
752e5b6d6dSopenharmony_ci     (uint8_t)((c)-48)<10 ||    /* digits */ \
762e5b6d6dSopenharmony_ci     (uint8_t)((c)-39)<3 ||     /* '() */ \
772e5b6d6dSopenharmony_ci     (uint8_t)((c)-44)<4 ||     /* ,-./ */ \
782e5b6d6dSopenharmony_ci     (c)==58 || (c)==63         /* :? */ \
792e5b6d6dSopenharmony_ci    )
802e5b6d6dSopenharmony_ci
812e5b6d6dSopenharmony_ci#define inSetO(c) \
822e5b6d6dSopenharmony_ci    ((uint8_t)((c)-33)<6 ||         /* !"#$%& */ \
832e5b6d6dSopenharmony_ci     (uint8_t)((c)-59)<4 ||         /* ;<=> */ \
842e5b6d6dSopenharmony_ci     (uint8_t)((c)-93)<4 ||         /* ]^_` */ \
852e5b6d6dSopenharmony_ci     (uint8_t)((c)-123)<3 ||        /* {|} */ \
862e5b6d6dSopenharmony_ci     (c)==42 || (c)==64 || (c)==91  /* *@[ */ \
872e5b6d6dSopenharmony_ci    )
882e5b6d6dSopenharmony_ci
892e5b6d6dSopenharmony_ci#define isCRLFTAB(c) ((c)==13 || (c)==10 || (c)==9)
902e5b6d6dSopenharmony_ci#define isCRLFSPTAB(c) ((c)==32 || (c)==13 || (c)==10 || (c)==9)
912e5b6d6dSopenharmony_ci
922e5b6d6dSopenharmony_ci#define PLUS  43
932e5b6d6dSopenharmony_ci#define MINUS 45
942e5b6d6dSopenharmony_ci#define BACKSLASH 92
952e5b6d6dSopenharmony_ci#define TILDE 126
962e5b6d6dSopenharmony_ci
972e5b6d6dSopenharmony_ci/* legal byte values: all US-ASCII graphic characters from space to before tilde, and CR LF TAB */
982e5b6d6dSopenharmony_ci#define isLegalUTF7(c) (((uint8_t)((c)-32)<94 && (c)!=BACKSLASH) || isCRLFTAB(c))
992e5b6d6dSopenharmony_ci
1002e5b6d6dSopenharmony_ci/* encode directly sets D and O and CR LF SP TAB */
1012e5b6d6dSopenharmony_cistatic const UBool encodeDirectlyMaximum[128]={
1022e5b6d6dSopenharmony_ci /* 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
1032e5b6d6dSopenharmony_ci    0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
1042e5b6d6dSopenharmony_ci    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1052e5b6d6dSopenharmony_ci
1062e5b6d6dSopenharmony_ci    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,
1072e5b6d6dSopenharmony_ci    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1082e5b6d6dSopenharmony_ci
1092e5b6d6dSopenharmony_ci    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1102e5b6d6dSopenharmony_ci    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
1112e5b6d6dSopenharmony_ci
1122e5b6d6dSopenharmony_ci    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1132e5b6d6dSopenharmony_ci    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0
1142e5b6d6dSopenharmony_ci};
1152e5b6d6dSopenharmony_ci
1162e5b6d6dSopenharmony_ci/* encode directly set D and CR LF SP TAB but not set O */
1172e5b6d6dSopenharmony_cistatic const UBool encodeDirectlyRestricted[128]={
1182e5b6d6dSopenharmony_ci /* 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
1192e5b6d6dSopenharmony_ci    0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
1202e5b6d6dSopenharmony_ci    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1212e5b6d6dSopenharmony_ci
1222e5b6d6dSopenharmony_ci    1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1,
1232e5b6d6dSopenharmony_ci    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
1242e5b6d6dSopenharmony_ci
1252e5b6d6dSopenharmony_ci    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1262e5b6d6dSopenharmony_ci    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1272e5b6d6dSopenharmony_ci
1282e5b6d6dSopenharmony_ci    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1292e5b6d6dSopenharmony_ci    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
1302e5b6d6dSopenharmony_ci};
1312e5b6d6dSopenharmony_ci
1322e5b6d6dSopenharmony_cistatic const uint8_t
1332e5b6d6dSopenharmony_citoBase64[64]={
1342e5b6d6dSopenharmony_ci    /* A-Z */
1352e5b6d6dSopenharmony_ci    65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
1362e5b6d6dSopenharmony_ci    78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
1372e5b6d6dSopenharmony_ci    /* a-z */
1382e5b6d6dSopenharmony_ci    97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
1392e5b6d6dSopenharmony_ci    110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
1402e5b6d6dSopenharmony_ci    /* 0-9 */
1412e5b6d6dSopenharmony_ci    48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
1422e5b6d6dSopenharmony_ci    /* +/ */
1432e5b6d6dSopenharmony_ci    43, 47
1442e5b6d6dSopenharmony_ci};
1452e5b6d6dSopenharmony_ci
1462e5b6d6dSopenharmony_cistatic const int8_t
1472e5b6d6dSopenharmony_cifromBase64[128]={
1482e5b6d6dSopenharmony_ci    /* C0 controls, -1 for legal ones (CR LF TAB), -3 for illegal ones */
1492e5b6d6dSopenharmony_ci    -3, -3, -3, -3, -3, -3, -3, -3, -3, -1, -1, -3, -3, -1, -3, -3,
1502e5b6d6dSopenharmony_ci    -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,
1512e5b6d6dSopenharmony_ci
1522e5b6d6dSopenharmony_ci    /* general punctuation with + and / and a special value (-2) for - */
1532e5b6d6dSopenharmony_ci    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -2, -1, 63,
1542e5b6d6dSopenharmony_ci    /* digits */
1552e5b6d6dSopenharmony_ci    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
1562e5b6d6dSopenharmony_ci
1572e5b6d6dSopenharmony_ci    /* A-Z */
1582e5b6d6dSopenharmony_ci    -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
1592e5b6d6dSopenharmony_ci    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -3, -1, -1, -1,
1602e5b6d6dSopenharmony_ci
1612e5b6d6dSopenharmony_ci    /* a-z */
1622e5b6d6dSopenharmony_ci    -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
1632e5b6d6dSopenharmony_ci    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -3, -3
1642e5b6d6dSopenharmony_ci};
1652e5b6d6dSopenharmony_ci
1662e5b6d6dSopenharmony_ci/*
1672e5b6d6dSopenharmony_ci * converter status values:
1682e5b6d6dSopenharmony_ci *
1692e5b6d6dSopenharmony_ci * toUnicodeStatus:
1702e5b6d6dSopenharmony_ci *     24 inDirectMode (boolean)
1712e5b6d6dSopenharmony_ci * 23..16 base64Counter (-1..7)
1722e5b6d6dSopenharmony_ci * 15..0  bits (up to 14 bits incoming base64)
1732e5b6d6dSopenharmony_ci *
1742e5b6d6dSopenharmony_ci * fromUnicodeStatus:
1752e5b6d6dSopenharmony_ci * 31..28 version (0: set O direct  1: set O escaped)
1762e5b6d6dSopenharmony_ci *     24 inDirectMode (boolean)
1772e5b6d6dSopenharmony_ci * 23..16 base64Counter (0..2)
1782e5b6d6dSopenharmony_ci *  7..0  bits (6 bits outgoing base64)
1792e5b6d6dSopenharmony_ci *
1802e5b6d6dSopenharmony_ci */
1812e5b6d6dSopenharmony_ci
1822e5b6d6dSopenharmony_ciU_CDECL_BEGIN
1832e5b6d6dSopenharmony_cistatic void U_CALLCONV
1842e5b6d6dSopenharmony_ci_UTF7Reset(UConverter *cnv, UConverterResetChoice choice) {
1852e5b6d6dSopenharmony_ci    if(choice<=UCNV_RESET_TO_UNICODE) {
1862e5b6d6dSopenharmony_ci        /* reset toUnicode */
1872e5b6d6dSopenharmony_ci        cnv->toUnicodeStatus=0x1000000; /* inDirectMode=true */
1882e5b6d6dSopenharmony_ci        cnv->toULength=0;
1892e5b6d6dSopenharmony_ci    }
1902e5b6d6dSopenharmony_ci    if(choice!=UCNV_RESET_TO_UNICODE) {
1912e5b6d6dSopenharmony_ci        /* reset fromUnicode */
1922e5b6d6dSopenharmony_ci        cnv->fromUnicodeStatus=(cnv->fromUnicodeStatus&0xf0000000)|0x1000000; /* keep version, inDirectMode=true */
1932e5b6d6dSopenharmony_ci    }
1942e5b6d6dSopenharmony_ci}
1952e5b6d6dSopenharmony_ci
1962e5b6d6dSopenharmony_cistatic void U_CALLCONV
1972e5b6d6dSopenharmony_ci_UTF7Open(UConverter *cnv,
1982e5b6d6dSopenharmony_ci          UConverterLoadArgs *pArgs,
1992e5b6d6dSopenharmony_ci          UErrorCode *pErrorCode) {
2002e5b6d6dSopenharmony_ci    (void)pArgs;
2012e5b6d6dSopenharmony_ci    if(UCNV_GET_VERSION(cnv)<=1) {
2022e5b6d6dSopenharmony_ci        /* TODO(markus): Should just use cnv->options rather than copying the version number. */
2032e5b6d6dSopenharmony_ci        cnv->fromUnicodeStatus=UCNV_GET_VERSION(cnv)<<28;
2042e5b6d6dSopenharmony_ci        _UTF7Reset(cnv, UCNV_RESET_BOTH);
2052e5b6d6dSopenharmony_ci    } else {
2062e5b6d6dSopenharmony_ci        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
2072e5b6d6dSopenharmony_ci    }
2082e5b6d6dSopenharmony_ci}
2092e5b6d6dSopenharmony_ci
2102e5b6d6dSopenharmony_cistatic void U_CALLCONV
2112e5b6d6dSopenharmony_ci_UTF7ToUnicodeWithOffsets(UConverterToUnicodeArgs *pArgs,
2122e5b6d6dSopenharmony_ci                          UErrorCode *pErrorCode) {
2132e5b6d6dSopenharmony_ci    UConverter *cnv;
2142e5b6d6dSopenharmony_ci    const uint8_t *source, *sourceLimit;
2152e5b6d6dSopenharmony_ci    UChar *target;
2162e5b6d6dSopenharmony_ci    const UChar *targetLimit;
2172e5b6d6dSopenharmony_ci    int32_t *offsets;
2182e5b6d6dSopenharmony_ci
2192e5b6d6dSopenharmony_ci    uint8_t *bytes;
2202e5b6d6dSopenharmony_ci    uint8_t byteIndex;
2212e5b6d6dSopenharmony_ci
2222e5b6d6dSopenharmony_ci    int32_t length, targetCapacity;
2232e5b6d6dSopenharmony_ci
2242e5b6d6dSopenharmony_ci    /* UTF-7 state */
2252e5b6d6dSopenharmony_ci    uint16_t bits;
2262e5b6d6dSopenharmony_ci    int8_t base64Counter;
2272e5b6d6dSopenharmony_ci    UBool inDirectMode;
2282e5b6d6dSopenharmony_ci
2292e5b6d6dSopenharmony_ci    int8_t base64Value;
2302e5b6d6dSopenharmony_ci
2312e5b6d6dSopenharmony_ci    int32_t sourceIndex, nextSourceIndex;
2322e5b6d6dSopenharmony_ci
2332e5b6d6dSopenharmony_ci    uint8_t b;
2342e5b6d6dSopenharmony_ci    /* set up the local pointers */
2352e5b6d6dSopenharmony_ci    cnv=pArgs->converter;
2362e5b6d6dSopenharmony_ci
2372e5b6d6dSopenharmony_ci    source=(const uint8_t *)pArgs->source;
2382e5b6d6dSopenharmony_ci    sourceLimit=(const uint8_t *)pArgs->sourceLimit;
2392e5b6d6dSopenharmony_ci    target=pArgs->target;
2402e5b6d6dSopenharmony_ci    targetLimit=pArgs->targetLimit;
2412e5b6d6dSopenharmony_ci    offsets=pArgs->offsets;
2422e5b6d6dSopenharmony_ci    /* get the state machine state */
2432e5b6d6dSopenharmony_ci    {
2442e5b6d6dSopenharmony_ci        uint32_t status=cnv->toUnicodeStatus;
2452e5b6d6dSopenharmony_ci        inDirectMode=(UBool)((status>>24)&1);
2462e5b6d6dSopenharmony_ci        base64Counter=(int8_t)(status>>16);
2472e5b6d6dSopenharmony_ci        bits=(uint16_t)status;
2482e5b6d6dSopenharmony_ci    }
2492e5b6d6dSopenharmony_ci    bytes=cnv->toUBytes;
2502e5b6d6dSopenharmony_ci    byteIndex=cnv->toULength;
2512e5b6d6dSopenharmony_ci
2522e5b6d6dSopenharmony_ci    /* sourceIndex=-1 if the current character began in the previous buffer */
2532e5b6d6dSopenharmony_ci    sourceIndex=byteIndex==0 ? 0 : -1;
2542e5b6d6dSopenharmony_ci    nextSourceIndex=0;
2552e5b6d6dSopenharmony_ci
2562e5b6d6dSopenharmony_ci    if(inDirectMode) {
2572e5b6d6dSopenharmony_cidirectMode:
2582e5b6d6dSopenharmony_ci        /*
2592e5b6d6dSopenharmony_ci         * In Direct Mode, most US-ASCII characters are encoded directly, i.e.,
2602e5b6d6dSopenharmony_ci         * with their US-ASCII byte values.
2612e5b6d6dSopenharmony_ci         * Backslash and Tilde and most control characters are not allowed in UTF-7.
2622e5b6d6dSopenharmony_ci         * A plus sign starts Unicode (or "escape") Mode.
2632e5b6d6dSopenharmony_ci         *
2642e5b6d6dSopenharmony_ci         * In Direct Mode, only the sourceIndex is used.
2652e5b6d6dSopenharmony_ci         */
2662e5b6d6dSopenharmony_ci        byteIndex=0;
2672e5b6d6dSopenharmony_ci        length=(int32_t)(sourceLimit-source);
2682e5b6d6dSopenharmony_ci        targetCapacity=(int32_t)(targetLimit-target);
2692e5b6d6dSopenharmony_ci        if(length>targetCapacity) {
2702e5b6d6dSopenharmony_ci            length=targetCapacity;
2712e5b6d6dSopenharmony_ci        }
2722e5b6d6dSopenharmony_ci        while(length>0) {
2732e5b6d6dSopenharmony_ci            b=*source++;
2742e5b6d6dSopenharmony_ci            if(!isLegalUTF7(b)) {
2752e5b6d6dSopenharmony_ci                /* illegal */
2762e5b6d6dSopenharmony_ci                bytes[0]=b;
2772e5b6d6dSopenharmony_ci                byteIndex=1;
2782e5b6d6dSopenharmony_ci                *pErrorCode=U_ILLEGAL_CHAR_FOUND;
2792e5b6d6dSopenharmony_ci                break;
2802e5b6d6dSopenharmony_ci            } else if(b!=PLUS) {
2812e5b6d6dSopenharmony_ci                /* write directly encoded character */
2822e5b6d6dSopenharmony_ci                *target++=b;
2832e5b6d6dSopenharmony_ci                if(offsets!=NULL) {
2842e5b6d6dSopenharmony_ci                    *offsets++=sourceIndex++;
2852e5b6d6dSopenharmony_ci                }
2862e5b6d6dSopenharmony_ci            } else /* PLUS */ {
2872e5b6d6dSopenharmony_ci                /* switch to Unicode mode */
2882e5b6d6dSopenharmony_ci                nextSourceIndex=++sourceIndex;
2892e5b6d6dSopenharmony_ci                inDirectMode=false;
2902e5b6d6dSopenharmony_ci                byteIndex=0;
2912e5b6d6dSopenharmony_ci                bits=0;
2922e5b6d6dSopenharmony_ci                base64Counter=-1;
2932e5b6d6dSopenharmony_ci                goto unicodeMode;
2942e5b6d6dSopenharmony_ci            }
2952e5b6d6dSopenharmony_ci            --length;
2962e5b6d6dSopenharmony_ci        }
2972e5b6d6dSopenharmony_ci        if(source<sourceLimit && target>=targetLimit) {
2982e5b6d6dSopenharmony_ci            /* target is full */
2992e5b6d6dSopenharmony_ci            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
3002e5b6d6dSopenharmony_ci        }
3012e5b6d6dSopenharmony_ci    } else {
3022e5b6d6dSopenharmony_ciunicodeMode:
3032e5b6d6dSopenharmony_ci        /*
3042e5b6d6dSopenharmony_ci         * In Unicode (or "escape") Mode, UTF-16BE is base64-encoded.
3052e5b6d6dSopenharmony_ci         * The base64 sequence ends with any character that is not in the base64 alphabet.
3062e5b6d6dSopenharmony_ci         * A terminating minus sign is consumed.
3072e5b6d6dSopenharmony_ci         *
3082e5b6d6dSopenharmony_ci         * In Unicode Mode, the sourceIndex has the index to the start of the current
3092e5b6d6dSopenharmony_ci         * base64 bytes, while nextSourceIndex is precisely parallel to source,
3102e5b6d6dSopenharmony_ci         * keeping the index to the following byte.
3112e5b6d6dSopenharmony_ci         * Note that in 2 out of 3 cases, UChars overlap within a base64 byte.
3122e5b6d6dSopenharmony_ci         */
3132e5b6d6dSopenharmony_ci        while(source<sourceLimit) {
3142e5b6d6dSopenharmony_ci            if(target<targetLimit) {
3152e5b6d6dSopenharmony_ci                bytes[byteIndex++]=b=*source++;
3162e5b6d6dSopenharmony_ci                ++nextSourceIndex;
3172e5b6d6dSopenharmony_ci                base64Value = -3; /* initialize as illegal */
3182e5b6d6dSopenharmony_ci                if(b>=126 || (base64Value=fromBase64[b])==-3 || base64Value==-1) {
3192e5b6d6dSopenharmony_ci                    /* either
3202e5b6d6dSopenharmony_ci                     * base64Value==-1 for any legal character except base64 and minus sign, or
3212e5b6d6dSopenharmony_ci                     * base64Value==-3 for illegal characters:
3222e5b6d6dSopenharmony_ci                     * 1. In either case, leave Unicode mode.
3232e5b6d6dSopenharmony_ci                     * 2.1. If we ended with an incomplete UChar or none after the +, then
3242e5b6d6dSopenharmony_ci                     *      generate an error for the preceding erroneous sequence and deal with
3252e5b6d6dSopenharmony_ci                     *      the current (possibly illegal) character next time through.
3262e5b6d6dSopenharmony_ci                     * 2.2. Else the current char comes after a complete UChar, which was already
3272e5b6d6dSopenharmony_ci                     *      pushed to the output buf, so:
3282e5b6d6dSopenharmony_ci                     * 2.2.1. If the current char is legal, just save it for processing next time.
3292e5b6d6dSopenharmony_ci                     *        It may be for example, a plus which we need to deal with in direct mode.
3302e5b6d6dSopenharmony_ci                     * 2.2.2. Else if the current char is illegal, we might as well deal with it here.
3312e5b6d6dSopenharmony_ci                     */
3322e5b6d6dSopenharmony_ci                    inDirectMode=true;
3332e5b6d6dSopenharmony_ci                    if(base64Counter==-1) {
3342e5b6d6dSopenharmony_ci                        /* illegal: + immediately followed by something other than base64 or minus sign */
3352e5b6d6dSopenharmony_ci                        /* include the plus sign in the reported sequence, but not the subsequent char */
3362e5b6d6dSopenharmony_ci                        --source;
3372e5b6d6dSopenharmony_ci                        bytes[0]=PLUS;
3382e5b6d6dSopenharmony_ci                        byteIndex=1;
3392e5b6d6dSopenharmony_ci                        *pErrorCode=U_ILLEGAL_CHAR_FOUND;
3402e5b6d6dSopenharmony_ci                        break;
3412e5b6d6dSopenharmony_ci                    } else if(bits!=0) {
3422e5b6d6dSopenharmony_ci                        /* bits are illegally left over, a UChar is incomplete */
3432e5b6d6dSopenharmony_ci                        /* don't include current char (legal or illegal) in error seq */
3442e5b6d6dSopenharmony_ci                        --source;
3452e5b6d6dSopenharmony_ci                        --byteIndex;
3462e5b6d6dSopenharmony_ci                        *pErrorCode=U_ILLEGAL_CHAR_FOUND;
3472e5b6d6dSopenharmony_ci                        break;
3482e5b6d6dSopenharmony_ci                    } else {
3492e5b6d6dSopenharmony_ci                        /* previous UChar was complete */
3502e5b6d6dSopenharmony_ci                        if(base64Value==-3) {
3512e5b6d6dSopenharmony_ci                            /* current character is illegal, deal with it here */
3522e5b6d6dSopenharmony_ci                            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
3532e5b6d6dSopenharmony_ci                            break;
3542e5b6d6dSopenharmony_ci                        } else {
3552e5b6d6dSopenharmony_ci                            /* un-read the current character in case it is a plus sign */
3562e5b6d6dSopenharmony_ci                            --source;
3572e5b6d6dSopenharmony_ci                            sourceIndex=nextSourceIndex-1;
3582e5b6d6dSopenharmony_ci                            goto directMode;
3592e5b6d6dSopenharmony_ci                        }
3602e5b6d6dSopenharmony_ci                    }
3612e5b6d6dSopenharmony_ci                } else if(base64Value>=0) {
3622e5b6d6dSopenharmony_ci                    /* collect base64 bytes into UChars */
3632e5b6d6dSopenharmony_ci                    switch(base64Counter) {
3642e5b6d6dSopenharmony_ci                    case -1: /* -1 is immediately after the + */
3652e5b6d6dSopenharmony_ci                    case 0:
3662e5b6d6dSopenharmony_ci                        bits=base64Value;
3672e5b6d6dSopenharmony_ci                        base64Counter=1;
3682e5b6d6dSopenharmony_ci                        break;
3692e5b6d6dSopenharmony_ci                    case 1:
3702e5b6d6dSopenharmony_ci                    case 3:
3712e5b6d6dSopenharmony_ci                    case 4:
3722e5b6d6dSopenharmony_ci                    case 6:
3732e5b6d6dSopenharmony_ci                        bits=(uint16_t)((bits<<6)|base64Value);
3742e5b6d6dSopenharmony_ci                        ++base64Counter;
3752e5b6d6dSopenharmony_ci                        break;
3762e5b6d6dSopenharmony_ci                    case 2:
3772e5b6d6dSopenharmony_ci                        *target++=(UChar)((bits<<4)|(base64Value>>2));
3782e5b6d6dSopenharmony_ci                        if(offsets!=NULL) {
3792e5b6d6dSopenharmony_ci                            *offsets++=sourceIndex;
3802e5b6d6dSopenharmony_ci                            sourceIndex=nextSourceIndex-1;
3812e5b6d6dSopenharmony_ci                        }
3822e5b6d6dSopenharmony_ci                        bytes[0]=b; /* keep this byte in case an error occurs */
3832e5b6d6dSopenharmony_ci                        byteIndex=1;
3842e5b6d6dSopenharmony_ci                        bits=(uint16_t)(base64Value&3);
3852e5b6d6dSopenharmony_ci                        base64Counter=3;
3862e5b6d6dSopenharmony_ci                        break;
3872e5b6d6dSopenharmony_ci                    case 5:
3882e5b6d6dSopenharmony_ci                        *target++=(UChar)((bits<<2)|(base64Value>>4));
3892e5b6d6dSopenharmony_ci                        if(offsets!=NULL) {
3902e5b6d6dSopenharmony_ci                            *offsets++=sourceIndex;
3912e5b6d6dSopenharmony_ci                            sourceIndex=nextSourceIndex-1;
3922e5b6d6dSopenharmony_ci                        }
3932e5b6d6dSopenharmony_ci                        bytes[0]=b; /* keep this byte in case an error occurs */
3942e5b6d6dSopenharmony_ci                        byteIndex=1;
3952e5b6d6dSopenharmony_ci                        bits=(uint16_t)(base64Value&15);
3962e5b6d6dSopenharmony_ci                        base64Counter=6;
3972e5b6d6dSopenharmony_ci                        break;
3982e5b6d6dSopenharmony_ci                    case 7:
3992e5b6d6dSopenharmony_ci                        *target++=(UChar)((bits<<6)|base64Value);
4002e5b6d6dSopenharmony_ci                        if(offsets!=NULL) {
4012e5b6d6dSopenharmony_ci                            *offsets++=sourceIndex;
4022e5b6d6dSopenharmony_ci                            sourceIndex=nextSourceIndex;
4032e5b6d6dSopenharmony_ci                        }
4042e5b6d6dSopenharmony_ci                        byteIndex=0;
4052e5b6d6dSopenharmony_ci                        bits=0;
4062e5b6d6dSopenharmony_ci                        base64Counter=0;
4072e5b6d6dSopenharmony_ci                        break;
4082e5b6d6dSopenharmony_ci                    default:
4092e5b6d6dSopenharmony_ci                        /* will never occur */
4102e5b6d6dSopenharmony_ci                        break;
4112e5b6d6dSopenharmony_ci                    }
4122e5b6d6dSopenharmony_ci                } else /*base64Value==-2*/ {
4132e5b6d6dSopenharmony_ci                    /* minus sign terminates the base64 sequence */
4142e5b6d6dSopenharmony_ci                    inDirectMode=true;
4152e5b6d6dSopenharmony_ci                    if(base64Counter==-1) {
4162e5b6d6dSopenharmony_ci                        /* +- i.e. a minus immediately following a plus */
4172e5b6d6dSopenharmony_ci                        *target++=PLUS;
4182e5b6d6dSopenharmony_ci                        if(offsets!=NULL) {
4192e5b6d6dSopenharmony_ci                            *offsets++=sourceIndex-1;
4202e5b6d6dSopenharmony_ci                        }
4212e5b6d6dSopenharmony_ci                    } else {
4222e5b6d6dSopenharmony_ci                        /* absorb the minus and leave the Unicode Mode */
4232e5b6d6dSopenharmony_ci                        if(bits!=0) {
4242e5b6d6dSopenharmony_ci                            /* bits are illegally left over, a UChar is incomplete */
4252e5b6d6dSopenharmony_ci                            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
4262e5b6d6dSopenharmony_ci                            break;
4272e5b6d6dSopenharmony_ci                        }
4282e5b6d6dSopenharmony_ci                    }
4292e5b6d6dSopenharmony_ci                    sourceIndex=nextSourceIndex;
4302e5b6d6dSopenharmony_ci                    goto directMode;
4312e5b6d6dSopenharmony_ci                }
4322e5b6d6dSopenharmony_ci            } else {
4332e5b6d6dSopenharmony_ci                /* target is full */
4342e5b6d6dSopenharmony_ci                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
4352e5b6d6dSopenharmony_ci                break;
4362e5b6d6dSopenharmony_ci            }
4372e5b6d6dSopenharmony_ci        }
4382e5b6d6dSopenharmony_ci    }
4392e5b6d6dSopenharmony_ci
4402e5b6d6dSopenharmony_ci    if(U_SUCCESS(*pErrorCode) && pArgs->flush && source==sourceLimit && bits==0) {
4412e5b6d6dSopenharmony_ci        /*
4422e5b6d6dSopenharmony_ci         * if we are in Unicode mode, then the byteIndex might not be 0,
4432e5b6d6dSopenharmony_ci         * but that is ok if bits==0
4442e5b6d6dSopenharmony_ci         * -> we set byteIndex=0 at the end of the stream to avoid a truncated error
4452e5b6d6dSopenharmony_ci         * (not true for IMAP-mailbox-name where we must end in direct mode)
4462e5b6d6dSopenharmony_ci         */
4472e5b6d6dSopenharmony_ci        byteIndex=0;
4482e5b6d6dSopenharmony_ci    }
4492e5b6d6dSopenharmony_ci
4502e5b6d6dSopenharmony_ci    /* set the converter state back into UConverter */
4512e5b6d6dSopenharmony_ci    cnv->toUnicodeStatus=((uint32_t)inDirectMode<<24)|((uint32_t)((uint8_t)base64Counter)<<16)|(uint32_t)bits;
4522e5b6d6dSopenharmony_ci    cnv->toULength=byteIndex;
4532e5b6d6dSopenharmony_ci
4542e5b6d6dSopenharmony_ci    /* write back the updated pointers */
4552e5b6d6dSopenharmony_ci    pArgs->source=(const char *)source;
4562e5b6d6dSopenharmony_ci    pArgs->target=target;
4572e5b6d6dSopenharmony_ci    pArgs->offsets=offsets;
4582e5b6d6dSopenharmony_ci    return;
4592e5b6d6dSopenharmony_ci}
4602e5b6d6dSopenharmony_ci
4612e5b6d6dSopenharmony_cistatic void U_CALLCONV
4622e5b6d6dSopenharmony_ci_UTF7FromUnicodeWithOffsets(UConverterFromUnicodeArgs *pArgs,
4632e5b6d6dSopenharmony_ci                            UErrorCode *pErrorCode) {
4642e5b6d6dSopenharmony_ci    UConverter *cnv;
4652e5b6d6dSopenharmony_ci    const UChar *source, *sourceLimit;
4662e5b6d6dSopenharmony_ci    uint8_t *target, *targetLimit;
4672e5b6d6dSopenharmony_ci    int32_t *offsets;
4682e5b6d6dSopenharmony_ci
4692e5b6d6dSopenharmony_ci    int32_t length, targetCapacity, sourceIndex;
4702e5b6d6dSopenharmony_ci    UChar c;
4712e5b6d6dSopenharmony_ci
4722e5b6d6dSopenharmony_ci    /* UTF-7 state */
4732e5b6d6dSopenharmony_ci    const UBool *encodeDirectly;
4742e5b6d6dSopenharmony_ci    uint8_t bits;
4752e5b6d6dSopenharmony_ci    int8_t base64Counter;
4762e5b6d6dSopenharmony_ci    UBool inDirectMode;
4772e5b6d6dSopenharmony_ci
4782e5b6d6dSopenharmony_ci    /* set up the local pointers */
4792e5b6d6dSopenharmony_ci    cnv=pArgs->converter;
4802e5b6d6dSopenharmony_ci
4812e5b6d6dSopenharmony_ci    /* set up the local pointers */
4822e5b6d6dSopenharmony_ci    source=pArgs->source;
4832e5b6d6dSopenharmony_ci    sourceLimit=pArgs->sourceLimit;
4842e5b6d6dSopenharmony_ci    target=(uint8_t *)pArgs->target;
4852e5b6d6dSopenharmony_ci    targetLimit=(uint8_t *)pArgs->targetLimit;
4862e5b6d6dSopenharmony_ci    offsets=pArgs->offsets;
4872e5b6d6dSopenharmony_ci
4882e5b6d6dSopenharmony_ci    /* get the state machine state */
4892e5b6d6dSopenharmony_ci    {
4902e5b6d6dSopenharmony_ci        uint32_t status=cnv->fromUnicodeStatus;
4912e5b6d6dSopenharmony_ci        encodeDirectly= status<0x10000000 ? encodeDirectlyMaximum : encodeDirectlyRestricted;
4922e5b6d6dSopenharmony_ci        inDirectMode=(UBool)((status>>24)&1);
4932e5b6d6dSopenharmony_ci        base64Counter=(int8_t)(status>>16);
4942e5b6d6dSopenharmony_ci        bits=(uint8_t)status;
4952e5b6d6dSopenharmony_ci        U_ASSERT(bits<=UPRV_LENGTHOF(toBase64));
4962e5b6d6dSopenharmony_ci    }
4972e5b6d6dSopenharmony_ci
4982e5b6d6dSopenharmony_ci    /* UTF-7 always encodes UTF-16 code units, therefore we need only a simple sourceIndex */
4992e5b6d6dSopenharmony_ci    sourceIndex=0;
5002e5b6d6dSopenharmony_ci
5012e5b6d6dSopenharmony_ci    if(inDirectMode) {
5022e5b6d6dSopenharmony_cidirectMode:
5032e5b6d6dSopenharmony_ci        length=(int32_t)(sourceLimit-source);
5042e5b6d6dSopenharmony_ci        targetCapacity=(int32_t)(targetLimit-target);
5052e5b6d6dSopenharmony_ci        if(length>targetCapacity) {
5062e5b6d6dSopenharmony_ci            length=targetCapacity;
5072e5b6d6dSopenharmony_ci        }
5082e5b6d6dSopenharmony_ci        while(length>0) {
5092e5b6d6dSopenharmony_ci            c=*source++;
5102e5b6d6dSopenharmony_ci            /* currently always encode CR LF SP TAB directly */
5112e5b6d6dSopenharmony_ci            if(c<=127 && encodeDirectly[c]) {
5122e5b6d6dSopenharmony_ci                /* encode directly */
5132e5b6d6dSopenharmony_ci                *target++=(uint8_t)c;
5142e5b6d6dSopenharmony_ci                if(offsets!=NULL) {
5152e5b6d6dSopenharmony_ci                    *offsets++=sourceIndex++;
5162e5b6d6dSopenharmony_ci                }
5172e5b6d6dSopenharmony_ci            } else if(c==PLUS) {
5182e5b6d6dSopenharmony_ci                /* output +- for + */
5192e5b6d6dSopenharmony_ci                *target++=PLUS;
5202e5b6d6dSopenharmony_ci                if(target<targetLimit) {
5212e5b6d6dSopenharmony_ci                    *target++=MINUS;
5222e5b6d6dSopenharmony_ci                    if(offsets!=NULL) {
5232e5b6d6dSopenharmony_ci                        *offsets++=sourceIndex;
5242e5b6d6dSopenharmony_ci                        *offsets++=sourceIndex++;
5252e5b6d6dSopenharmony_ci                    }
5262e5b6d6dSopenharmony_ci                    /* realign length and targetCapacity */
5272e5b6d6dSopenharmony_ci                    goto directMode;
5282e5b6d6dSopenharmony_ci                } else {
5292e5b6d6dSopenharmony_ci                    if(offsets!=NULL) {
5302e5b6d6dSopenharmony_ci                        *offsets++=sourceIndex++;
5312e5b6d6dSopenharmony_ci                    }
5322e5b6d6dSopenharmony_ci                    cnv->charErrorBuffer[0]=MINUS;
5332e5b6d6dSopenharmony_ci                    cnv->charErrorBufferLength=1;
5342e5b6d6dSopenharmony_ci                    *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
5352e5b6d6dSopenharmony_ci                    break;
5362e5b6d6dSopenharmony_ci                }
5372e5b6d6dSopenharmony_ci            } else {
5382e5b6d6dSopenharmony_ci                /* un-read this character and switch to Unicode Mode */
5392e5b6d6dSopenharmony_ci                --source;
5402e5b6d6dSopenharmony_ci                *target++=PLUS;
5412e5b6d6dSopenharmony_ci                if(offsets!=NULL) {
5422e5b6d6dSopenharmony_ci                    *offsets++=sourceIndex;
5432e5b6d6dSopenharmony_ci                }
5442e5b6d6dSopenharmony_ci                inDirectMode=false;
5452e5b6d6dSopenharmony_ci                base64Counter=0;
5462e5b6d6dSopenharmony_ci                goto unicodeMode;
5472e5b6d6dSopenharmony_ci            }
5482e5b6d6dSopenharmony_ci            --length;
5492e5b6d6dSopenharmony_ci        }
5502e5b6d6dSopenharmony_ci        if(source<sourceLimit && target>=targetLimit) {
5512e5b6d6dSopenharmony_ci            /* target is full */
5522e5b6d6dSopenharmony_ci            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
5532e5b6d6dSopenharmony_ci        }
5542e5b6d6dSopenharmony_ci    } else {
5552e5b6d6dSopenharmony_ciunicodeMode:
5562e5b6d6dSopenharmony_ci        while(source<sourceLimit) {
5572e5b6d6dSopenharmony_ci            if(target<targetLimit) {
5582e5b6d6dSopenharmony_ci                c=*source++;
5592e5b6d6dSopenharmony_ci                if(c<=127 && encodeDirectly[c]) {
5602e5b6d6dSopenharmony_ci                    /* encode directly */
5612e5b6d6dSopenharmony_ci                    inDirectMode=true;
5622e5b6d6dSopenharmony_ci
5632e5b6d6dSopenharmony_ci                    /* trick: back out this character to make this easier */
5642e5b6d6dSopenharmony_ci                    --source;
5652e5b6d6dSopenharmony_ci
5662e5b6d6dSopenharmony_ci                    /* terminate the base64 sequence */
5672e5b6d6dSopenharmony_ci                    if(base64Counter!=0) {
5682e5b6d6dSopenharmony_ci                        /* write remaining bits for the previous character */
5692e5b6d6dSopenharmony_ci                        *target++=toBase64[bits];
5702e5b6d6dSopenharmony_ci                        if(offsets!=NULL) {
5712e5b6d6dSopenharmony_ci                            *offsets++=sourceIndex-1;
5722e5b6d6dSopenharmony_ci                        }
5732e5b6d6dSopenharmony_ci                    }
5742e5b6d6dSopenharmony_ci                    if(fromBase64[c]!=-1) {
5752e5b6d6dSopenharmony_ci                        /* need to terminate with a minus */
5762e5b6d6dSopenharmony_ci                        if(target<targetLimit) {
5772e5b6d6dSopenharmony_ci                            *target++=MINUS;
5782e5b6d6dSopenharmony_ci                            if(offsets!=NULL) {
5792e5b6d6dSopenharmony_ci                                *offsets++=sourceIndex-1;
5802e5b6d6dSopenharmony_ci                            }
5812e5b6d6dSopenharmony_ci                        } else {
5822e5b6d6dSopenharmony_ci                            cnv->charErrorBuffer[0]=MINUS;
5832e5b6d6dSopenharmony_ci                            cnv->charErrorBufferLength=1;
5842e5b6d6dSopenharmony_ci                            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
5852e5b6d6dSopenharmony_ci                            break;
5862e5b6d6dSopenharmony_ci                        }
5872e5b6d6dSopenharmony_ci                    }
5882e5b6d6dSopenharmony_ci                    goto directMode;
5892e5b6d6dSopenharmony_ci                } else {
5902e5b6d6dSopenharmony_ci                    /*
5912e5b6d6dSopenharmony_ci                     * base64 this character:
5922e5b6d6dSopenharmony_ci                     * Output 2 or 3 base64 bytes for the remaining bits of the previous character
5932e5b6d6dSopenharmony_ci                     * and the bits of this character, each implicitly in UTF-16BE.
5942e5b6d6dSopenharmony_ci                     *
5952e5b6d6dSopenharmony_ci                     * Here, bits is an 8-bit variable because only 6 bits need to be kept from one
5962e5b6d6dSopenharmony_ci                     * character to the next. The actual 2 or 4 bits are shifted to the left edge
5972e5b6d6dSopenharmony_ci                     * of the 6-bits field 5..0 to make the termination of the base64 sequence easier.
5982e5b6d6dSopenharmony_ci                     */
5992e5b6d6dSopenharmony_ci                    switch(base64Counter) {
6002e5b6d6dSopenharmony_ci                    case 0:
6012e5b6d6dSopenharmony_ci                        *target++=toBase64[c>>10];
6022e5b6d6dSopenharmony_ci                        if(target<targetLimit) {
6032e5b6d6dSopenharmony_ci                            *target++=toBase64[(c>>4)&0x3f];
6042e5b6d6dSopenharmony_ci                            if(offsets!=NULL) {
6052e5b6d6dSopenharmony_ci                                *offsets++=sourceIndex;
6062e5b6d6dSopenharmony_ci                                *offsets++=sourceIndex++;
6072e5b6d6dSopenharmony_ci                            }
6082e5b6d6dSopenharmony_ci                        } else {
6092e5b6d6dSopenharmony_ci                            if(offsets!=NULL) {
6102e5b6d6dSopenharmony_ci                                *offsets++=sourceIndex++;
6112e5b6d6dSopenharmony_ci                            }
6122e5b6d6dSopenharmony_ci                            cnv->charErrorBuffer[0]=toBase64[(c>>4)&0x3f];
6132e5b6d6dSopenharmony_ci                            cnv->charErrorBufferLength=1;
6142e5b6d6dSopenharmony_ci                            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
6152e5b6d6dSopenharmony_ci                        }
6162e5b6d6dSopenharmony_ci                        bits=(uint8_t)((c&15)<<2);
6172e5b6d6dSopenharmony_ci                        base64Counter=1;
6182e5b6d6dSopenharmony_ci                        break;
6192e5b6d6dSopenharmony_ci                    case 1:
6202e5b6d6dSopenharmony_ci                        *target++=toBase64[bits|(c>>14)];
6212e5b6d6dSopenharmony_ci                        if(target<targetLimit) {
6222e5b6d6dSopenharmony_ci                            *target++=toBase64[(c>>8)&0x3f];
6232e5b6d6dSopenharmony_ci                            if(target<targetLimit) {
6242e5b6d6dSopenharmony_ci                                *target++=toBase64[(c>>2)&0x3f];
6252e5b6d6dSopenharmony_ci                                if(offsets!=NULL) {
6262e5b6d6dSopenharmony_ci                                    *offsets++=sourceIndex;
6272e5b6d6dSopenharmony_ci                                    *offsets++=sourceIndex;
6282e5b6d6dSopenharmony_ci                                    *offsets++=sourceIndex++;
6292e5b6d6dSopenharmony_ci                                }
6302e5b6d6dSopenharmony_ci                            } else {
6312e5b6d6dSopenharmony_ci                                if(offsets!=NULL) {
6322e5b6d6dSopenharmony_ci                                    *offsets++=sourceIndex;
6332e5b6d6dSopenharmony_ci                                    *offsets++=sourceIndex++;
6342e5b6d6dSopenharmony_ci                                }
6352e5b6d6dSopenharmony_ci                                cnv->charErrorBuffer[0]=toBase64[(c>>2)&0x3f];
6362e5b6d6dSopenharmony_ci                                cnv->charErrorBufferLength=1;
6372e5b6d6dSopenharmony_ci                                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
6382e5b6d6dSopenharmony_ci                            }
6392e5b6d6dSopenharmony_ci                        } else {
6402e5b6d6dSopenharmony_ci                            if(offsets!=NULL) {
6412e5b6d6dSopenharmony_ci                                *offsets++=sourceIndex++;
6422e5b6d6dSopenharmony_ci                            }
6432e5b6d6dSopenharmony_ci                            cnv->charErrorBuffer[0]=toBase64[(c>>8)&0x3f];
6442e5b6d6dSopenharmony_ci                            cnv->charErrorBuffer[1]=toBase64[(c>>2)&0x3f];
6452e5b6d6dSopenharmony_ci                            cnv->charErrorBufferLength=2;
6462e5b6d6dSopenharmony_ci                            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
6472e5b6d6dSopenharmony_ci                        }
6482e5b6d6dSopenharmony_ci                        bits=(uint8_t)((c&3)<<4);
6492e5b6d6dSopenharmony_ci                        base64Counter=2;
6502e5b6d6dSopenharmony_ci                        break;
6512e5b6d6dSopenharmony_ci                    case 2:
6522e5b6d6dSopenharmony_ci                        *target++=toBase64[bits|(c>>12)];
6532e5b6d6dSopenharmony_ci                        if(target<targetLimit) {
6542e5b6d6dSopenharmony_ci                            *target++=toBase64[(c>>6)&0x3f];
6552e5b6d6dSopenharmony_ci                            if(target<targetLimit) {
6562e5b6d6dSopenharmony_ci                                *target++=toBase64[c&0x3f];
6572e5b6d6dSopenharmony_ci                                if(offsets!=NULL) {
6582e5b6d6dSopenharmony_ci                                    *offsets++=sourceIndex;
6592e5b6d6dSopenharmony_ci                                    *offsets++=sourceIndex;
6602e5b6d6dSopenharmony_ci                                    *offsets++=sourceIndex++;
6612e5b6d6dSopenharmony_ci                                }
6622e5b6d6dSopenharmony_ci                            } else {
6632e5b6d6dSopenharmony_ci                                if(offsets!=NULL) {
6642e5b6d6dSopenharmony_ci                                    *offsets++=sourceIndex;
6652e5b6d6dSopenharmony_ci                                    *offsets++=sourceIndex++;
6662e5b6d6dSopenharmony_ci                                }
6672e5b6d6dSopenharmony_ci                                cnv->charErrorBuffer[0]=toBase64[c&0x3f];
6682e5b6d6dSopenharmony_ci                                cnv->charErrorBufferLength=1;
6692e5b6d6dSopenharmony_ci                                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
6702e5b6d6dSopenharmony_ci                            }
6712e5b6d6dSopenharmony_ci                        } else {
6722e5b6d6dSopenharmony_ci                            if(offsets!=NULL) {
6732e5b6d6dSopenharmony_ci                                *offsets++=sourceIndex++;
6742e5b6d6dSopenharmony_ci                            }
6752e5b6d6dSopenharmony_ci                            cnv->charErrorBuffer[0]=toBase64[(c>>6)&0x3f];
6762e5b6d6dSopenharmony_ci                            cnv->charErrorBuffer[1]=toBase64[c&0x3f];
6772e5b6d6dSopenharmony_ci                            cnv->charErrorBufferLength=2;
6782e5b6d6dSopenharmony_ci                            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
6792e5b6d6dSopenharmony_ci                        }
6802e5b6d6dSopenharmony_ci                        bits=0;
6812e5b6d6dSopenharmony_ci                        base64Counter=0;
6822e5b6d6dSopenharmony_ci                        break;
6832e5b6d6dSopenharmony_ci                    default:
6842e5b6d6dSopenharmony_ci                        /* will never occur */
6852e5b6d6dSopenharmony_ci                        break;
6862e5b6d6dSopenharmony_ci                    }
6872e5b6d6dSopenharmony_ci                }
6882e5b6d6dSopenharmony_ci            } else {
6892e5b6d6dSopenharmony_ci                /* target is full */
6902e5b6d6dSopenharmony_ci                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
6912e5b6d6dSopenharmony_ci                break;
6922e5b6d6dSopenharmony_ci            }
6932e5b6d6dSopenharmony_ci        }
6942e5b6d6dSopenharmony_ci    }
6952e5b6d6dSopenharmony_ci
6962e5b6d6dSopenharmony_ci    if(pArgs->flush && source>=sourceLimit) {
6972e5b6d6dSopenharmony_ci        /* flush remaining bits to the target */
6982e5b6d6dSopenharmony_ci        if(!inDirectMode) {
6992e5b6d6dSopenharmony_ci            if (base64Counter!=0) {
7002e5b6d6dSopenharmony_ci                if(target<targetLimit) {
7012e5b6d6dSopenharmony_ci                    *target++=toBase64[bits];
7022e5b6d6dSopenharmony_ci                    if(offsets!=NULL) {
7032e5b6d6dSopenharmony_ci                        *offsets++=sourceIndex-1;
7042e5b6d6dSopenharmony_ci                    }
7052e5b6d6dSopenharmony_ci                } else {
7062e5b6d6dSopenharmony_ci                    cnv->charErrorBuffer[cnv->charErrorBufferLength++]=toBase64[bits];
7072e5b6d6dSopenharmony_ci                    *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
7082e5b6d6dSopenharmony_ci                }
7092e5b6d6dSopenharmony_ci            }
7102e5b6d6dSopenharmony_ci            /* Add final MINUS to terminate unicodeMode */
7112e5b6d6dSopenharmony_ci            if(target<targetLimit) {
7122e5b6d6dSopenharmony_ci                *target++=MINUS;
7132e5b6d6dSopenharmony_ci                if(offsets!=NULL) {
7142e5b6d6dSopenharmony_ci                    *offsets++=sourceIndex-1;
7152e5b6d6dSopenharmony_ci                }
7162e5b6d6dSopenharmony_ci            } else {
7172e5b6d6dSopenharmony_ci                cnv->charErrorBuffer[cnv->charErrorBufferLength++]=MINUS;
7182e5b6d6dSopenharmony_ci                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
7192e5b6d6dSopenharmony_ci            }
7202e5b6d6dSopenharmony_ci        }
7212e5b6d6dSopenharmony_ci        /* reset the state for the next conversion */
7222e5b6d6dSopenharmony_ci        cnv->fromUnicodeStatus=(cnv->fromUnicodeStatus&0xf0000000)|0x1000000; /* keep version, inDirectMode=true */
7232e5b6d6dSopenharmony_ci    } else {
7242e5b6d6dSopenharmony_ci        /* set the converter state back into UConverter */
7252e5b6d6dSopenharmony_ci        cnv->fromUnicodeStatus=
7262e5b6d6dSopenharmony_ci            (cnv->fromUnicodeStatus&0xf0000000)|    /* keep version*/
7272e5b6d6dSopenharmony_ci            ((uint32_t)inDirectMode<<24)|((uint32_t)base64Counter<<16)|(uint32_t)bits;
7282e5b6d6dSopenharmony_ci    }
7292e5b6d6dSopenharmony_ci
7302e5b6d6dSopenharmony_ci    /* write back the updated pointers */
7312e5b6d6dSopenharmony_ci    pArgs->source=source;
7322e5b6d6dSopenharmony_ci    pArgs->target=(char *)target;
7332e5b6d6dSopenharmony_ci    pArgs->offsets=offsets;
7342e5b6d6dSopenharmony_ci    return;
7352e5b6d6dSopenharmony_ci}
7362e5b6d6dSopenharmony_ci
7372e5b6d6dSopenharmony_cistatic const char * U_CALLCONV
7382e5b6d6dSopenharmony_ci_UTF7GetName(const UConverter *cnv) {
7392e5b6d6dSopenharmony_ci    switch(cnv->fromUnicodeStatus>>28) {
7402e5b6d6dSopenharmony_ci    case 1:
7412e5b6d6dSopenharmony_ci        return "UTF-7,version=1";
7422e5b6d6dSopenharmony_ci    default:
7432e5b6d6dSopenharmony_ci        return "UTF-7";
7442e5b6d6dSopenharmony_ci    }
7452e5b6d6dSopenharmony_ci}
7462e5b6d6dSopenharmony_ciU_CDECL_END
7472e5b6d6dSopenharmony_ci
7482e5b6d6dSopenharmony_cistatic const UConverterImpl _UTF7Impl={
7492e5b6d6dSopenharmony_ci    UCNV_UTF7,
7502e5b6d6dSopenharmony_ci
7512e5b6d6dSopenharmony_ci    NULL,
7522e5b6d6dSopenharmony_ci    NULL,
7532e5b6d6dSopenharmony_ci
7542e5b6d6dSopenharmony_ci    _UTF7Open,
7552e5b6d6dSopenharmony_ci    NULL,
7562e5b6d6dSopenharmony_ci    _UTF7Reset,
7572e5b6d6dSopenharmony_ci
7582e5b6d6dSopenharmony_ci    _UTF7ToUnicodeWithOffsets,
7592e5b6d6dSopenharmony_ci    _UTF7ToUnicodeWithOffsets,
7602e5b6d6dSopenharmony_ci    _UTF7FromUnicodeWithOffsets,
7612e5b6d6dSopenharmony_ci    _UTF7FromUnicodeWithOffsets,
7622e5b6d6dSopenharmony_ci    NULL,
7632e5b6d6dSopenharmony_ci
7642e5b6d6dSopenharmony_ci    NULL,
7652e5b6d6dSopenharmony_ci    _UTF7GetName,
7662e5b6d6dSopenharmony_ci    NULL, /* we don't need writeSub() because we never call a callback at fromUnicode() */
7672e5b6d6dSopenharmony_ci    NULL,
7682e5b6d6dSopenharmony_ci    ucnv_getCompleteUnicodeSet,
7692e5b6d6dSopenharmony_ci
7702e5b6d6dSopenharmony_ci    NULL,
7712e5b6d6dSopenharmony_ci    NULL
7722e5b6d6dSopenharmony_ci};
7732e5b6d6dSopenharmony_ci
7742e5b6d6dSopenharmony_cistatic const UConverterStaticData _UTF7StaticData={
7752e5b6d6dSopenharmony_ci    sizeof(UConverterStaticData),
7762e5b6d6dSopenharmony_ci    "UTF-7",
7772e5b6d6dSopenharmony_ci    0, /* TODO CCSID for UTF-7 */
7782e5b6d6dSopenharmony_ci    UCNV_IBM, UCNV_UTF7,
7792e5b6d6dSopenharmony_ci    1, 4,
7802e5b6d6dSopenharmony_ci    { 0x3f, 0, 0, 0 }, 1, /* the subchar is not used */
7812e5b6d6dSopenharmony_ci    false, false,
7822e5b6d6dSopenharmony_ci    0,
7832e5b6d6dSopenharmony_ci    0,
7842e5b6d6dSopenharmony_ci    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
7852e5b6d6dSopenharmony_ci};
7862e5b6d6dSopenharmony_ci
7872e5b6d6dSopenharmony_ciconst UConverterSharedData _UTF7Data=
7882e5b6d6dSopenharmony_ci        UCNV_IMMUTABLE_SHARED_DATA_INITIALIZER(&_UTF7StaticData, &_UTF7Impl);
7892e5b6d6dSopenharmony_ci
7902e5b6d6dSopenharmony_ci/* IMAP mailbox name encoding ----------------------------------------------- */
7912e5b6d6dSopenharmony_ci
7922e5b6d6dSopenharmony_ci/*
7932e5b6d6dSopenharmony_ci * RFC 2060: INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1
7942e5b6d6dSopenharmony_ci * http://www.ietf.org/rfc/rfc2060.txt
7952e5b6d6dSopenharmony_ci *
7962e5b6d6dSopenharmony_ci * 5.1.3.  Mailbox International Naming Convention
7972e5b6d6dSopenharmony_ci *
7982e5b6d6dSopenharmony_ci * By convention, international mailbox names are specified using a
7992e5b6d6dSopenharmony_ci * modified version of the UTF-7 encoding described in [UTF-7].  The
8002e5b6d6dSopenharmony_ci * purpose of these modifications is to correct the following problems
8012e5b6d6dSopenharmony_ci * with UTF-7:
8022e5b6d6dSopenharmony_ci *
8032e5b6d6dSopenharmony_ci *    1) UTF-7 uses the "+" character for shifting; this conflicts with
8042e5b6d6dSopenharmony_ci *       the common use of "+" in mailbox names, in particular USENET
8052e5b6d6dSopenharmony_ci *       newsgroup names.
8062e5b6d6dSopenharmony_ci *
8072e5b6d6dSopenharmony_ci *    2) UTF-7's encoding is BASE64 which uses the "/" character; this
8082e5b6d6dSopenharmony_ci *       conflicts with the use of "/" as a popular hierarchy delimiter.
8092e5b6d6dSopenharmony_ci *
8102e5b6d6dSopenharmony_ci *    3) UTF-7 prohibits the unencoded usage of "\"; this conflicts with
8112e5b6d6dSopenharmony_ci *       the use of "\" as a popular hierarchy delimiter.
8122e5b6d6dSopenharmony_ci *
8132e5b6d6dSopenharmony_ci *    4) UTF-7 prohibits the unencoded usage of "~"; this conflicts with
8142e5b6d6dSopenharmony_ci *       the use of "~" in some servers as a home directory indicator.
8152e5b6d6dSopenharmony_ci *
8162e5b6d6dSopenharmony_ci *    5) UTF-7 permits multiple alternate forms to represent the same
8172e5b6d6dSopenharmony_ci *       string; in particular, printable US-ASCII characters can be
8182e5b6d6dSopenharmony_ci *       represented in encoded form.
8192e5b6d6dSopenharmony_ci *
8202e5b6d6dSopenharmony_ci * In modified UTF-7, printable US-ASCII characters except for "&"
8212e5b6d6dSopenharmony_ci * represent themselves; that is, characters with octet values 0x20-0x25
8222e5b6d6dSopenharmony_ci * and 0x27-0x7e.  The character "&" (0x26) is represented by the two-
8232e5b6d6dSopenharmony_ci * octet sequence "&-".
8242e5b6d6dSopenharmony_ci *
8252e5b6d6dSopenharmony_ci * All other characters (octet values 0x00-0x1f, 0x7f-0xff, and all
8262e5b6d6dSopenharmony_ci * Unicode 16-bit octets) are represented in modified BASE64, with a
8272e5b6d6dSopenharmony_ci * further modification from [UTF-7] that "," is used instead of "/".
8282e5b6d6dSopenharmony_ci * Modified BASE64 MUST NOT be used to represent any printing US-ASCII
8292e5b6d6dSopenharmony_ci * character which can represent itself.
8302e5b6d6dSopenharmony_ci *
8312e5b6d6dSopenharmony_ci * "&" is used to shift to modified BASE64 and "-" to shift back to US-
8322e5b6d6dSopenharmony_ci * ASCII.  All names start in US-ASCII, and MUST end in US-ASCII (that
8332e5b6d6dSopenharmony_ci * is, a name that ends with a Unicode 16-bit octet MUST end with a "-
8342e5b6d6dSopenharmony_ci * ").
8352e5b6d6dSopenharmony_ci *
8362e5b6d6dSopenharmony_ci * For example, here is a mailbox name which mixes English, Japanese,
8372e5b6d6dSopenharmony_ci * and Chinese text: ~peter/mail/&ZeVnLIqe-/&U,BTFw-
8382e5b6d6dSopenharmony_ci */
8392e5b6d6dSopenharmony_ci
8402e5b6d6dSopenharmony_ci/*
8412e5b6d6dSopenharmony_ci * Tests for US-ASCII characters belonging to character classes
8422e5b6d6dSopenharmony_ci * defined in UTF-7.
8432e5b6d6dSopenharmony_ci *
8442e5b6d6dSopenharmony_ci * Set D (directly encoded characters) consists of the following
8452e5b6d6dSopenharmony_ci * characters: the upper and lower case letters A through Z
8462e5b6d6dSopenharmony_ci * and a through z, the 10 digits 0-9, and the following nine special
8472e5b6d6dSopenharmony_ci * characters (note that "+" and "=" are omitted):
8482e5b6d6dSopenharmony_ci *     '(),-./:?
8492e5b6d6dSopenharmony_ci *
8502e5b6d6dSopenharmony_ci * Set O (optional direct characters) consists of the following
8512e5b6d6dSopenharmony_ci * characters (note that "\" and "~" are omitted):
8522e5b6d6dSopenharmony_ci *     !"#$%&*;<=>@[]^_`{|}
8532e5b6d6dSopenharmony_ci *
8542e5b6d6dSopenharmony_ci * According to the rules in RFC 2152, the byte values for the following
8552e5b6d6dSopenharmony_ci * US-ASCII characters are not used in UTF-7 and are therefore illegal:
8562e5b6d6dSopenharmony_ci * - all C0 control codes except for CR LF TAB
8572e5b6d6dSopenharmony_ci * - BACKSLASH
8582e5b6d6dSopenharmony_ci * - TILDE
8592e5b6d6dSopenharmony_ci * - DEL
8602e5b6d6dSopenharmony_ci * - all codes beyond US-ASCII, i.e. all >127
8612e5b6d6dSopenharmony_ci */
8622e5b6d6dSopenharmony_ci
8632e5b6d6dSopenharmony_ci/* uses '&' not '+' to start a base64 sequence */
8642e5b6d6dSopenharmony_ci#define AMPERSAND 0x26
8652e5b6d6dSopenharmony_ci#define COMMA 0x2c
8662e5b6d6dSopenharmony_ci#define SLASH 0x2f
8672e5b6d6dSopenharmony_ci
8682e5b6d6dSopenharmony_ci/* legal byte values: all US-ASCII graphic characters 0x20..0x7e */
8692e5b6d6dSopenharmony_ci#define isLegalIMAP(c) (0x20<=(c) && (c)<=0x7e)
8702e5b6d6dSopenharmony_ci
8712e5b6d6dSopenharmony_ci/* direct-encode all of printable ASCII 0x20..0x7e except '&' 0x26 */
8722e5b6d6dSopenharmony_ci#define inSetDIMAP(c) (isLegalIMAP(c) && c!=AMPERSAND)
8732e5b6d6dSopenharmony_ci
8742e5b6d6dSopenharmony_ci#define TO_BASE64_IMAP(n) ((n)<63 ? toBase64[n] : COMMA)
8752e5b6d6dSopenharmony_ci#define FROM_BASE64_IMAP(c) ((c)==COMMA ? 63 : (c)==SLASH ? -1 : fromBase64[c])
8762e5b6d6dSopenharmony_ci
8772e5b6d6dSopenharmony_ci/*
8782e5b6d6dSopenharmony_ci * converter status values:
8792e5b6d6dSopenharmony_ci *
8802e5b6d6dSopenharmony_ci * toUnicodeStatus:
8812e5b6d6dSopenharmony_ci *     24 inDirectMode (boolean)
8822e5b6d6dSopenharmony_ci * 23..16 base64Counter (-1..7)
8832e5b6d6dSopenharmony_ci * 15..0  bits (up to 14 bits incoming base64)
8842e5b6d6dSopenharmony_ci *
8852e5b6d6dSopenharmony_ci * fromUnicodeStatus:
8862e5b6d6dSopenharmony_ci *     24 inDirectMode (boolean)
8872e5b6d6dSopenharmony_ci * 23..16 base64Counter (0..2)
8882e5b6d6dSopenharmony_ci *  7..0  bits (6 bits outgoing base64)
8892e5b6d6dSopenharmony_ci *
8902e5b6d6dSopenharmony_ci * ignore bits 31..25
8912e5b6d6dSopenharmony_ci */
8922e5b6d6dSopenharmony_ci
8932e5b6d6dSopenharmony_ciU_CDECL_BEGIN
8942e5b6d6dSopenharmony_cistatic void U_CALLCONV
8952e5b6d6dSopenharmony_ci_IMAPToUnicodeWithOffsets(UConverterToUnicodeArgs *pArgs,
8962e5b6d6dSopenharmony_ci                          UErrorCode *pErrorCode) {
8972e5b6d6dSopenharmony_ci    UConverter *cnv;
8982e5b6d6dSopenharmony_ci    const uint8_t *source, *sourceLimit;
8992e5b6d6dSopenharmony_ci    UChar *target;
9002e5b6d6dSopenharmony_ci    const UChar *targetLimit;
9012e5b6d6dSopenharmony_ci    int32_t *offsets;
9022e5b6d6dSopenharmony_ci
9032e5b6d6dSopenharmony_ci    uint8_t *bytes;
9042e5b6d6dSopenharmony_ci    uint8_t byteIndex;
9052e5b6d6dSopenharmony_ci
9062e5b6d6dSopenharmony_ci    int32_t length, targetCapacity;
9072e5b6d6dSopenharmony_ci
9082e5b6d6dSopenharmony_ci    /* UTF-7 state */
9092e5b6d6dSopenharmony_ci    uint16_t bits;
9102e5b6d6dSopenharmony_ci    int8_t base64Counter;
9112e5b6d6dSopenharmony_ci    UBool inDirectMode;
9122e5b6d6dSopenharmony_ci
9132e5b6d6dSopenharmony_ci    int8_t base64Value;
9142e5b6d6dSopenharmony_ci
9152e5b6d6dSopenharmony_ci    int32_t sourceIndex, nextSourceIndex;
9162e5b6d6dSopenharmony_ci
9172e5b6d6dSopenharmony_ci    UChar c;
9182e5b6d6dSopenharmony_ci    uint8_t b;
9192e5b6d6dSopenharmony_ci
9202e5b6d6dSopenharmony_ci    /* set up the local pointers */
9212e5b6d6dSopenharmony_ci    cnv=pArgs->converter;
9222e5b6d6dSopenharmony_ci
9232e5b6d6dSopenharmony_ci    source=(const uint8_t *)pArgs->source;
9242e5b6d6dSopenharmony_ci    sourceLimit=(const uint8_t *)pArgs->sourceLimit;
9252e5b6d6dSopenharmony_ci    target=pArgs->target;
9262e5b6d6dSopenharmony_ci    targetLimit=pArgs->targetLimit;
9272e5b6d6dSopenharmony_ci    offsets=pArgs->offsets;
9282e5b6d6dSopenharmony_ci    /* get the state machine state */
9292e5b6d6dSopenharmony_ci    {
9302e5b6d6dSopenharmony_ci        uint32_t status=cnv->toUnicodeStatus;
9312e5b6d6dSopenharmony_ci        inDirectMode=(UBool)((status>>24)&1);
9322e5b6d6dSopenharmony_ci        base64Counter=(int8_t)(status>>16);
9332e5b6d6dSopenharmony_ci        bits=(uint16_t)status;
9342e5b6d6dSopenharmony_ci    }
9352e5b6d6dSopenharmony_ci    bytes=cnv->toUBytes;
9362e5b6d6dSopenharmony_ci    byteIndex=cnv->toULength;
9372e5b6d6dSopenharmony_ci
9382e5b6d6dSopenharmony_ci    /* sourceIndex=-1 if the current character began in the previous buffer */
9392e5b6d6dSopenharmony_ci    sourceIndex=byteIndex==0 ? 0 : -1;
9402e5b6d6dSopenharmony_ci    nextSourceIndex=0;
9412e5b6d6dSopenharmony_ci
9422e5b6d6dSopenharmony_ci    if(inDirectMode) {
9432e5b6d6dSopenharmony_cidirectMode:
9442e5b6d6dSopenharmony_ci        /*
9452e5b6d6dSopenharmony_ci         * In Direct Mode, US-ASCII characters are encoded directly, i.e.,
9462e5b6d6dSopenharmony_ci         * with their US-ASCII byte values.
9472e5b6d6dSopenharmony_ci         * An ampersand starts Unicode (or "escape") Mode.
9482e5b6d6dSopenharmony_ci         *
9492e5b6d6dSopenharmony_ci         * In Direct Mode, only the sourceIndex is used.
9502e5b6d6dSopenharmony_ci         */
9512e5b6d6dSopenharmony_ci        byteIndex=0;
9522e5b6d6dSopenharmony_ci        length=(int32_t)(sourceLimit-source);
9532e5b6d6dSopenharmony_ci        targetCapacity=(int32_t)(targetLimit-target);
9542e5b6d6dSopenharmony_ci        if(length>targetCapacity) {
9552e5b6d6dSopenharmony_ci            length=targetCapacity;
9562e5b6d6dSopenharmony_ci        }
9572e5b6d6dSopenharmony_ci        while(length>0) {
9582e5b6d6dSopenharmony_ci            b=*source++;
9592e5b6d6dSopenharmony_ci            if(!isLegalIMAP(b)) {
9602e5b6d6dSopenharmony_ci                /* illegal */
9612e5b6d6dSopenharmony_ci                bytes[0]=b;
9622e5b6d6dSopenharmony_ci                byteIndex=1;
9632e5b6d6dSopenharmony_ci                *pErrorCode=U_ILLEGAL_CHAR_FOUND;
9642e5b6d6dSopenharmony_ci                break;
9652e5b6d6dSopenharmony_ci            } else if(b!=AMPERSAND) {
9662e5b6d6dSopenharmony_ci                /* write directly encoded character */
9672e5b6d6dSopenharmony_ci                *target++=b;
9682e5b6d6dSopenharmony_ci                if(offsets!=NULL) {
9692e5b6d6dSopenharmony_ci                    *offsets++=sourceIndex++;
9702e5b6d6dSopenharmony_ci                }
9712e5b6d6dSopenharmony_ci            } else /* AMPERSAND */ {
9722e5b6d6dSopenharmony_ci                /* switch to Unicode mode */
9732e5b6d6dSopenharmony_ci                nextSourceIndex=++sourceIndex;
9742e5b6d6dSopenharmony_ci                inDirectMode=false;
9752e5b6d6dSopenharmony_ci                byteIndex=0;
9762e5b6d6dSopenharmony_ci                bits=0;
9772e5b6d6dSopenharmony_ci                base64Counter=-1;
9782e5b6d6dSopenharmony_ci                goto unicodeMode;
9792e5b6d6dSopenharmony_ci            }
9802e5b6d6dSopenharmony_ci            --length;
9812e5b6d6dSopenharmony_ci        }
9822e5b6d6dSopenharmony_ci        if(source<sourceLimit && target>=targetLimit) {
9832e5b6d6dSopenharmony_ci            /* target is full */
9842e5b6d6dSopenharmony_ci            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
9852e5b6d6dSopenharmony_ci        }
9862e5b6d6dSopenharmony_ci    } else {
9872e5b6d6dSopenharmony_ciunicodeMode:
9882e5b6d6dSopenharmony_ci        /*
9892e5b6d6dSopenharmony_ci         * In Unicode (or "escape") Mode, UTF-16BE is base64-encoded.
9902e5b6d6dSopenharmony_ci         * The base64 sequence ends with any character that is not in the base64 alphabet.
9912e5b6d6dSopenharmony_ci         * A terminating minus sign is consumed.
9922e5b6d6dSopenharmony_ci         * US-ASCII must not be base64-ed.
9932e5b6d6dSopenharmony_ci         *
9942e5b6d6dSopenharmony_ci         * In Unicode Mode, the sourceIndex has the index to the start of the current
9952e5b6d6dSopenharmony_ci         * base64 bytes, while nextSourceIndex is precisely parallel to source,
9962e5b6d6dSopenharmony_ci         * keeping the index to the following byte.
9972e5b6d6dSopenharmony_ci         * Note that in 2 out of 3 cases, UChars overlap within a base64 byte.
9982e5b6d6dSopenharmony_ci         */
9992e5b6d6dSopenharmony_ci        while(source<sourceLimit) {
10002e5b6d6dSopenharmony_ci            if(target<targetLimit) {
10012e5b6d6dSopenharmony_ci                bytes[byteIndex++]=b=*source++;
10022e5b6d6dSopenharmony_ci                ++nextSourceIndex;
10032e5b6d6dSopenharmony_ci                if(b>0x7e) {
10042e5b6d6dSopenharmony_ci                    /* illegal - test other illegal US-ASCII values by base64Value==-3 */
10052e5b6d6dSopenharmony_ci                    inDirectMode=true;
10062e5b6d6dSopenharmony_ci                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
10072e5b6d6dSopenharmony_ci                    break;
10082e5b6d6dSopenharmony_ci                } else if((base64Value=FROM_BASE64_IMAP(b))>=0) {
10092e5b6d6dSopenharmony_ci                    /* collect base64 bytes into UChars */
10102e5b6d6dSopenharmony_ci                    switch(base64Counter) {
10112e5b6d6dSopenharmony_ci                    case -1: /* -1 is immediately after the & */
10122e5b6d6dSopenharmony_ci                    case 0:
10132e5b6d6dSopenharmony_ci                        bits=base64Value;
10142e5b6d6dSopenharmony_ci                        base64Counter=1;
10152e5b6d6dSopenharmony_ci                        break;
10162e5b6d6dSopenharmony_ci                    case 1:
10172e5b6d6dSopenharmony_ci                    case 3:
10182e5b6d6dSopenharmony_ci                    case 4:
10192e5b6d6dSopenharmony_ci                    case 6:
10202e5b6d6dSopenharmony_ci                        bits=(uint16_t)((bits<<6)|base64Value);
10212e5b6d6dSopenharmony_ci                        ++base64Counter;
10222e5b6d6dSopenharmony_ci                        break;
10232e5b6d6dSopenharmony_ci                    case 2:
10242e5b6d6dSopenharmony_ci                        c=(UChar)((bits<<4)|(base64Value>>2));
10252e5b6d6dSopenharmony_ci                        if(isLegalIMAP(c)) {
10262e5b6d6dSopenharmony_ci                            /* illegal */
10272e5b6d6dSopenharmony_ci                            inDirectMode=true;
10282e5b6d6dSopenharmony_ci                            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
10292e5b6d6dSopenharmony_ci                            goto endloop;
10302e5b6d6dSopenharmony_ci                        }
10312e5b6d6dSopenharmony_ci                        *target++=c;
10322e5b6d6dSopenharmony_ci                        if(offsets!=NULL) {
10332e5b6d6dSopenharmony_ci                            *offsets++=sourceIndex;
10342e5b6d6dSopenharmony_ci                            sourceIndex=nextSourceIndex-1;
10352e5b6d6dSopenharmony_ci                        }
10362e5b6d6dSopenharmony_ci                        bytes[0]=b; /* keep this byte in case an error occurs */
10372e5b6d6dSopenharmony_ci                        byteIndex=1;
10382e5b6d6dSopenharmony_ci                        bits=(uint16_t)(base64Value&3);
10392e5b6d6dSopenharmony_ci                        base64Counter=3;
10402e5b6d6dSopenharmony_ci                        break;
10412e5b6d6dSopenharmony_ci                    case 5:
10422e5b6d6dSopenharmony_ci                        c=(UChar)((bits<<2)|(base64Value>>4));
10432e5b6d6dSopenharmony_ci                        if(isLegalIMAP(c)) {
10442e5b6d6dSopenharmony_ci                            /* illegal */
10452e5b6d6dSopenharmony_ci                            inDirectMode=true;
10462e5b6d6dSopenharmony_ci                            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
10472e5b6d6dSopenharmony_ci                            goto endloop;
10482e5b6d6dSopenharmony_ci                        }
10492e5b6d6dSopenharmony_ci                        *target++=c;
10502e5b6d6dSopenharmony_ci                        if(offsets!=NULL) {
10512e5b6d6dSopenharmony_ci                            *offsets++=sourceIndex;
10522e5b6d6dSopenharmony_ci                            sourceIndex=nextSourceIndex-1;
10532e5b6d6dSopenharmony_ci                        }
10542e5b6d6dSopenharmony_ci                        bytes[0]=b; /* keep this byte in case an error occurs */
10552e5b6d6dSopenharmony_ci                        byteIndex=1;
10562e5b6d6dSopenharmony_ci                        bits=(uint16_t)(base64Value&15);
10572e5b6d6dSopenharmony_ci                        base64Counter=6;
10582e5b6d6dSopenharmony_ci                        break;
10592e5b6d6dSopenharmony_ci                    case 7:
10602e5b6d6dSopenharmony_ci                        c=(UChar)((bits<<6)|base64Value);
10612e5b6d6dSopenharmony_ci                        if(isLegalIMAP(c)) {
10622e5b6d6dSopenharmony_ci                            /* illegal */
10632e5b6d6dSopenharmony_ci                            inDirectMode=true;
10642e5b6d6dSopenharmony_ci                            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
10652e5b6d6dSopenharmony_ci                            goto endloop;
10662e5b6d6dSopenharmony_ci                        }
10672e5b6d6dSopenharmony_ci                        *target++=c;
10682e5b6d6dSopenharmony_ci                        if(offsets!=NULL) {
10692e5b6d6dSopenharmony_ci                            *offsets++=sourceIndex;
10702e5b6d6dSopenharmony_ci                            sourceIndex=nextSourceIndex;
10712e5b6d6dSopenharmony_ci                        }
10722e5b6d6dSopenharmony_ci                        byteIndex=0;
10732e5b6d6dSopenharmony_ci                        bits=0;
10742e5b6d6dSopenharmony_ci                        base64Counter=0;
10752e5b6d6dSopenharmony_ci                        break;
10762e5b6d6dSopenharmony_ci                    default:
10772e5b6d6dSopenharmony_ci                        /* will never occur */
10782e5b6d6dSopenharmony_ci                        break;
10792e5b6d6dSopenharmony_ci                    }
10802e5b6d6dSopenharmony_ci                } else if(base64Value==-2) {
10812e5b6d6dSopenharmony_ci                    /* minus sign terminates the base64 sequence */
10822e5b6d6dSopenharmony_ci                    inDirectMode=true;
10832e5b6d6dSopenharmony_ci                    if(base64Counter==-1) {
10842e5b6d6dSopenharmony_ci                        /* &- i.e. a minus immediately following an ampersand */
10852e5b6d6dSopenharmony_ci                        *target++=AMPERSAND;
10862e5b6d6dSopenharmony_ci                        if(offsets!=NULL) {
10872e5b6d6dSopenharmony_ci                            *offsets++=sourceIndex-1;
10882e5b6d6dSopenharmony_ci                        }
10892e5b6d6dSopenharmony_ci                    } else {
10902e5b6d6dSopenharmony_ci                        /* absorb the minus and leave the Unicode Mode */
10912e5b6d6dSopenharmony_ci                        if(bits!=0 || (base64Counter!=0 && base64Counter!=3 && base64Counter!=6)) {
10922e5b6d6dSopenharmony_ci                            /* bits are illegally left over, a UChar is incomplete */
10932e5b6d6dSopenharmony_ci                            /* base64Counter other than 0, 3, 6 means non-minimal zero-padding, also illegal */
10942e5b6d6dSopenharmony_ci                            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
10952e5b6d6dSopenharmony_ci                            break;
10962e5b6d6dSopenharmony_ci                        }
10972e5b6d6dSopenharmony_ci                    }
10982e5b6d6dSopenharmony_ci                    sourceIndex=nextSourceIndex;
10992e5b6d6dSopenharmony_ci                    goto directMode;
11002e5b6d6dSopenharmony_ci                } else {
11012e5b6d6dSopenharmony_ci                    if(base64Counter==-1) {
11022e5b6d6dSopenharmony_ci                        /* illegal: & immediately followed by something other than base64 or minus sign */
11032e5b6d6dSopenharmony_ci                        /* include the ampersand in the reported sequence */
11042e5b6d6dSopenharmony_ci                        --sourceIndex;
11052e5b6d6dSopenharmony_ci                        bytes[0]=AMPERSAND;
11062e5b6d6dSopenharmony_ci                        bytes[1]=b;
11072e5b6d6dSopenharmony_ci                        byteIndex=2;
11082e5b6d6dSopenharmony_ci                    }
11092e5b6d6dSopenharmony_ci                    /* base64Value==-1 for characters that are illegal only in Unicode mode */
11102e5b6d6dSopenharmony_ci                    /* base64Value==-3 for illegal characters */
11112e5b6d6dSopenharmony_ci                    /* illegal */
11122e5b6d6dSopenharmony_ci                    inDirectMode=true;
11132e5b6d6dSopenharmony_ci                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
11142e5b6d6dSopenharmony_ci                    break;
11152e5b6d6dSopenharmony_ci                }
11162e5b6d6dSopenharmony_ci            } else {
11172e5b6d6dSopenharmony_ci                /* target is full */
11182e5b6d6dSopenharmony_ci                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
11192e5b6d6dSopenharmony_ci                break;
11202e5b6d6dSopenharmony_ci            }
11212e5b6d6dSopenharmony_ci        }
11222e5b6d6dSopenharmony_ci    }
11232e5b6d6dSopenharmony_ciendloop:
11242e5b6d6dSopenharmony_ci
11252e5b6d6dSopenharmony_ci    /*
11262e5b6d6dSopenharmony_ci     * the end of the input stream and detection of truncated input
11272e5b6d6dSopenharmony_ci     * are handled by the framework, but here we must check if we are in Unicode
11282e5b6d6dSopenharmony_ci     * mode and byteIndex==0 because we must end in direct mode
11292e5b6d6dSopenharmony_ci     *
11302e5b6d6dSopenharmony_ci     * conditions:
11312e5b6d6dSopenharmony_ci     *   successful
11322e5b6d6dSopenharmony_ci     *   in Unicode mode and byteIndex==0
11332e5b6d6dSopenharmony_ci     *   end of input and no truncated input
11342e5b6d6dSopenharmony_ci     */
11352e5b6d6dSopenharmony_ci    if( U_SUCCESS(*pErrorCode) &&
11362e5b6d6dSopenharmony_ci        !inDirectMode && byteIndex==0 &&
11372e5b6d6dSopenharmony_ci        pArgs->flush && source>=sourceLimit
11382e5b6d6dSopenharmony_ci    ) {
11392e5b6d6dSopenharmony_ci        if(base64Counter==-1) {
11402e5b6d6dSopenharmony_ci            /* & at the very end of the input */
11412e5b6d6dSopenharmony_ci            /* make the ampersand the reported sequence */
11422e5b6d6dSopenharmony_ci            bytes[0]=AMPERSAND;
11432e5b6d6dSopenharmony_ci            byteIndex=1;
11442e5b6d6dSopenharmony_ci        }
11452e5b6d6dSopenharmony_ci        /* else if(base64Counter!=-1) byteIndex remains 0 because there is no particular byte sequence */
11462e5b6d6dSopenharmony_ci
11472e5b6d6dSopenharmony_ci        inDirectMode=true; /* avoid looping */
11482e5b6d6dSopenharmony_ci        *pErrorCode=U_TRUNCATED_CHAR_FOUND;
11492e5b6d6dSopenharmony_ci    }
11502e5b6d6dSopenharmony_ci
11512e5b6d6dSopenharmony_ci    /* set the converter state back into UConverter */
11522e5b6d6dSopenharmony_ci    cnv->toUnicodeStatus=((uint32_t)inDirectMode<<24)|((uint32_t)((uint8_t)base64Counter)<<16)|(uint32_t)bits;
11532e5b6d6dSopenharmony_ci    cnv->toULength=byteIndex;
11542e5b6d6dSopenharmony_ci
11552e5b6d6dSopenharmony_ci    /* write back the updated pointers */
11562e5b6d6dSopenharmony_ci    pArgs->source=(const char *)source;
11572e5b6d6dSopenharmony_ci    pArgs->target=target;
11582e5b6d6dSopenharmony_ci    pArgs->offsets=offsets;
11592e5b6d6dSopenharmony_ci    return;
11602e5b6d6dSopenharmony_ci}
11612e5b6d6dSopenharmony_ci
11622e5b6d6dSopenharmony_cistatic void U_CALLCONV
11632e5b6d6dSopenharmony_ci_IMAPFromUnicodeWithOffsets(UConverterFromUnicodeArgs *pArgs,
11642e5b6d6dSopenharmony_ci                            UErrorCode *pErrorCode) {
11652e5b6d6dSopenharmony_ci    UConverter *cnv;
11662e5b6d6dSopenharmony_ci    const UChar *source, *sourceLimit;
11672e5b6d6dSopenharmony_ci    uint8_t *target, *targetLimit;
11682e5b6d6dSopenharmony_ci    int32_t *offsets;
11692e5b6d6dSopenharmony_ci
11702e5b6d6dSopenharmony_ci    int32_t length, targetCapacity, sourceIndex;
11712e5b6d6dSopenharmony_ci    UChar c;
11722e5b6d6dSopenharmony_ci    uint8_t b;
11732e5b6d6dSopenharmony_ci
11742e5b6d6dSopenharmony_ci    /* UTF-7 state */
11752e5b6d6dSopenharmony_ci    uint8_t bits;
11762e5b6d6dSopenharmony_ci    int8_t base64Counter;
11772e5b6d6dSopenharmony_ci    UBool inDirectMode;
11782e5b6d6dSopenharmony_ci
11792e5b6d6dSopenharmony_ci    /* set up the local pointers */
11802e5b6d6dSopenharmony_ci    cnv=pArgs->converter;
11812e5b6d6dSopenharmony_ci
11822e5b6d6dSopenharmony_ci    /* set up the local pointers */
11832e5b6d6dSopenharmony_ci    source=pArgs->source;
11842e5b6d6dSopenharmony_ci    sourceLimit=pArgs->sourceLimit;
11852e5b6d6dSopenharmony_ci    target=(uint8_t *)pArgs->target;
11862e5b6d6dSopenharmony_ci    targetLimit=(uint8_t *)pArgs->targetLimit;
11872e5b6d6dSopenharmony_ci    offsets=pArgs->offsets;
11882e5b6d6dSopenharmony_ci
11892e5b6d6dSopenharmony_ci    /* get the state machine state */
11902e5b6d6dSopenharmony_ci    {
11912e5b6d6dSopenharmony_ci        uint32_t status=cnv->fromUnicodeStatus;
11922e5b6d6dSopenharmony_ci        inDirectMode=(UBool)((status>>24)&1);
11932e5b6d6dSopenharmony_ci        base64Counter=(int8_t)(status>>16);
11942e5b6d6dSopenharmony_ci        bits=(uint8_t)status;
11952e5b6d6dSopenharmony_ci    }
11962e5b6d6dSopenharmony_ci
11972e5b6d6dSopenharmony_ci    /* UTF-7 always encodes UTF-16 code units, therefore we need only a simple sourceIndex */
11982e5b6d6dSopenharmony_ci    sourceIndex=0;
11992e5b6d6dSopenharmony_ci
12002e5b6d6dSopenharmony_ci    if(inDirectMode) {
12012e5b6d6dSopenharmony_cidirectMode:
12022e5b6d6dSopenharmony_ci        length=(int32_t)(sourceLimit-source);
12032e5b6d6dSopenharmony_ci        targetCapacity=(int32_t)(targetLimit-target);
12042e5b6d6dSopenharmony_ci        if(length>targetCapacity) {
12052e5b6d6dSopenharmony_ci            length=targetCapacity;
12062e5b6d6dSopenharmony_ci        }
12072e5b6d6dSopenharmony_ci        while(length>0) {
12082e5b6d6dSopenharmony_ci            c=*source++;
12092e5b6d6dSopenharmony_ci            /* encode 0x20..0x7e except '&' directly */
12102e5b6d6dSopenharmony_ci            if(inSetDIMAP(c)) {
12112e5b6d6dSopenharmony_ci                /* encode directly */
12122e5b6d6dSopenharmony_ci                *target++=(uint8_t)c;
12132e5b6d6dSopenharmony_ci                if(offsets!=NULL) {
12142e5b6d6dSopenharmony_ci                    *offsets++=sourceIndex++;
12152e5b6d6dSopenharmony_ci                }
12162e5b6d6dSopenharmony_ci            } else if(c==AMPERSAND) {
12172e5b6d6dSopenharmony_ci                /* output &- for & */
12182e5b6d6dSopenharmony_ci                *target++=AMPERSAND;
12192e5b6d6dSopenharmony_ci                if(target<targetLimit) {
12202e5b6d6dSopenharmony_ci                    *target++=MINUS;
12212e5b6d6dSopenharmony_ci                    if(offsets!=NULL) {
12222e5b6d6dSopenharmony_ci                        *offsets++=sourceIndex;
12232e5b6d6dSopenharmony_ci                        *offsets++=sourceIndex++;
12242e5b6d6dSopenharmony_ci                    }
12252e5b6d6dSopenharmony_ci                    /* realign length and targetCapacity */
12262e5b6d6dSopenharmony_ci                    goto directMode;
12272e5b6d6dSopenharmony_ci                } else {
12282e5b6d6dSopenharmony_ci                    if(offsets!=NULL) {
12292e5b6d6dSopenharmony_ci                        *offsets++=sourceIndex++;
12302e5b6d6dSopenharmony_ci                    }
12312e5b6d6dSopenharmony_ci                    cnv->charErrorBuffer[0]=MINUS;
12322e5b6d6dSopenharmony_ci                    cnv->charErrorBufferLength=1;
12332e5b6d6dSopenharmony_ci                    *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
12342e5b6d6dSopenharmony_ci                    break;
12352e5b6d6dSopenharmony_ci                }
12362e5b6d6dSopenharmony_ci            } else {
12372e5b6d6dSopenharmony_ci                /* un-read this character and switch to Unicode Mode */
12382e5b6d6dSopenharmony_ci                --source;
12392e5b6d6dSopenharmony_ci                *target++=AMPERSAND;
12402e5b6d6dSopenharmony_ci                if(offsets!=NULL) {
12412e5b6d6dSopenharmony_ci                    *offsets++=sourceIndex;
12422e5b6d6dSopenharmony_ci                }
12432e5b6d6dSopenharmony_ci                inDirectMode=false;
12442e5b6d6dSopenharmony_ci                base64Counter=0;
12452e5b6d6dSopenharmony_ci                goto unicodeMode;
12462e5b6d6dSopenharmony_ci            }
12472e5b6d6dSopenharmony_ci            --length;
12482e5b6d6dSopenharmony_ci        }
12492e5b6d6dSopenharmony_ci        if(source<sourceLimit && target>=targetLimit) {
12502e5b6d6dSopenharmony_ci            /* target is full */
12512e5b6d6dSopenharmony_ci            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
12522e5b6d6dSopenharmony_ci        }
12532e5b6d6dSopenharmony_ci    } else {
12542e5b6d6dSopenharmony_ciunicodeMode:
12552e5b6d6dSopenharmony_ci        while(source<sourceLimit) {
12562e5b6d6dSopenharmony_ci            if(target<targetLimit) {
12572e5b6d6dSopenharmony_ci                c=*source++;
12582e5b6d6dSopenharmony_ci                if(isLegalIMAP(c)) {
12592e5b6d6dSopenharmony_ci                    /* encode directly */
12602e5b6d6dSopenharmony_ci                    inDirectMode=true;
12612e5b6d6dSopenharmony_ci
12622e5b6d6dSopenharmony_ci                    /* trick: back out this character to make this easier */
12632e5b6d6dSopenharmony_ci                    --source;
12642e5b6d6dSopenharmony_ci
12652e5b6d6dSopenharmony_ci                    /* terminate the base64 sequence */
12662e5b6d6dSopenharmony_ci                    if(base64Counter!=0) {
12672e5b6d6dSopenharmony_ci                        /* write remaining bits for the previous character */
12682e5b6d6dSopenharmony_ci                        *target++=TO_BASE64_IMAP(bits);
12692e5b6d6dSopenharmony_ci                        if(offsets!=NULL) {
12702e5b6d6dSopenharmony_ci                            *offsets++=sourceIndex-1;
12712e5b6d6dSopenharmony_ci                        }
12722e5b6d6dSopenharmony_ci                    }
12732e5b6d6dSopenharmony_ci                    /* need to terminate with a minus */
12742e5b6d6dSopenharmony_ci                    if(target<targetLimit) {
12752e5b6d6dSopenharmony_ci                        *target++=MINUS;
12762e5b6d6dSopenharmony_ci                        if(offsets!=NULL) {
12772e5b6d6dSopenharmony_ci                            *offsets++=sourceIndex-1;
12782e5b6d6dSopenharmony_ci                        }
12792e5b6d6dSopenharmony_ci                    } else {
12802e5b6d6dSopenharmony_ci                        cnv->charErrorBuffer[0]=MINUS;
12812e5b6d6dSopenharmony_ci                        cnv->charErrorBufferLength=1;
12822e5b6d6dSopenharmony_ci                        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
12832e5b6d6dSopenharmony_ci                        break;
12842e5b6d6dSopenharmony_ci                    }
12852e5b6d6dSopenharmony_ci                    goto directMode;
12862e5b6d6dSopenharmony_ci                } else {
12872e5b6d6dSopenharmony_ci                    /*
12882e5b6d6dSopenharmony_ci                     * base64 this character:
12892e5b6d6dSopenharmony_ci                     * Output 2 or 3 base64 bytes for the remaining bits of the previous character
12902e5b6d6dSopenharmony_ci                     * and the bits of this character, each implicitly in UTF-16BE.
12912e5b6d6dSopenharmony_ci                     *
12922e5b6d6dSopenharmony_ci                     * Here, bits is an 8-bit variable because only 6 bits need to be kept from one
12932e5b6d6dSopenharmony_ci                     * character to the next. The actual 2 or 4 bits are shifted to the left edge
12942e5b6d6dSopenharmony_ci                     * of the 6-bits field 5..0 to make the termination of the base64 sequence easier.
12952e5b6d6dSopenharmony_ci                     */
12962e5b6d6dSopenharmony_ci                    switch(base64Counter) {
12972e5b6d6dSopenharmony_ci                    case 0:
12982e5b6d6dSopenharmony_ci                        b=(uint8_t)(c>>10);
12992e5b6d6dSopenharmony_ci                        *target++=TO_BASE64_IMAP(b);
13002e5b6d6dSopenharmony_ci                        if(target<targetLimit) {
13012e5b6d6dSopenharmony_ci                            b=(uint8_t)((c>>4)&0x3f);
13022e5b6d6dSopenharmony_ci                            *target++=TO_BASE64_IMAP(b);
13032e5b6d6dSopenharmony_ci                            if(offsets!=NULL) {
13042e5b6d6dSopenharmony_ci                                *offsets++=sourceIndex;
13052e5b6d6dSopenharmony_ci                                *offsets++=sourceIndex++;
13062e5b6d6dSopenharmony_ci                            }
13072e5b6d6dSopenharmony_ci                        } else {
13082e5b6d6dSopenharmony_ci                            if(offsets!=NULL) {
13092e5b6d6dSopenharmony_ci                                *offsets++=sourceIndex++;
13102e5b6d6dSopenharmony_ci                            }
13112e5b6d6dSopenharmony_ci                            b=(uint8_t)((c>>4)&0x3f);
13122e5b6d6dSopenharmony_ci                            cnv->charErrorBuffer[0]=TO_BASE64_IMAP(b);
13132e5b6d6dSopenharmony_ci                            cnv->charErrorBufferLength=1;
13142e5b6d6dSopenharmony_ci                            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
13152e5b6d6dSopenharmony_ci                        }
13162e5b6d6dSopenharmony_ci                        bits=(uint8_t)((c&15)<<2);
13172e5b6d6dSopenharmony_ci                        base64Counter=1;
13182e5b6d6dSopenharmony_ci                        break;
13192e5b6d6dSopenharmony_ci                    case 1:
13202e5b6d6dSopenharmony_ci                        b=(uint8_t)(bits|(c>>14));
13212e5b6d6dSopenharmony_ci                        *target++=TO_BASE64_IMAP(b);
13222e5b6d6dSopenharmony_ci                        if(target<targetLimit) {
13232e5b6d6dSopenharmony_ci                            b=(uint8_t)((c>>8)&0x3f);
13242e5b6d6dSopenharmony_ci                            *target++=TO_BASE64_IMAP(b);
13252e5b6d6dSopenharmony_ci                            if(target<targetLimit) {
13262e5b6d6dSopenharmony_ci                                b=(uint8_t)((c>>2)&0x3f);
13272e5b6d6dSopenharmony_ci                                *target++=TO_BASE64_IMAP(b);
13282e5b6d6dSopenharmony_ci                                if(offsets!=NULL) {
13292e5b6d6dSopenharmony_ci                                    *offsets++=sourceIndex;
13302e5b6d6dSopenharmony_ci                                    *offsets++=sourceIndex;
13312e5b6d6dSopenharmony_ci                                    *offsets++=sourceIndex++;
13322e5b6d6dSopenharmony_ci                                }
13332e5b6d6dSopenharmony_ci                            } else {
13342e5b6d6dSopenharmony_ci                                if(offsets!=NULL) {
13352e5b6d6dSopenharmony_ci                                    *offsets++=sourceIndex;
13362e5b6d6dSopenharmony_ci                                    *offsets++=sourceIndex++;
13372e5b6d6dSopenharmony_ci                                }
13382e5b6d6dSopenharmony_ci                                b=(uint8_t)((c>>2)&0x3f);
13392e5b6d6dSopenharmony_ci                                cnv->charErrorBuffer[0]=TO_BASE64_IMAP(b);
13402e5b6d6dSopenharmony_ci                                cnv->charErrorBufferLength=1;
13412e5b6d6dSopenharmony_ci                                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
13422e5b6d6dSopenharmony_ci                            }
13432e5b6d6dSopenharmony_ci                        } else {
13442e5b6d6dSopenharmony_ci                            if(offsets!=NULL) {
13452e5b6d6dSopenharmony_ci                                *offsets++=sourceIndex++;
13462e5b6d6dSopenharmony_ci                            }
13472e5b6d6dSopenharmony_ci                            b=(uint8_t)((c>>8)&0x3f);
13482e5b6d6dSopenharmony_ci                            cnv->charErrorBuffer[0]=TO_BASE64_IMAP(b);
13492e5b6d6dSopenharmony_ci                            b=(uint8_t)((c>>2)&0x3f);
13502e5b6d6dSopenharmony_ci                            cnv->charErrorBuffer[1]=TO_BASE64_IMAP(b);
13512e5b6d6dSopenharmony_ci                            cnv->charErrorBufferLength=2;
13522e5b6d6dSopenharmony_ci                            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
13532e5b6d6dSopenharmony_ci                        }
13542e5b6d6dSopenharmony_ci                        bits=(uint8_t)((c&3)<<4);
13552e5b6d6dSopenharmony_ci                        base64Counter=2;
13562e5b6d6dSopenharmony_ci                        break;
13572e5b6d6dSopenharmony_ci                    case 2:
13582e5b6d6dSopenharmony_ci                        b=(uint8_t)(bits|(c>>12));
13592e5b6d6dSopenharmony_ci                        *target++=TO_BASE64_IMAP(b);
13602e5b6d6dSopenharmony_ci                        if(target<targetLimit) {
13612e5b6d6dSopenharmony_ci                            b=(uint8_t)((c>>6)&0x3f);
13622e5b6d6dSopenharmony_ci                            *target++=TO_BASE64_IMAP(b);
13632e5b6d6dSopenharmony_ci                            if(target<targetLimit) {
13642e5b6d6dSopenharmony_ci                                b=(uint8_t)(c&0x3f);
13652e5b6d6dSopenharmony_ci                                *target++=TO_BASE64_IMAP(b);
13662e5b6d6dSopenharmony_ci                                if(offsets!=NULL) {
13672e5b6d6dSopenharmony_ci                                    *offsets++=sourceIndex;
13682e5b6d6dSopenharmony_ci                                    *offsets++=sourceIndex;
13692e5b6d6dSopenharmony_ci                                    *offsets++=sourceIndex++;
13702e5b6d6dSopenharmony_ci                                }
13712e5b6d6dSopenharmony_ci                            } else {
13722e5b6d6dSopenharmony_ci                                if(offsets!=NULL) {
13732e5b6d6dSopenharmony_ci                                    *offsets++=sourceIndex;
13742e5b6d6dSopenharmony_ci                                    *offsets++=sourceIndex++;
13752e5b6d6dSopenharmony_ci                                }
13762e5b6d6dSopenharmony_ci                                b=(uint8_t)(c&0x3f);
13772e5b6d6dSopenharmony_ci                                cnv->charErrorBuffer[0]=TO_BASE64_IMAP(b);
13782e5b6d6dSopenharmony_ci                                cnv->charErrorBufferLength=1;
13792e5b6d6dSopenharmony_ci                                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
13802e5b6d6dSopenharmony_ci                            }
13812e5b6d6dSopenharmony_ci                        } else {
13822e5b6d6dSopenharmony_ci                            if(offsets!=NULL) {
13832e5b6d6dSopenharmony_ci                                *offsets++=sourceIndex++;
13842e5b6d6dSopenharmony_ci                            }
13852e5b6d6dSopenharmony_ci                            b=(uint8_t)((c>>6)&0x3f);
13862e5b6d6dSopenharmony_ci                            cnv->charErrorBuffer[0]=TO_BASE64_IMAP(b);
13872e5b6d6dSopenharmony_ci                            b=(uint8_t)(c&0x3f);
13882e5b6d6dSopenharmony_ci                            cnv->charErrorBuffer[1]=TO_BASE64_IMAP(b);
13892e5b6d6dSopenharmony_ci                            cnv->charErrorBufferLength=2;
13902e5b6d6dSopenharmony_ci                            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
13912e5b6d6dSopenharmony_ci                        }
13922e5b6d6dSopenharmony_ci                        bits=0;
13932e5b6d6dSopenharmony_ci                        base64Counter=0;
13942e5b6d6dSopenharmony_ci                        break;
13952e5b6d6dSopenharmony_ci                    default:
13962e5b6d6dSopenharmony_ci                        /* will never occur */
13972e5b6d6dSopenharmony_ci                        break;
13982e5b6d6dSopenharmony_ci                    }
13992e5b6d6dSopenharmony_ci                }
14002e5b6d6dSopenharmony_ci            } else {
14012e5b6d6dSopenharmony_ci                /* target is full */
14022e5b6d6dSopenharmony_ci                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
14032e5b6d6dSopenharmony_ci                break;
14042e5b6d6dSopenharmony_ci            }
14052e5b6d6dSopenharmony_ci        }
14062e5b6d6dSopenharmony_ci    }
14072e5b6d6dSopenharmony_ci
14082e5b6d6dSopenharmony_ci    if(pArgs->flush && source>=sourceLimit) {
14092e5b6d6dSopenharmony_ci        /* flush remaining bits to the target */
14102e5b6d6dSopenharmony_ci        if(!inDirectMode) {
14112e5b6d6dSopenharmony_ci            if(base64Counter!=0) {
14122e5b6d6dSopenharmony_ci                if(target<targetLimit) {
14132e5b6d6dSopenharmony_ci                    *target++=TO_BASE64_IMAP(bits);
14142e5b6d6dSopenharmony_ci                    if(offsets!=NULL) {
14152e5b6d6dSopenharmony_ci                        *offsets++=sourceIndex-1;
14162e5b6d6dSopenharmony_ci                    }
14172e5b6d6dSopenharmony_ci                } else {
14182e5b6d6dSopenharmony_ci                    cnv->charErrorBuffer[cnv->charErrorBufferLength++]=TO_BASE64_IMAP(bits);
14192e5b6d6dSopenharmony_ci                    *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
14202e5b6d6dSopenharmony_ci                }
14212e5b6d6dSopenharmony_ci            }
14222e5b6d6dSopenharmony_ci            /* need to terminate with a minus */
14232e5b6d6dSopenharmony_ci            if(target<targetLimit) {
14242e5b6d6dSopenharmony_ci                *target++=MINUS;
14252e5b6d6dSopenharmony_ci                if(offsets!=NULL) {
14262e5b6d6dSopenharmony_ci                    *offsets++=sourceIndex-1;
14272e5b6d6dSopenharmony_ci                }
14282e5b6d6dSopenharmony_ci            } else {
14292e5b6d6dSopenharmony_ci                cnv->charErrorBuffer[cnv->charErrorBufferLength++]=MINUS;
14302e5b6d6dSopenharmony_ci                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
14312e5b6d6dSopenharmony_ci            }
14322e5b6d6dSopenharmony_ci        }
14332e5b6d6dSopenharmony_ci        /* reset the state for the next conversion */
14342e5b6d6dSopenharmony_ci        cnv->fromUnicodeStatus=(cnv->fromUnicodeStatus&0xf0000000)|0x1000000; /* keep version, inDirectMode=true */
14352e5b6d6dSopenharmony_ci    } else {
14362e5b6d6dSopenharmony_ci        /* set the converter state back into UConverter */
14372e5b6d6dSopenharmony_ci        cnv->fromUnicodeStatus=
14382e5b6d6dSopenharmony_ci            (cnv->fromUnicodeStatus&0xf0000000)|    /* keep version*/
14392e5b6d6dSopenharmony_ci            ((uint32_t)inDirectMode<<24)|((uint32_t)base64Counter<<16)|(uint32_t)bits;
14402e5b6d6dSopenharmony_ci    }
14412e5b6d6dSopenharmony_ci
14422e5b6d6dSopenharmony_ci    /* write back the updated pointers */
14432e5b6d6dSopenharmony_ci    pArgs->source=source;
14442e5b6d6dSopenharmony_ci    pArgs->target=(char *)target;
14452e5b6d6dSopenharmony_ci    pArgs->offsets=offsets;
14462e5b6d6dSopenharmony_ci    return;
14472e5b6d6dSopenharmony_ci}
14482e5b6d6dSopenharmony_ciU_CDECL_END
14492e5b6d6dSopenharmony_ci
14502e5b6d6dSopenharmony_cistatic const UConverterImpl _IMAPImpl={
14512e5b6d6dSopenharmony_ci    UCNV_IMAP_MAILBOX,
14522e5b6d6dSopenharmony_ci
14532e5b6d6dSopenharmony_ci    NULL,
14542e5b6d6dSopenharmony_ci    NULL,
14552e5b6d6dSopenharmony_ci
14562e5b6d6dSopenharmony_ci    _UTF7Open,
14572e5b6d6dSopenharmony_ci    NULL,
14582e5b6d6dSopenharmony_ci    _UTF7Reset,
14592e5b6d6dSopenharmony_ci
14602e5b6d6dSopenharmony_ci    _IMAPToUnicodeWithOffsets,
14612e5b6d6dSopenharmony_ci    _IMAPToUnicodeWithOffsets,
14622e5b6d6dSopenharmony_ci    _IMAPFromUnicodeWithOffsets,
14632e5b6d6dSopenharmony_ci    _IMAPFromUnicodeWithOffsets,
14642e5b6d6dSopenharmony_ci    NULL,
14652e5b6d6dSopenharmony_ci
14662e5b6d6dSopenharmony_ci    NULL,
14672e5b6d6dSopenharmony_ci    NULL,
14682e5b6d6dSopenharmony_ci    NULL, /* we don't need writeSub() because we never call a callback at fromUnicode() */
14692e5b6d6dSopenharmony_ci    NULL,
14702e5b6d6dSopenharmony_ci    ucnv_getCompleteUnicodeSet,
14712e5b6d6dSopenharmony_ci    NULL,
14722e5b6d6dSopenharmony_ci    NULL
14732e5b6d6dSopenharmony_ci};
14742e5b6d6dSopenharmony_ci
14752e5b6d6dSopenharmony_cistatic const UConverterStaticData _IMAPStaticData={
14762e5b6d6dSopenharmony_ci    sizeof(UConverterStaticData),
14772e5b6d6dSopenharmony_ci    "IMAP-mailbox-name",
14782e5b6d6dSopenharmony_ci    0, /* TODO CCSID for IMAP-mailbox-name */
14792e5b6d6dSopenharmony_ci    UCNV_IBM, UCNV_IMAP_MAILBOX,
14802e5b6d6dSopenharmony_ci    1, 4,
14812e5b6d6dSopenharmony_ci    { 0x3f, 0, 0, 0 }, 1, /* the subchar is not used */
14822e5b6d6dSopenharmony_ci    false, false,
14832e5b6d6dSopenharmony_ci    0,
14842e5b6d6dSopenharmony_ci    0,
14852e5b6d6dSopenharmony_ci    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
14862e5b6d6dSopenharmony_ci};
14872e5b6d6dSopenharmony_ci
14882e5b6d6dSopenharmony_ciconst UConverterSharedData _IMAPData=
14892e5b6d6dSopenharmony_ci        UCNV_IMMUTABLE_SHARED_DATA_INITIALIZER(&_IMAPStaticData, &_IMAPImpl);
14902e5b6d6dSopenharmony_ci
14912e5b6d6dSopenharmony_ci#endif
1492