LCOV - code coverage report
Current view: top level - setup_payload - Base38Encode.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 26 26 100.0 %
Date: 2024-02-15 08:20:41 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2021 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             : /**
      19             :  *    @file
      20             :  *      This file implements converting an array of bytes into a Base38 String.
      21             :  *
      22             :  *      The encoding chosen is: treat every 3 bytes of input data as a little-endian
      23             :  *        uint32_t, then div and mod that into 5 base38 characters, with the least-significant
      24             :  *        encoding bits in the first character of the resulting string. If a number of bytes
      25             :  *        is used that is not multiple of 3, then last 2 bytes are encoded to 4 base38 characters
      26             :  *        or last 1 byte is encoded to 2 base38 characters. Algoritm considers worst case size
      27             :  *        of bytes chunks and does not introduce code length optimization.
      28             :  *
      29             :  */
      30             : 
      31             : #include "Base38Encode.h"
      32             : 
      33             : #include <climits>
      34             : #include <cstring>
      35             : 
      36             : namespace {
      37             : 
      38             : static const uint8_t kMaxBytesSingleChunkLen = 3;
      39             : 
      40             : } // unnamed namespace
      41             : 
      42             : namespace chip {
      43             : 
      44          46 : CHIP_ERROR base38Encode(ByteSpan in_buf, MutableCharSpan & out_buf)
      45             : {
      46          46 :     CHIP_ERROR err             = CHIP_NO_ERROR;
      47          46 :     const uint8_t * in_buf_ptr = in_buf.data();
      48          46 :     size_t in_buf_len          = in_buf.size();
      49          46 :     size_t out_idx             = 0;
      50             : 
      51         213 :     while (in_buf_len > 0)
      52             :     {
      53         169 :         uint32_t value = 0;
      54             :         static_assert((sizeof(value) * CHAR_BIT) >= (kMaxBytesSingleChunkLen * 8), "Type for value is too small for conversions");
      55             : 
      56         169 :         size_t bytesInChunk = (in_buf_len >= kMaxBytesSingleChunkLen) ? kMaxBytesSingleChunkLen : in_buf_len;
      57             : 
      58         630 :         for (size_t byte_idx = 0; byte_idx < bytesInChunk; byte_idx++)
      59             :         {
      60         461 :             value += static_cast<uint32_t>(in_buf_ptr[byte_idx] << (8 * byte_idx));
      61             :         }
      62         169 :         in_buf_len -= bytesInChunk;
      63         169 :         in_buf_ptr += bytesInChunk;
      64             : 
      65             :         // Without code length optimization there is constant characters number needed for specific chunk size.
      66         169 :         const uint8_t base38CharactersNeeded = kBase38CharactersNeededInNBytesChunk[bytesInChunk - 1];
      67             : 
      68         169 :         if ((out_idx + base38CharactersNeeded) >= out_buf.size())
      69             :         {
      70           2 :             err = CHIP_ERROR_BUFFER_TOO_SMALL;
      71           2 :             break;
      72             :         }
      73             : 
      74         947 :         for (uint8_t character = 0; character < base38CharactersNeeded; character++)
      75             :         {
      76         780 :             out_buf.data()[out_idx++] = kCodes[value % kRadix];
      77         780 :             value /= kRadix;
      78             :         }
      79             :     }
      80             : 
      81          46 :     if (out_idx < out_buf.size())
      82             :     {
      83          44 :         out_buf.data()[out_idx] = '\0';
      84             :         // Reduce output span size to be the size of written data and to not include null-terminator.
      85          44 :         out_buf.reduce_size(out_idx);
      86             :     }
      87             :     else
      88             :     {
      89             :         // out_buf size is zero.
      90           2 :         err = CHIP_ERROR_BUFFER_TOO_SMALL;
      91             :     }
      92             : 
      93          46 :     return err;
      94             : }
      95             : 
      96          26 : size_t base38EncodedLength(size_t num_bytes)
      97             : {
      98             :     // Each group of 3 bytes converts to 5 chars, and each remaining byte converts to 2 chars.
      99             :     // Add one for the null terminator.
     100          26 :     return (num_bytes / 3) * 5 + (num_bytes % 3) * 2 + 1;
     101             : }
     102             : 
     103             : } // namespace chip

Generated by: LCOV version 1.14