Matter SDK Coverage Report
Current view: top level - setup_payload - ManualSetupPayloadParser.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 92.2 % 90 83
Test Date: 2025-01-17 19:00:11 Functions: 100.0 % 5 5

            Line data    Source code
       1              : /**
       2              :  *
       3              :  *    Copyright (c) 2020 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 describes a Manul Setup Payload parser based on the
      21              :  *      CHIP specification.
      22              :  */
      23              : 
      24              : #include "ManualSetupPayloadParser.h"
      25              : 
      26              : #include <lib/support/SafeInt.h>
      27              : #include <lib/support/logging/CHIPLogging.h>
      28              : #include <lib/support/verhoeff/Verhoeff.h>
      29              : 
      30              : namespace chip {
      31              : 
      32           29 : CHIP_ERROR ManualSetupPayloadParser::CheckDecimalStringValidity(std::string decimalString,
      33              :                                                                 std::string & decimalStringWithoutCheckDigit)
      34              : {
      35           29 :     if (decimalString.length() < 2)
      36              :     {
      37            3 :         ChipLogError(SetupPayload, "Failed decoding base10. Input was empty. %u",
      38              :                      static_cast<unsigned int>(decimalString.length()));
      39            3 :         return CHIP_ERROR_INVALID_STRING_LENGTH;
      40              :     }
      41           26 :     std::string repWithoutCheckChar = decimalString.substr(0, decimalString.length() - 1);
      42           26 :     char checkChar                  = decimalString.back();
      43              : 
      44           26 :     if (!Verhoeff10::ValidateCheckChar(checkChar, repWithoutCheckChar.c_str()))
      45              :     {
      46            1 :         return CHIP_ERROR_INTEGRITY_CHECK_FAILED;
      47              :     }
      48           25 :     decimalStringWithoutCheckDigit = repWithoutCheckChar;
      49           25 :     return CHIP_NO_ERROR;
      50           26 : }
      51              : 
      52           27 : CHIP_ERROR ManualSetupPayloadParser::CheckCodeLengthValidity(const std::string & decimalString, bool isLongCode)
      53              : {
      54           27 :     size_t expectedCharLength = isLongCode ? kManualSetupLongCodeCharLength : kManualSetupShortCodeCharLength;
      55           27 :     if (decimalString.length() != expectedCharLength)
      56              :     {
      57            7 :         ChipLogError(SetupPayload, "Failed decoding base10. Input length %u was not expected length %u",
      58              :                      static_cast<unsigned int>(decimalString.length()), static_cast<unsigned int>(expectedCharLength));
      59            7 :         return CHIP_ERROR_INVALID_STRING_LENGTH;
      60              :     }
      61           20 :     return CHIP_NO_ERROR;
      62              : }
      63              : 
      64           98 : CHIP_ERROR ManualSetupPayloadParser::ToNumber(const std::string & decimalString, uint32_t & dest)
      65              : {
      66           98 :     uint32_t number = 0;
      67          462 :     for (char c : decimalString)
      68              :     {
      69          367 :         if (!isdigit(c))
      70              :         {
      71            3 :             ChipLogError(SetupPayload, "Failed decoding base10. Character was invalid %c", c);
      72            3 :             return CHIP_ERROR_INVALID_INTEGER_VALUE;
      73              :         }
      74          364 :         number *= 10;
      75          364 :         number += static_cast<uint32_t>(c - '0');
      76              :     }
      77           95 :     dest = number;
      78           95 :     return CHIP_NO_ERROR;
      79              : }
      80              : 
      81              : // Populate numberOfChars into dest from decimalString starting at startIndex (least significant digit = left-most digit)
      82           96 : CHIP_ERROR ManualSetupPayloadParser::ReadDigitsFromDecimalString(const std::string & decimalString, size_t & index, uint32_t & dest,
      83              :                                                                  size_t numberOfCharsToRead)
      84              : {
      85           96 :     if (decimalString.length() < numberOfCharsToRead || (numberOfCharsToRead + index > decimalString.length()))
      86              :     {
      87            4 :         ChipLogError(SetupPayload, "Failed decoding base10. Input was too short. %u",
      88              :                      static_cast<unsigned int>(decimalString.length()));
      89            4 :         return CHIP_ERROR_INVALID_STRING_LENGTH;
      90              :     }
      91              : 
      92           92 :     std::string decimalSubstring = decimalString.substr(index, numberOfCharsToRead);
      93           92 :     index += numberOfCharsToRead;
      94           92 :     return ToNumber(decimalSubstring, dest);
      95           92 : }
      96              : 
      97           25 : CHIP_ERROR ManualSetupPayloadParser::populatePayload(SetupPayload & outPayload)
      98              : {
      99           25 :     CHIP_ERROR result = CHIP_NO_ERROR;
     100           25 :     SetupPayload payload;
     101           25 :     std::string representationWithoutCheckDigit;
     102              : 
     103           25 :     result = CheckDecimalStringValidity(mDecimalStringRepresentation, representationWithoutCheckDigit);
     104           25 :     if (result != CHIP_NO_ERROR)
     105              :     {
     106            2 :         return result;
     107              :     }
     108              : 
     109           23 :     size_t stringOffset = 0;
     110              :     uint32_t chunk1, chunk2, chunk3;
     111              : 
     112           23 :     result = ReadDigitsFromDecimalString(representationWithoutCheckDigit, stringOffset, chunk1, kManualSetupCodeChunk1CharLength);
     113           23 :     if (result != CHIP_NO_ERROR)
     114              :     {
     115            0 :         return result;
     116              :     }
     117              : 
     118           23 :     result = ReadDigitsFromDecimalString(representationWithoutCheckDigit, stringOffset, chunk2, kManualSetupCodeChunk2CharLength);
     119           23 :     if (result != CHIP_NO_ERROR)
     120              :     {
     121            2 :         return result;
     122              :     }
     123              : 
     124           21 :     result = ReadDigitsFromDecimalString(representationWithoutCheckDigit, stringOffset, chunk3, kManualSetupCodeChunk3CharLength);
     125           21 :     if (result != CHIP_NO_ERROR)
     126              :     {
     127            0 :         return result;
     128              :     }
     129              : 
     130              :     // First digit of '8' or '9' would be invalid for v1 and would indicate new format (e.g. version 2)
     131           21 :     if (chunk1 == 8 || chunk1 == 9)
     132              :     {
     133            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     134              :     }
     135              : 
     136           21 :     bool isLongCode = ((chunk1 >> kManualSetupChunk1VidPidPresentBitPos) & 1) == 1;
     137           21 :     result          = CheckCodeLengthValidity(representationWithoutCheckDigit, isLongCode);
     138           21 :     if (result != CHIP_NO_ERROR)
     139              :     {
     140            3 :         return result;
     141              :     }
     142              : 
     143           18 :     constexpr uint32_t kDiscriminatorMsbitsMask = (1 << kManualSetupChunk1DiscriminatorMsbitsLength) - 1;
     144           18 :     constexpr uint32_t kDiscriminatorLsbitsMask = (1 << kManualSetupChunk2DiscriminatorLsbitsLength) - 1;
     145              : 
     146           18 :     uint32_t discriminator = ((chunk2 >> kManualSetupChunk2DiscriminatorLsbitsPos) & kDiscriminatorLsbitsMask);
     147           18 :     discriminator |= ((chunk1 >> kManualSetupChunk1DiscriminatorMsbitsPos) & kDiscriminatorMsbitsMask)
     148           18 :         << kManualSetupChunk2DiscriminatorLsbitsLength;
     149              : 
     150           18 :     constexpr uint32_t kPincodeMsbitsMask = (1 << kManualSetupChunk3PINCodeMsbitsLength) - 1;
     151           18 :     constexpr uint32_t kPincodeLsbitsMask = (1 << kManualSetupChunk2PINCodeLsbitsLength) - 1;
     152              : 
     153           18 :     uint32_t setUpPINCode = ((chunk2 >> kManualSetupChunk2PINCodeLsbitsPos) & kPincodeLsbitsMask);
     154           18 :     setUpPINCode |= ((chunk3 >> kManualSetupChunk3PINCodeMsbitsPos) & kPincodeMsbitsMask) << kManualSetupChunk2PINCodeLsbitsLength;
     155              : 
     156           18 :     if (setUpPINCode == 0)
     157              :     {
     158            1 :         ChipLogError(SetupPayload, "Failed decoding base10. SetUpPINCode was 0.");
     159            1 :         return CHIP_ERROR_INVALID_ARGUMENT;
     160              :     }
     161              : 
     162           17 :     if (isLongCode)
     163              :     {
     164              :         uint32_t vendorID;
     165           10 :         result =
     166           10 :             ReadDigitsFromDecimalString(representationWithoutCheckDigit, stringOffset, vendorID, kManualSetupVendorIdCharLength);
     167           10 :         if (result != CHIP_NO_ERROR)
     168              :         {
     169            0 :             return result;
     170              :         }
     171              : 
     172              :         uint32_t productID;
     173           10 :         result =
     174           10 :             ReadDigitsFromDecimalString(representationWithoutCheckDigit, stringOffset, productID, kManualSetupProductIdCharLength);
     175           10 :         if (result != CHIP_NO_ERROR)
     176              :         {
     177            0 :             return result;
     178              :         }
     179              :         // Need to do dynamic checks, because we are reading 5 chars, so could
     180              :         // have 99,999 here or something.
     181           10 :         if (!CanCastTo<uint16_t>(vendorID))
     182              :         {
     183            0 :             return CHIP_ERROR_INVALID_INTEGER_VALUE;
     184              :         }
     185           10 :         outPayload.vendorID = static_cast<uint16_t>(vendorID);
     186           10 :         if (!CanCastTo<uint16_t>(productID))
     187              :         {
     188            0 :             return CHIP_ERROR_INVALID_INTEGER_VALUE;
     189              :         }
     190           10 :         outPayload.productID = static_cast<uint16_t>(productID);
     191              :     }
     192           17 :     outPayload.commissioningFlow = isLongCode ? CommissioningFlow::kCustom : CommissioningFlow::kStandard;
     193              :     static_assert(kSetupPINCodeFieldLengthInBits <= 32, "Won't fit in uint32_t");
     194           17 :     outPayload.setUpPINCode = static_cast<uint32_t>(setUpPINCode);
     195              :     static_assert(kManualSetupDiscriminatorFieldLengthInBits <= 8, "Won't fit in uint8_t");
     196           17 :     outPayload.discriminator.SetShortValue(static_cast<uint8_t>(discriminator));
     197              : 
     198           17 :     return result;
     199           25 : }
     200              : 
     201              : } // namespace chip
        

Generated by: LCOV version 2.0-1