LCOV - code coverage report
Current view: top level - lib/support - utf8.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 56 61 91.8 %
Date: 2024-02-15 08:20:41 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2023 Project CHIP Authors
       4             :  *    All rights reserved.
       5             :  *
       6             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7             :  *    you may not use this file except in compliance with the License.
       8             :  *    You may obtain a copy of the License at
       9             :  *
      10             :  *        http://www.apache.org/licenses/LICENSE-2.0
      11             :  *
      12             :  *    Unless required by applicable law or agreed to in writing, software
      13             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15             :  *    See the License for the specific language governing permissions and
      16             :  *    limitations under the License.
      17             :  */
      18             : #include "utf8.h"
      19             : 
      20             : namespace chip {
      21             : namespace Utf8 {
      22             : 
      23             : namespace {
      24             : /**
      25             :    State machine for UTF8 valid bytes
      26             : 
      27             : Table 3-7. Well-Formed UTF-8 Byte Sequences
      28             : 
      29             : Code Points       | First B  | Second B   | Third B | Fourth B
      30             : ------------------+----------+------------+---------+---------
      31             : U+0000..U+007F    | 00..7F   |            |         |
      32             : U+0080..U+07FF    | C2..DF   | 80..BF     |         |
      33             : U+0800..U+0FFF    | E0       | A0..BF (A) | 80..BF  |
      34             : U+1000..U+CFFF    | E1..EC   | 80..BF     | 80..BF  |
      35             : U+D000..U+D7FF    | ED       | 80..9F (B) | 80..BF  |
      36             : U+E000..U+FFFF    | EE..EF   | 80..BF     | 80..BF  |
      37             : U+10000..U+3FFFF  | F0       | 90..BF (C) | 80..BF  | 80..BF
      38             : U+40000..U+FFFFF  | F1..F3   | 80..BF     | 80..BF  | 80..BF
      39             : U+100000..U+10FFFF| F4       | 80..8F (D) | 80..BF  | 80..BF
      40             : */
      41             : 
      42             : enum class ParserState
      43             : {
      44             :     kFirstByte,
      45             :     kSecondByte_A,
      46             :     kSecondByte_B,
      47             :     kSecondByte_C,
      48             :     kSecondByte_D,
      49             :     kExtraOneByte,    // 0x80 .. 0xBF  once
      50             :     kExtraTwoBytes,   // 0x80 .. 0xBF  twice
      51             :     kExtraThreeBytes, // 0x80 .. 0xBF  three times
      52             :     //
      53             :     kInvalid, // some error
      54             : };
      55             : 
      56      115243 : ParserState NextState(ParserState state, uint8_t value)
      57             : {
      58      115243 :     switch (state)
      59             :     {
      60      115122 :     case ParserState::kFirstByte:
      61      115122 :         if (value <= 0x7F)
      62             :         {
      63      115022 :             return ParserState::kFirstByte;
      64             :         }
      65         100 :         else if ((value >= 0xC2) && (value <= 0xDF))
      66             :         {
      67          16 :             return ParserState::kExtraOneByte;
      68             :         }
      69          84 :         else if (value == 0xE0)
      70             :         {
      71           6 :             return ParserState::kSecondByte_A;
      72             :         }
      73          78 :         else if ((value >= 0xE1) && (value <= 0xEC))
      74             :         {
      75           3 :             return ParserState::kExtraTwoBytes;
      76             :         }
      77          75 :         else if (value == 0xED)
      78             :         {
      79           6 :             return ParserState::kSecondByte_B;
      80             :         }
      81          69 :         else if ((value >= 0xEE) && (value <= 0xEF))
      82             :         {
      83          35 :             return ParserState::kExtraTwoBytes;
      84             :         }
      85          34 :         else if (value == 0xF0)
      86             :         {
      87           8 :             return ParserState::kSecondByte_C;
      88             :         }
      89          26 :         else if ((value >= 0xF1) && (value <= 0xF3))
      90             :         {
      91           3 :             return ParserState::kExtraThreeBytes;
      92             :         }
      93          23 :         else if (value == 0xF4)
      94             :         {
      95           6 :             return ParserState::kSecondByte_D;
      96             :         }
      97             :         else
      98             :         {
      99          17 :             return ParserState::kInvalid;
     100             :         }
     101           5 :     case ParserState::kSecondByte_A:
     102           5 :         if (value >= 0xA0 && value <= 0xBF)
     103             :         {
     104           1 :             return ParserState::kExtraOneByte;
     105             :         }
     106             :         else
     107             :         {
     108           4 :             return ParserState::kInvalid;
     109             :         }
     110           6 :     case ParserState::kSecondByte_B:
     111           6 :         if (value >= 0x80 && value <= 0x9F)
     112             :         {
     113           3 :             return ParserState::kExtraOneByte;
     114             :         }
     115             :         else
     116             :         {
     117           3 :             return ParserState::kInvalid;
     118             :         }
     119           7 :     case ParserState::kSecondByte_C:
     120           7 :         if (value >= 0x90 && value <= 0xBF)
     121             :         {
     122           3 :             return ParserState::kExtraTwoBytes;
     123             :         }
     124             :         else
     125             :         {
     126           4 :             return ParserState::kInvalid;
     127             :         }
     128           5 :     case ParserState::kSecondByte_D:
     129           5 :         if (value >= 0x80 && value <= 0x8F)
     130             :         {
     131           1 :             return ParserState::kExtraTwoBytes;
     132             :         }
     133             :         else
     134             :         {
     135           4 :             return ParserState::kInvalid;
     136             :         }
     137          55 :     case ParserState::kExtraOneByte:
     138          55 :         if (value >= 0x80 && value <= 0xBF)
     139             :         {
     140          55 :             return ParserState::kFirstByte;
     141             :         }
     142             :         else
     143             :         {
     144           0 :             return ParserState::kInvalid;
     145             :         }
     146          41 :     case ParserState::kExtraTwoBytes:
     147          41 :         if (value >= 0x80 && value <= 0xBF)
     148             :         {
     149          41 :             return ParserState::kExtraOneByte;
     150             :         }
     151             :         else
     152             :         {
     153           0 :             return ParserState::kInvalid;
     154             :         }
     155           2 :     case ParserState::kExtraThreeBytes:
     156           2 :         if (value >= 0x80 && value <= 0xBF)
     157             :         {
     158           2 :             return ParserState::kExtraTwoBytes;
     159             :         }
     160             :         else
     161             :         {
     162           0 :             return ParserState::kInvalid;
     163             :         }
     164           0 :     default:
     165           0 :         return ParserState::kInvalid;
     166             :     }
     167             : }
     168             : 
     169             : } // namespace
     170             : 
     171        2085 : bool IsValid(CharSpan span)
     172             : {
     173        2085 :     ParserState state = ParserState::kFirstByte;
     174             : 
     175        2085 :     const char * data    = span.data();
     176        2085 :     const size_t kLength = span.size();
     177             : 
     178             :     // Every byte should be valid
     179      117296 :     for (size_t i = 0; i < kLength; i++)
     180             :     {
     181      115243 :         state = NextState(state, static_cast<uint8_t>(data[i]));
     182             : 
     183      115243 :         if (state == ParserState::kInvalid)
     184             :         {
     185          32 :             return false;
     186             :         }
     187             :     }
     188             : 
     189             :     // finally no continuation should be expected
     190        2053 :     return state == ParserState::kFirstByte;
     191             : }
     192             : 
     193             : } // namespace Utf8
     194             : } // namespace chip

Generated by: LCOV version 1.14