(root)/
util-linux-2.39/
lib/
encode.c
       1  /*
       2   * Based on code from libblkid,
       3   *
       4   * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
       5   * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
       6   * Copyright (C) 2020 Pali Rohár <pali.rohar@gmail.com>
       7   *
       8   * This file may be redistributed under the terms of the
       9   * GNU Lesser General Public License.
      10   */
      11  #include "c.h"
      12  #include "encode.h"
      13  
      14  size_t ul_encode_to_utf8(int enc, unsigned char *dest, size_t len,
      15  			const unsigned char *src, size_t count)
      16  {
      17  	size_t i, j;
      18  	uint32_t c;
      19  	uint16_t c2;
      20  
      21  	for (j = i = 0; i < count; i++) {
      22  		if (enc == UL_ENCODE_UTF16LE) {
      23  			if (i+2 > count)
      24  				break;
      25  			c = (src[i+1] << 8) | src[i];
      26  			i++;
      27  		} else if (enc == UL_ENCODE_UTF16BE) {
      28  			if (i+2 > count)
      29  				break;
      30  			c = (src[i] << 8) | src[i+1];
      31  			i++;
      32  		} else if (enc == UL_ENCODE_LATIN1) {
      33  			c = src[i];
      34  		} else {
      35  			return 0;
      36  		}
      37  		if ((enc == UL_ENCODE_UTF16LE || enc == UL_ENCODE_UTF16BE) &&
      38  		    c >= 0xD800 && c <= 0xDBFF && i+2 < count) {
      39  			if (enc == UL_ENCODE_UTF16LE)
      40  				c2 = (src[i+2] << 8) | src[i+1];
      41  			else
      42  				c2 = (src[i+1] << 8) | src[i+2];
      43  			if (c2 >= 0xDC00 && c2 <= 0xDFFF) {
      44  				c = 0x10000 + ((c - 0xD800) << 10) + (c2 - 0xDC00);
      45  				i += 2;
      46  			}
      47  		}
      48  		if (c == 0) {
      49  			dest[j] = '\0';
      50  			break;
      51  		}
      52  
      53  		if (c < 0x80) {
      54  			if (j+1 >= len)
      55  				break;
      56  			dest[j++] = (uint8_t) c;
      57  		} else if (c < 0x800) {
      58  			if (j+2 >= len)
      59  				break;
      60  			dest[j++] = (uint8_t) (0xc0 | (c >> 6));
      61  			dest[j++] = (uint8_t) (0x80 | (c & 0x3f));
      62  		} else if (c < 0x10000) {
      63  			if (j+3 >= len)
      64  				break;
      65  			dest[j++] = (uint8_t) (0xe0 | (c >> 12));
      66  			dest[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f));
      67  			dest[j++] = (uint8_t) (0x80 | (c & 0x3f));
      68  		} else {
      69  			if (j+4 >= len)
      70  				break;
      71  			dest[j++] = (uint8_t) (0xf0 | (c >> 18));
      72  			dest[j++] = (uint8_t) (0x80 | ((c >> 12) & 0x3f));
      73  			dest[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f));
      74  			dest[j++] = (uint8_t) (0x80 | (c & 0x3f));
      75  		}
      76  	}
      77  	dest[j] = '\0';
      78  	return j;
      79  }