Matter SDK Coverage Report
Current view: top level - lib/support - utf8.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 91.8 % 61 56
Test Date: 2025-01-17 19:00:11 Functions: 100.0 % 2 2

            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       126218 : ParserState NextState(ParserState state, uint8_t value)
      57              : {
      58       126218 :     switch (state)
      59              :     {
      60       126097 :     case ParserState::kFirstByte:
      61       126097 :         if (value <= 0x7F)
      62              :         {
      63       125997 :             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         2371 : bool IsValid(CharSpan span)
     172              : {
     173         2371 :     ParserState state = ParserState::kFirstByte;
     174              : 
     175         2371 :     const char * data    = span.data();
     176         2371 :     const size_t kLength = span.size();
     177              : 
     178              :     // Every byte should be valid
     179       128557 :     for (size_t i = 0; i < kLength; i++)
     180              :     {
     181       126218 :         state = NextState(state, static_cast<uint8_t>(data[i]));
     182              : 
     183       126218 :         if (state == ParserState::kInvalid)
     184              :         {
     185           32 :             return false;
     186              :         }
     187              :     }
     188              : 
     189              :     // finally no continuation should be expected
     190         2339 :     return state == ParserState::kFirstByte;
     191              : }
     192              : 
     193              : } // namespace Utf8
     194              : } // namespace chip
        

Generated by: LCOV version 2.0-1