LCOV - code coverage report
Current view: top level - include/spdk_internal - utf.h (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 139 149 93.3 %
Date: 2024-12-13 04:02:48 Functions: 13 13 100.0 %

          Line data    Source code
       1             : /*   SPDX-License-Identifier: BSD-3-Clause
       2             :  *   Copyright (C) 2016 Intel Corporation.
       3             :  *   All rights reserved.
       4             :  */
       5             : 
       6             : #ifndef SPDK_UTF_H_
       7             : #define SPDK_UTF_H_
       8             : 
       9             : #include "spdk/stdinc.h"
      10             : 
      11             : #include "spdk/endian.h"
      12             : #include "spdk/likely.h"
      13             : #include "spdk/string.h"
      14             : 
      15             : static inline bool
      16         270 : utf8_tail(uint8_t c)
      17             : {
      18             :         /* c >= 0x80 && c <= 0xBF, or binary 01xxxxxx */
      19         270 :         return (c & 0xC0) == 0x80;
      20             : }
      21             : 
      22             : /*
      23             :  * Check for a valid UTF-8 encoding of a single codepoint.
      24             :  *
      25             :  * \return Length of valid UTF-8 byte sequence, or negative if invalid.
      26             :  */
      27             : static inline int
      28        5954 : utf8_valid(const uint8_t *start, const uint8_t *end)
      29             : {
      30        5954 :         const uint8_t *p = start;
      31        5954 :         uint8_t b0, b1, b2, b3;
      32             : 
      33        5954 :         if (p == end) {
      34           0 :                 return 0;
      35             :         }
      36             : 
      37        5954 :         b0 = *p;
      38             : 
      39        5954 :         if (b0 <= 0x7F) {
      40        5742 :                 return 1;
      41             :         }
      42             : 
      43         212 :         if (b0 <= 0xC1) {
      44             :                 /* Invalid start byte */
      45           6 :                 return -1;
      46             :         }
      47             : 
      48         206 :         if (++p == end) {
      49             :                 /* Not enough bytes left */
      50           8 :                 return -1;
      51             :         }
      52         198 :         b1 = *p;
      53             : 
      54         198 :         if (b0 <= 0xDF) {
      55             :                 /* C2..DF 80..BF */
      56          21 :                 if (!utf8_tail(b1)) {
      57           2 :                         return -1;
      58             :                 }
      59          19 :                 return 2;
      60             :         }
      61             : 
      62         177 :         if (++p == end) {
      63             :                 /* Not enough bytes left */
      64          14 :                 return -1;
      65             :         }
      66         163 :         b2 = *p;
      67             : 
      68         163 :         if (b0 == 0xE0) {
      69             :                 /* E0 A0..BF 80..BF */
      70          21 :                 if (b1 < 0xA0 || b1 > 0xBF || !utf8_tail(b2)) {
      71           9 :                         return -1;
      72             :                 }
      73          12 :                 return 3;
      74         142 :         } else if (b0 == 0xED && b1 >= 0xA0) {
      75             :                 /*
      76             :                  * UTF-16 surrogate pairs use U+D800..U+DFFF, which would be encoded as
      77             :                  * ED A0..BF 80..BF in UTF-8; however, surrogate pairs are not allowed in UTF-8.
      78             :                  */
      79          10 :                 return -1;
      80         132 :         } else if (b0 <= 0xEF) {
      81             :                 /* E1..EF 80..BF 80..BF */
      82          56 :                 if (!utf8_tail(b1) || !utf8_tail(b2)) {
      83           9 :                         return -1;
      84             :                 }
      85          47 :                 return 3;
      86             :         }
      87             : 
      88          76 :         if (++p == end) {
      89             :                 /* Not enough bytes left */
      90           8 :                 return -1;
      91             :         }
      92          68 :         b3 = *p;
      93             : 
      94          68 :         if (b0 == 0xF0) {
      95             :                 /* F0 90..BF 80..BF 80..BF */
      96          26 :                 if (b1 < 0x90 || b1 > 0xBF || !utf8_tail(b2) || !utf8_tail(b3)) {
      97           7 :                         return -1;
      98             :                 }
      99          19 :                 return 4;
     100          42 :         } else if (b0 <= 0xF3) {
     101             :                 /* F1..F3 80..BF 80..BF 80..BF */
     102          24 :                 if (!utf8_tail(b1) || !utf8_tail(b2) || !utf8_tail(b3)) {
     103           9 :                         return -1;
     104             :                 }
     105          15 :                 return 4;
     106          18 :         } else if (b0 == 0xF4) {
     107             :                 /* F4 80..8F 80..BF 80..BF */
     108          12 :                 if (b1 < 0x80 || b1 > 0x8F || !utf8_tail(b2) || !utf8_tail(b3)) {
     109           3 :                         return -1;
     110             :                 }
     111           9 :                 return 4;
     112             :         }
     113             : 
     114           6 :         return -1;
     115        5954 : }
     116             : 
     117             : static inline uint32_t
     118        1421 : utf8_decode_unsafe_1(const uint8_t *data)
     119             : {
     120        1421 :         return data[0];
     121             : }
     122             : 
     123             : static inline uint32_t
     124           6 : utf8_decode_unsafe_2(const uint8_t *data)
     125             : {
     126           6 :         uint32_t codepoint;
     127             : 
     128           6 :         codepoint = ((data[0] & 0x1F) << 6);
     129           6 :         codepoint |= (data[1] & 0x3F);
     130             : 
     131          12 :         return codepoint;
     132           6 : }
     133             : 
     134             : static inline uint32_t
     135          20 : utf8_decode_unsafe_3(const uint8_t *data)
     136             : {
     137          20 :         uint32_t codepoint;
     138             : 
     139          20 :         codepoint = ((data[0] & 0x0F) << 12);
     140          20 :         codepoint |= (data[1] & 0x3F) << 6;
     141          20 :         codepoint |= (data[2] & 0x3F);
     142             : 
     143          40 :         return codepoint;
     144          20 : }
     145             : 
     146             : static inline uint32_t
     147          15 : utf8_decode_unsafe_4(const uint8_t *data)
     148             : {
     149          15 :         uint32_t codepoint;
     150             : 
     151          15 :         codepoint = ((data[0] & 0x07) << 18);
     152          15 :         codepoint |= (data[1] & 0x3F) << 12;
     153          15 :         codepoint |= (data[2] & 0x3F) << 6;
     154          15 :         codepoint |= (data[3] & 0x3F);
     155             : 
     156          30 :         return codepoint;
     157          15 : }
     158             : 
     159             : /*
     160             :  * Encode a single Unicode codepoint as UTF-8.
     161             :  *
     162             :  * buf must have at least 4 bytes of space available (hence unsafe).
     163             :  *
     164             :  * \return Number of bytes appended to buf, or negative if encoding failed.
     165             :  */
     166             : static inline int
     167           7 : utf8_encode_unsafe(uint8_t *buf, uint32_t c)
     168             : {
     169           7 :         if (c <= 0x7F) {
     170           3 :                 buf[0] = c;
     171           3 :                 return 1;
     172           4 :         } else if (c <= 0x7FF) {
     173           0 :                 buf[0] = 0xC0 | (c >> 6);
     174           0 :                 buf[1] = 0x80 | (c & 0x3F);
     175           0 :                 return 2;
     176           4 :         } else if (c >= 0xD800 && c <= 0xDFFF) {
     177             :                 /* UTF-16 surrogate pairs - invalid in UTF-8 */
     178           0 :                 return -1;
     179           4 :         } else if (c <= 0xFFFF) {
     180           3 :                 buf[0] = 0xE0 | (c >> 12);
     181           3 :                 buf[1] = 0x80 | ((c >> 6) & 0x3F);
     182           3 :                 buf[2] = 0x80 | (c & 0x3F);
     183           3 :                 return 3;
     184           1 :         } else if (c <= 0x10FFFF) {
     185           1 :                 buf[0] = 0xF0 | (c >> 18);
     186           1 :                 buf[1] = 0x80 | ((c >> 12) & 0x3F);
     187           1 :                 buf[2] = 0x80 | ((c >> 6) & 0x3F);
     188           1 :                 buf[3] = 0x80 | (c & 0x3F);
     189           1 :                 return 4;
     190             :         }
     191           0 :         return -1;
     192           7 : }
     193             : 
     194             : static inline int
     195           7 : utf8_codepoint_len(uint32_t c)
     196             : {
     197           7 :         if (c <= 0x7F) {
     198           3 :                 return 1;
     199           4 :         } else if (c <= 0x7FF) {
     200           0 :                 return 2;
     201           4 :         } else if (c >= 0xD800 && c <= 0xDFFF) {
     202             :                 /* UTF-16 surrogate pairs - invalid in UTF-8 */
     203           0 :                 return -1;
     204           4 :         } else if (c <= 0xFFFF) {
     205           3 :                 return 3;
     206           1 :         } else if (c <= 0x10FFFF) {
     207           1 :                 return 4;
     208             :         }
     209           0 :         return -1;
     210           7 : }
     211             : 
     212             : static inline bool
     213          47 : utf16_valid_surrogate_high(uint32_t val)
     214             : {
     215          47 :         return val >= 0xD800 && val <= 0xDBFF;
     216             : }
     217             : 
     218             : static inline bool
     219          40 : utf16_valid_surrogate_low(uint32_t val)
     220             : {
     221          40 :         return val >= 0xDC00 && val <= 0xDFFF;
     222             : }
     223             : 
     224             : /*
     225             :  * Check for a valid UTF-16LE encoding of a single codepoint.
     226             :  *
     227             :  * \return Length of valid UTF-16LE sequence in 16-bit code units, or negative if invalid.
     228             :  */
     229             : static inline int
     230          13 : utf16le_valid(const uint16_t *start, const uint16_t *end)
     231             : {
     232          13 :         const uint16_t *p = start;
     233          13 :         uint16_t high, low;
     234             : 
     235          13 :         if (p == end) {
     236           0 :                 return 0;
     237             :         }
     238             : 
     239          13 :         high = from_le16(p);
     240             : 
     241          13 :         if (high <= 0xD7FF || high >= 0xE000) {
     242             :                 /* Single code unit in BMP */
     243           9 :                 return 1;
     244             :         }
     245             : 
     246           4 :         if (high >= 0xDC00) {
     247             :                 /* Low surrogate in first code unit - invalid */
     248           1 :                 return -1;
     249             :         }
     250             : 
     251           3 :         assert(utf16_valid_surrogate_high(high));
     252             : 
     253           3 :         if (++p == end) {
     254             :                 /* Not enough code units left */
     255           1 :                 return -1;
     256             :         }
     257           2 :         low = from_le16(p);
     258             : 
     259           2 :         if (!utf16_valid_surrogate_low(low)) {
     260           1 :                 return -1;
     261             :         }
     262             : 
     263             :         /* Valid surrogate pair */
     264           1 :         return 2;
     265          13 : }
     266             : 
     267             : static inline uint32_t
     268           3 : utf16_decode_surrogate_pair(uint32_t high, uint32_t low)
     269             : {
     270           3 :         uint32_t codepoint;
     271             : 
     272           3 :         assert(utf16_valid_surrogate_high(high));
     273           3 :         assert(utf16_valid_surrogate_low(low));
     274             : 
     275           3 :         codepoint = low;
     276           3 :         codepoint &= 0x3FF;
     277           3 :         codepoint |= ((high & 0x3FF) << 10);
     278           3 :         codepoint += 0x10000;
     279             : 
     280           6 :         return codepoint;
     281           3 : }
     282             : 
     283             : static inline void
     284          16 : utf16_encode_surrogate_pair(uint32_t codepoint, uint16_t *high, uint16_t *low)
     285             : {
     286          16 :         assert(codepoint >= 0x10000);
     287          16 :         assert(codepoint <= 0x10FFFF);
     288             : 
     289          16 :         codepoint -= 0x10000;
     290          16 :         *high = 0xD800 | (codepoint >> 10);
     291          16 :         *low = 0xDC00 | (codepoint & 0x3FF);
     292             : 
     293          16 :         assert(utf16_valid_surrogate_high(*high));
     294          16 :         assert(utf16_valid_surrogate_low(*low));
     295          16 : }
     296             : 
     297             : #endif

Generated by: LCOV version 1.15