/*
 * UTF-8 encoder
 *
 * SPDX-FileType: SOURCE
 * SPDX-FileCopyrightText: Michael Bäuerle
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include "utf8.h"


/* ========================================================================== */
/*
 * Encode Unicode codepoint 'ucp' to UTF-8 and store octet-sequence into 'buf'
 *
 * Attention:
 * The caller must provide space for at least four octets!
 *
 * Returns length of UTF-8 sequence (or zero on error).
 * On error nothing is written into 'buf'.
 */
size_t ucic0_i_encode_utf8(unsigned char *buf, unsigned long int ucp)
{
    size_t        i      = 0;  /* Index in UTF-8 octet-sequence */
    unsigned char prefix = 0;
    unsigned char data   = 0;

    if (0x00007FUL >= ucp)
    {
        buf[i++] = ucp;
    }
    else if (0x0007FFUL >= ucp)
    {
        prefix   = 0xC0;
        data     = (ucp >> 6) & 0x1FUL;
        buf[i++] = prefix | data;
        prefix   = 0x80;
        data     = ucp & 0x3FUL;
        buf[i++] = prefix | data;
    }
    else if ( (0x00DFFFUL >= ucp) && (0x00D800UL <= ucp) )
    {
        /* Surrogate codepoint (not allowed for UTF-8) */
        return 0;
    }
    else if (0x00FFFFUL >= ucp)
    {
        prefix   = 0xE0;
        data     = (ucp >> 12) & 0x0FUL;
        buf[i++] = (prefix | data);
        prefix   = 0x80;
        data     = (ucp >> 6) & 0x3FUL;
        buf[i++] = prefix | data;
        prefix   = 0x80;
        data     = ucp & 0x3FUL;
        buf[i++] = prefix | data;
    }
    else if (0x10FFFFUL >= ucp)
    {
        prefix   = 0xF0;
        data     = (ucp >> 18) & 0x07UL;
        buf[i++] = prefix | data;
        prefix   = 0x80;
        data     = (ucp >> 12) & 0x3FUL;
        buf[i++] = prefix | data;
        prefix   = 0x80;
        data     = (ucp >> 6) & 0x3FUL;
        buf[i++] = prefix | data;
        prefix   = 0x80;
        data     = ucp & 0x3FUL;
        buf[i++] = prefix | data;
    }
    else
    {
        /* Codepoint beyond defined range (not allowed for any UTF) */
        return 0;
    }

    return i;
}
