Matter SDK Coverage Report
Current view: top level - lib/support - BytesToHex.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 93.1 % 102 95
Test Date: 2025-01-17 19:00:11 Functions: 100.0 % 12 12

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2021-2022 Project CHIP Authors
       4              :  *
       5              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       6              :  *    you may not use this file except in compliance with the License.
       7              :  *    You may obtain a copy of the License at
       8              :  *
       9              :  *        http://www.apache.org/licenses/LICENSE-2.0
      10              :  *
      11              :  *    Unless required by applicable law or agreed to in writing, software
      12              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      13              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14              :  *    See the License for the specific language governing permissions and
      15              :  *    limitations under the License.
      16              :  */
      17              : 
      18              : #include "BytesToHex.h"
      19              : #include <lib/core/CHIPEncoding.h>
      20              : #include <lib/support/CodeUtils.h>
      21              : 
      22              : #include <cstring>
      23              : #include <stdio.h>
      24              : namespace chip {
      25              : namespace Encoding {
      26              : 
      27              : namespace {
      28              : 
      29       155298 : char NibbleToHex(uint8_t nibble, bool uppercase)
      30              : {
      31       155298 :     char x = static_cast<char>(nibble & 0xFu);
      32              : 
      33       155298 :     if (x >= 10)
      34              :     {
      35        59237 :         return static_cast<char>((x - 10) + (uppercase ? 'A' : 'a'));
      36              :     }
      37              : 
      38        96061 :     return static_cast<char>(x + '0');
      39              : }
      40              : 
      41       200133 : CHIP_ERROR MakeU8FromAsciiHex(const char * src, const size_t srcLen, uint8_t * val, BitFlags<HexFlags> flags)
      42              : {
      43       200133 :     if (srcLen != 2)
      44              :     {
      45            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
      46              :     }
      47       200133 :     uint8_t ret = 0;
      48       600356 :     for (size_t i = 0; i < srcLen; ++i)
      49              :     {
      50       400252 :         ret          = static_cast<uint8_t>(ret << 4);
      51       400252 :         char c       = src[i];
      52       400252 :         uint8_t cval = static_cast<uint8_t>(c);
      53       400252 :         if (c >= '0' && c <= '9')
      54              :         {
      55       311743 :             ret = static_cast<uint8_t>(ret + cval - static_cast<uint8_t>('0'));
      56              :         }
      57        88509 :         else if (c >= 'A' && c <= 'F')
      58              :         {
      59         3022 :             ret = static_cast<uint8_t>(ret + cval - static_cast<uint8_t>('A') + 0xA);
      60              :         }
      61              :         // If kUppercase flag is not set then lowercase are also allowed.
      62        85487 :         else if (!flags.Has(HexFlags::kUppercase) && c >= 'a' && c <= 'f')
      63              :         {
      64        85458 :             ret = static_cast<uint8_t>(ret + cval - static_cast<uint8_t>('a') + 0xA);
      65              :         }
      66              :         else
      67              :         {
      68           29 :             return CHIP_ERROR_INVALID_ARGUMENT;
      69              :         }
      70              :     }
      71       200104 :     *val = ret;
      72       200104 :     return CHIP_NO_ERROR;
      73              : }
      74              : 
      75         2696 : size_t HexToBytes(const char * src_hex, const size_t src_size, uint8_t * dest_bytes, size_t dest_size_max, BitFlags<HexFlags> flags)
      76              : {
      77         2696 :     if ((src_hex == nullptr) || (dest_bytes == nullptr))
      78              :     {
      79            0 :         return 0;
      80              :     }
      81              :     // Octet string where each octet is 2 ascii digits representing the hex value
      82              :     // Each is represented by two ascii chars, so must be even number
      83         2696 :     if ((src_size & 0x1) != 0 || src_size > dest_size_max * 2)
      84              :     {
      85            1 :         return 0;
      86              :     }
      87              : 
      88         2695 :     size_t bytesFilled = 0;
      89       202799 :     for (size_t i = 0; i < src_size; i += 2)
      90              :     {
      91       200133 :         VerifyOrReturnError(MakeU8FromAsciiHex(src_hex + i, 2, &dest_bytes[i / 2], flags) == CHIP_NO_ERROR, 0);
      92       200104 :         bytesFilled++;
      93              :     }
      94         2666 :     return bytesFilled;
      95              : }
      96              : 
      97              : } // namespace
      98              : 
      99         9728 : CHIP_ERROR BytesToHex(const uint8_t * src_bytes, size_t src_size, char * dest_hex, size_t dest_size_max, BitFlags<HexFlags> flags)
     100              : {
     101         9728 :     if ((src_bytes == nullptr) && (src_size != 0))
     102              :     {
     103            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     104              :     }
     105              : 
     106         9728 :     if ((dest_hex == nullptr) && (dest_size_max != 0))
     107              :     {
     108            3 :         return CHIP_ERROR_INVALID_ARGUMENT;
     109              :     }
     110              : 
     111         9725 :     if (src_size > ((SIZE_MAX - 1) / 2u))
     112              :     {
     113              :         // Output would overflow a size_t, let's bail out to avoid computation wraparounds below.
     114              :         // This condition will hit with slightly less than the very max, but is unlikely to
     115              :         // ever happen unless an error occurs and won't happen on embedded targets.
     116            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     117              :     }
     118              : 
     119         9725 :     bool nul_terminate          = flags.Has(HexFlags::kNullTerminate);
     120         9725 :     size_t expected_output_size = (src_size * 2u) + (nul_terminate ? 1u : 0u);
     121         9725 :     if (dest_size_max < expected_output_size)
     122              :     {
     123            9 :         return CHIP_ERROR_BUFFER_TOO_SMALL;
     124              :     }
     125              : 
     126         9716 :     bool uppercase = flags.Has(HexFlags::kUppercase);
     127         9716 :     char * cursor  = dest_hex;
     128        87365 :     for (size_t byte_idx = 0; byte_idx < src_size; ++byte_idx)
     129              :     {
     130        77649 :         *cursor++ = NibbleToHex((src_bytes[byte_idx] >> 4) & 0xFu, uppercase);
     131        77649 :         *cursor++ = NibbleToHex((src_bytes[byte_idx] >> 0) & 0xFu, uppercase);
     132              :     }
     133              : 
     134         9716 :     if (nul_terminate)
     135              :     {
     136           46 :         *cursor = '\0';
     137              :     }
     138              : 
     139         9716 :     return CHIP_NO_ERROR;
     140              : }
     141              : 
     142         9499 : CHIP_ERROR Uint64ToHex(uint64_t src, char * dest_hex, size_t dest_size_max, BitFlags<HexFlags> flags)
     143              : {
     144         9499 :     uint8_t buf[sizeof(src)] = { 0 };
     145         9499 :     Encoding::BigEndian::Put64(buf, src);
     146         9499 :     return BytesToHex(buf, sizeof(buf), dest_hex, dest_size_max, flags);
     147              : }
     148              : 
     149          123 : CHIP_ERROR Uint32ToHex(uint32_t src, char * dest_hex, size_t dest_size_max, BitFlags<HexFlags> flags)
     150              : {
     151          123 :     uint8_t buf[sizeof(src)] = { 0 };
     152          123 :     Encoding::BigEndian::Put32(buf, src);
     153          123 :     return BytesToHex(buf, sizeof(buf), dest_hex, dest_size_max, flags);
     154              : }
     155              : 
     156            4 : CHIP_ERROR Uint16ToHex(uint16_t src, char * dest_hex, size_t dest_size_max, BitFlags<HexFlags> flags)
     157              : {
     158            4 :     uint8_t buf[sizeof(src)] = { 0 };
     159            4 :     Encoding::BigEndian::Put16(buf, src);
     160            4 :     return BytesToHex(buf, sizeof(buf), dest_hex, dest_size_max, flags);
     161              : }
     162              : 
     163         1709 : size_t HexToBytes(const char * src_hex, const size_t src_size, uint8_t * dest_bytes, size_t dest_size_max)
     164              : {
     165         1709 :     return HexToBytes(src_hex, src_size, dest_bytes, dest_size_max, HexFlags::kNone);
     166              : }
     167              : 
     168          400 : size_t UppercaseHexToUint64(const char * src_hex, const size_t src_size, uint64_t & dest)
     169              : {
     170          400 :     uint8_t buf[sizeof(uint64_t)] = { 0 };
     171          400 :     size_t decoded_size           = HexToBytes(src_hex, src_size, buf, sizeof(buf), HexFlags::kUppercase);
     172          400 :     if (decoded_size != sizeof(buf))
     173              :     {
     174            1 :         return 0;
     175              :     }
     176          399 :     dest = Encoding::BigEndian::Get64(buf);
     177          399 :     return decoded_size;
     178              : }
     179              : 
     180           14 : size_t UppercaseHexToUint32(const char * src_hex, const size_t src_size, uint32_t & dest)
     181              : {
     182           14 :     uint8_t buf[sizeof(uint32_t)] = { 0 };
     183           14 :     size_t decoded_size           = HexToBytes(src_hex, src_size, buf, sizeof(buf), HexFlags::kUppercase);
     184           14 :     if (decoded_size != sizeof(buf))
     185              :     {
     186            0 :         return 0;
     187              :     }
     188           14 :     dest = Encoding::BigEndian::Get32(buf);
     189           14 :     return decoded_size;
     190              : }
     191              : 
     192          573 : size_t UppercaseHexToUint16(const char * src_hex, const size_t src_size, uint16_t & dest)
     193              : {
     194          573 :     uint8_t buf[sizeof(uint16_t)] = { 0 };
     195          573 :     size_t decoded_size           = HexToBytes(src_hex, src_size, buf, sizeof(buf), HexFlags::kUppercase);
     196          573 :     if (decoded_size != sizeof(buf))
     197              :     {
     198           24 :         return 0;
     199              :     }
     200          549 :     dest = Encoding::BigEndian::Get16(buf);
     201          549 :     return decoded_size;
     202              : }
     203              : 
     204            5 : void LogBufferAsHex(const char * label, const ByteSpan & span)
     205              : {
     206            5 :     constexpr size_t kBytesPerLine = 32u;
     207              : 
     208            5 :     size_t remaining = span.size();
     209            5 :     if (remaining == 0)
     210              :     {
     211            1 :         ChipLogProgress(Support, "%s>>>", ((label != nullptr) ? label : ""));
     212            1 :         return;
     213              :     }
     214              : 
     215            4 :     const uint8_t * cursor = span.data();
     216           14 :     while (remaining > 0u)
     217              :     {
     218           10 :         size_t chunk_size = (remaining < kBytesPerLine) ? remaining : kBytesPerLine;
     219              :         char hex_buf[(kBytesPerLine * 2) + 1];
     220              : 
     221           10 :         CHIP_ERROR err = BytesToUppercaseHexString(cursor, chunk_size, &hex_buf[0], sizeof(hex_buf));
     222           10 :         if (err != CHIP_NO_ERROR)
     223              :         {
     224            0 :             ChipLogProgress(Support, "Failed to dump hex %" CHIP_ERROR_FORMAT, err.Format());
     225            0 :             return;
     226              :         }
     227              : 
     228           10 :         ChipLogProgress(Support, "%s>>>%s", ((label != nullptr) ? label : ""), hex_buf);
     229              : 
     230           10 :         cursor += chunk_size;
     231           10 :         remaining -= chunk_size;
     232              :     }
     233              : }
     234              : 
     235              : } // namespace Encoding
     236              : } // namespace chip
        

Generated by: LCOV version 2.0-1