LCOV - code coverage report
Current view: top level - lib/support - BytesToHex.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 95 102 93.1 %
Date: 2024-02-15 08:20:41 Functions: 12 12 100.0 %

          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      141578 : char NibbleToHex(uint8_t nibble, bool uppercase)
      30             : {
      31      141578 :     char x = static_cast<char>(nibble & 0xFu);
      32             : 
      33      141578 :     if (x >= 10)
      34             :     {
      35       53738 :         return static_cast<char>((x - 10) + (uppercase ? 'A' : 'a'));
      36             :     }
      37             : 
      38       87840 :     return static_cast<char>(x + '0');
      39             : }
      40             : 
      41      194987 : CHIP_ERROR MakeU8FromAsciiHex(const char * src, const size_t srcLen, uint8_t * val, BitFlags<HexFlags> flags)
      42             : {
      43      194987 :     if (srcLen != 2)
      44             :     {
      45           0 :         return CHIP_ERROR_INVALID_ARGUMENT;
      46             :     }
      47      194987 :     uint8_t ret = 0;
      48      584922 :     for (size_t i = 0; i < srcLen; ++i)
      49             :     {
      50      389962 :         ret          = static_cast<uint8_t>(ret << 4);
      51      389962 :         char c       = src[i];
      52      389962 :         uint8_t cval = static_cast<uint8_t>(c);
      53      389962 :         if (c >= '0' && c <= '9')
      54             :         {
      55      303671 :             ret = static_cast<uint8_t>(ret + cval - static_cast<uint8_t>('0'));
      56             :         }
      57       86291 :         else if (c >= 'A' && c <= 'F')
      58             :         {
      59        2994 :             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       83297 :         else if (!flags.Has(HexFlags::kUppercase) && c >= 'a' && c <= 'f')
      63             :         {
      64       83270 :             ret = static_cast<uint8_t>(ret + cval - static_cast<uint8_t>('a') + 0xA);
      65             :         }
      66             :         else
      67             :         {
      68          27 :             return CHIP_ERROR_INVALID_ARGUMENT;
      69             :         }
      70             :     }
      71      194960 :     *val = ret;
      72      194960 :     return CHIP_NO_ERROR;
      73             : }
      74             : 
      75        2660 : 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        2660 :     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        2660 :     if ((src_size & 0x1) != 0 || src_size > dest_size_max * 2)
      84             :     {
      85           1 :         return 0;
      86             :     }
      87             : 
      88        2659 :     size_t bytesFilled = 0;
      89      197619 :     for (size_t i = 0; i < src_size; i += 2)
      90             :     {
      91      194987 :         VerifyOrReturnError(MakeU8FromAsciiHex(src_hex + i, 2, &dest_bytes[i / 2], flags) == CHIP_NO_ERROR, 0);
      92      194960 :         bytesFilled++;
      93             :     }
      94        2632 :     return bytesFilled;
      95             : }
      96             : 
      97             : } // namespace
      98             : 
      99        8914 : 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        8914 :     if ((src_bytes == nullptr) && (src_size != 0))
     102             :     {
     103           0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     104             :     }
     105             : 
     106        8914 :     if ((dest_hex == nullptr) && (dest_size_max != 0))
     107             :     {
     108           3 :         return CHIP_ERROR_INVALID_ARGUMENT;
     109             :     }
     110             : 
     111        8911 :     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        8911 :     bool nul_terminate          = flags.Has(HexFlags::kNullTerminate);
     120        8911 :     size_t expected_output_size = (src_size * 2u) + (nul_terminate ? 1u : 0u);
     121        8911 :     if (dest_size_max < expected_output_size)
     122             :     {
     123           9 :         return CHIP_ERROR_BUFFER_TOO_SMALL;
     124             :     }
     125             : 
     126        8902 :     bool uppercase = flags.Has(HexFlags::kUppercase);
     127        8902 :     char * cursor  = dest_hex;
     128       79691 :     for (size_t byte_idx = 0; byte_idx < src_size; ++byte_idx)
     129             :     {
     130       70789 :         *cursor++ = NibbleToHex((src_bytes[byte_idx] >> 4) & 0xFu, uppercase);
     131       70789 :         *cursor++ = NibbleToHex((src_bytes[byte_idx] >> 0) & 0xFu, uppercase);
     132             :     }
     133             : 
     134        8902 :     if (nul_terminate)
     135             :     {
     136          47 :         *cursor = '\0';
     137             :     }
     138             : 
     139        8902 :     return CHIP_NO_ERROR;
     140             : }
     141             : 
     142        8735 : CHIP_ERROR Uint64ToHex(uint64_t src, char * dest_hex, size_t dest_size_max, BitFlags<HexFlags> flags)
     143             : {
     144        8735 :     uint8_t buf[sizeof(src)] = { 0 };
     145        8735 :     Encoding::BigEndian::Put64(buf, src);
     146        8735 :     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        1689 : size_t HexToBytes(const char * src_hex, const size_t src_size, uint8_t * dest_bytes, size_t dest_size_max)
     164             : {
     165        1689 :     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         557 : size_t UppercaseHexToUint16(const char * src_hex, const size_t src_size, uint16_t & dest)
     193             : {
     194         557 :     uint8_t buf[sizeof(uint16_t)] = { 0 };
     195         557 :     size_t decoded_size           = HexToBytes(src_hex, src_size, buf, sizeof(buf), HexFlags::kUppercase);
     196         557 :     if (decoded_size != sizeof(buf))
     197             :     {
     198          22 :         return 0;
     199             :     }
     200         535 :     dest = Encoding::BigEndian::Get16(buf);
     201         535 :     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 1.14