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

#include <assert.h>
#include <stddef.h>
#include <string.h>

#include "libjpiconv-0/iconv_bool.h"
#include "libjpiconv-0/iconv_table_ni.h"
#include "libjpiconv-0/iconv_utf8.h"


/* ========================================================================== */
/*
 * Encode Unicode codepoint 'ucp' to UTF-8 and store the octet-sequence with
 * NUL-termination into 'buf'.
 *
 * Attention:
 * The caller must provide space for at least JPIC0_I_UTF8_BUFLEN octets!
 *
 * Returns zero (false / no error) on success.
 * On error nothing is written into 'buf'.
 */
jpic0_i_bool jpic0_i_encode_utf8(char *buf, long int ucp)
{
    size_t        i      = 0;  /* Index in UTF-8 octet-sequence */
    unsigned char prefix = 0;
    unsigned char data   = 0;

    if (0 > ucp)
    {
        /* Unicode codepoints are positive by definition */
        return 1;
    }
    else if (0x00007FL >= ucp)
    {
        buf[i++] = (char)ucp;
    }
    else if (0x0007FFL >= ucp)
    {
        prefix = 0xC0;
        data = (unsigned char) ((ucp >> 6) & 0x1FL);
        buf[i++] = (char)(prefix | data);
        prefix = 0x80;
        data = (unsigned char)(ucp & 0x3FL);
        buf[i++] = (char)(prefix | data);
    }
    else if ( (0x00DFFFL >= ucp) && (0x00D800L <= ucp) )
    {
        /* Surrogate codepoint (not allowed for UTF-8) */
        return 1;
    }
    else if (0x00FFFFL >= ucp)
    {
        prefix = 0xE0;
        data = (unsigned char)((ucp >> 12) & 0x0FL);
        buf[i++] = (char)(prefix | data);
        prefix = 0x80;
        data = (unsigned char)((ucp >> 6) & 0x3FL);
        buf[i++] = (char)(prefix | data);
        prefix = 0x80;
        data = (unsigned char)(ucp & 0x3FL);
        buf[i++] = (char)(prefix | data);
    }
    else if (0x10FFFFL >= ucp)
    {
        prefix = 0xF0;
        data = (unsigned char)((ucp >> 18) & 0x07L);
        buf[i++] = (char)(prefix | data);
        prefix = 0x80;
        data = (unsigned char)((ucp >> 12) & 0x3FL);
        buf[i++] = (char)(prefix | data);
        prefix = 0x80;
        data = (unsigned char)((ucp >> 6) & 0x3FL);
        buf[i++] = (char)(prefix | data);
        prefix = 0x80;
        data = (unsigned char)(ucp & 0x3FL);
        buf[i++] = (char)(prefix | data);
    }
    else
    {
        /* Codepoint beyond defined range (not allowed for any UTF) */
        return 1;
    }

    assert(JPIC0_I_UTF8_BUFLEN > i);
    buf[i] = 0;

    return 0;
}
