Matter SDK Coverage Report
Current view: top level - lib/support - IniEscaping.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 74.5 % 55 41
Test Date: 2025-01-17 19:00:11 Functions: 71.4 % 7 5

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2022 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              : 
      19              : #include <memory>
      20              : #include <string>
      21              : 
      22              : #include "IniEscaping.h"
      23              : #include <lib/support/Base64.h>
      24              : #include <lib/support/BytesToHex.h>
      25              : 
      26              : namespace chip {
      27              : namespace IniEscaping {
      28              : 
      29              : namespace {
      30              : 
      31              : constexpr size_t kEscapeChunkSize = 4; // "\x12" --> 4 chars
      32              : 
      33        11168 : constexpr bool NeedsEscape(char c)
      34              : {
      35        11168 :     return (c <= 0x20) || (c == '=') || (c == '\\') || (c >= 0x7F);
      36              : }
      37              : 
      38         1838 : constexpr bool IsLowercaseHex(char c)
      39              : {
      40         1838 :     return ((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f'));
      41              : }
      42              : 
      43          919 : bool IsValidEscape(const std::string & s)
      44              : {
      45          919 :     return (s.size() >= kEscapeChunkSize) && (s[0] == '\\') && (s[1] == 'x') && IsLowercaseHex(s[2]) && IsLowercaseHex(s[3]);
      46              : }
      47              : 
      48              : } // namespace
      49              : 
      50          909 : std::string EscapeKey(const std::string & key)
      51              : {
      52          909 :     std::string escapedKey;
      53          909 :     escapedKey.reserve(key.size());
      54              : 
      55        11159 :     for (char c : key)
      56              :     {
      57              :         // Replace spaces, non-printable chars, `=` and the escape itself with hex-escaped (C-style) characters.
      58        10250 :         if (NeedsEscape(c))
      59              :         {
      60          877 :             char escaped[kEscapeChunkSize + 1] = { 0 };
      61          877 :             snprintf(escaped, sizeof(escaped), "\\x%02x", (static_cast<unsigned>(c) & 0xff));
      62          877 :             escapedKey += escaped;
      63              :         }
      64              :         else
      65              :         {
      66         9373 :             escapedKey += c;
      67              :         }
      68              :     }
      69              : 
      70          909 :     return escapedKey;
      71              : }
      72              : 
      73          284 : std::string UnescapeKey(const std::string & key)
      74              : {
      75          284 :     std::string unescaped;
      76          284 :     unescaped.reserve(key.size());
      77              : 
      78          284 :     size_t idx       = 0;
      79          284 :     size_t remaining = key.size();
      80         1697 :     while (remaining > 0)
      81              :     {
      82         1417 :         char c = key[idx];
      83         1417 :         if (c == '\\')
      84              :         {
      85              :             // Don't process invalid escapes.
      86          920 :             if (remaining < kEscapeChunkSize)
      87              :             {
      88            1 :                 return "";
      89              :             }
      90              : 
      91          919 :             auto escapeChunk = key.substr(idx, kEscapeChunkSize);
      92          919 :             if (!IsValidEscape(escapeChunk))
      93              :             {
      94            1 :                 return "";
      95              :             }
      96              : 
      97              :             // We validated format, now extract the last two chars as hex
      98          918 :             auto hexDigits   = escapeChunk.substr(2, 2);
      99          918 :             uint8_t charByte = 0;
     100          918 :             if ((chip::Encoding::HexToBytes(hexDigits.data(), 2, &charByte, 1) != 1) || !NeedsEscape(static_cast<char>(charByte)))
     101              :             {
     102            2 :                 return "";
     103              :             }
     104              : 
     105          916 :             unescaped += static_cast<char>(charByte);
     106          916 :             idx += kEscapeChunkSize;
     107          921 :         }
     108              :         else
     109              :         {
     110          497 :             unescaped += c;
     111          497 :             idx += 1;
     112              :         }
     113              : 
     114         1413 :         remaining = key.size() - idx;
     115              :     }
     116              : 
     117          280 :     return unescaped;
     118          284 : }
     119              : 
     120            0 : std::string StringToBase64(const std::string & value)
     121              : {
     122            0 :     std::unique_ptr<char[]> buffer(new char[BASE64_ENCODED_LEN(value.length())]);
     123              : 
     124              :     uint32_t len =
     125            0 :         chip::Base64Encode32(reinterpret_cast<const uint8_t *>(value.data()), static_cast<uint32_t>(value.length()), buffer.get());
     126            0 :     if (len == UINT32_MAX)
     127              :     {
     128            0 :         return "";
     129              :     }
     130              : 
     131            0 :     return std::string(buffer.get(), len);
     132            0 : }
     133              : 
     134            0 : std::string Base64ToString(const std::string & b64Value)
     135              : {
     136            0 :     std::unique_ptr<uint8_t[]> buffer(new uint8_t[BASE64_MAX_DECODED_LEN(b64Value.length())]);
     137              : 
     138            0 :     uint32_t len = chip::Base64Decode32(b64Value.data(), static_cast<uint32_t>(b64Value.length()), buffer.get());
     139            0 :     if (len == UINT32_MAX)
     140              :     {
     141            0 :         return "";
     142              :     }
     143              : 
     144            0 :     return std::string(reinterpret_cast<const char *>(buffer.get()), len);
     145            0 : }
     146              : 
     147              : } // namespace IniEscaping
     148              : } // namespace chip
        

Generated by: LCOV version 2.0-1