diff --git a/examples/chip-tool/commands/clusters/ComplexArgument.h b/examples/chip-tool/commands/clusters/ComplexArgument.h index 8cb23a0b661797..2af80e5b3eef3e 100644 --- a/examples/chip-tool/commands/clusters/ComplexArgument.h +++ b/examples/chip-tool/commands/clusters/ComplexArgument.h @@ -16,6 +16,21 @@ * */ +/** + * This file allocate/free memory using the chip platform abstractions + * (Platform::MemoryCalloc and Platform::MemoryFree) for hosting a subset of the + * data model internal types until they are consumed by the DataModel::Encode machinery: + * - chip::app:DataModel::List + * - chip::ByteSpan + * - chip::CharSpan + * + * Memory allocation happens during the 'Setup' phase, while memory deallocation happens + * during the 'Finalize' phase. + * + * The 'Finalize' phase during the destructor phase, and if needed, 'Finalize' will call + * the 'Finalize' phase of its descendant. + */ + #pragma once #include @@ -173,17 +188,44 @@ class ComplexArgumentParser return CHIP_ERROR_INVALID_ARGUMENT; } - if (strlen(value.asCString()) % 2 != 0) + auto str = value.asString(); + auto size = str.size(); + uint8_t * buffer = nullptr; + + if (IsStrString(str.c_str())) { - ChipLogError(chipTool, "Error while encoding %s as an octet string: Odd number of characters.", label); - return CHIP_ERROR_INVALID_STRING_LENGTH; + // Skip the prefix + str.erase(0, kStrStringPrefixLen); + size = str.size(); + + buffer = static_cast(chip::Platform::MemoryCalloc(size, sizeof(uint8_t))); + memcpy(buffer, str.c_str(), size); } + else + { + if (IsHexString(str.c_str())) + { + // Skip the prefix + str.erase(0, kHexStringPrefixLen); + size = str.size(); + } + + if (size % 2 != 0) + { + ChipLogError(chipTool, "Error while encoding %s as a hex string: Odd number of characters.", label); + return CHIP_ERROR_INVALID_STRING_LENGTH; + } - size_t size = strlen(value.asCString()); - auto buffer = static_cast(chip::Platform::MemoryCalloc(size / 2, sizeof(uint8_t))); - size_t octetCount = chip::Encoding::HexToBytes(value.asCString(), size, buffer, size / 2); + buffer = static_cast(chip::Platform::MemoryCalloc(size / 2, sizeof(uint8_t))); + size = chip::Encoding::HexToBytes(str.c_str(), size, buffer, size / 2); + if (size == 0) + { + ChipLogError(chipTool, "Error while encoding %s as a hex string.", label); + return CHIP_ERROR_INTERNAL; + } + } - request = chip::ByteSpan(buffer, octetCount); + request = chip::ByteSpan(buffer, size); return CHIP_NO_ERROR; } diff --git a/examples/chip-tool/commands/clusters/JsonParser.h b/examples/chip-tool/commands/clusters/JsonParser.h index 2b74aee6fffb7c..adb1375bd880d1 100644 --- a/examples/chip-tool/commands/clusters/JsonParser.h +++ b/examples/chip-tool/commands/clusters/JsonParser.h @@ -18,6 +18,8 @@ #pragma once +#include "../common/CustomStringPrefix.h" + #include #include diff --git a/examples/chip-tool/commands/common/Command.cpp b/examples/chip-tool/commands/common/Command.cpp index 0c5777e825df3b..c4161b6ac59908 100644 --- a/examples/chip-tool/commands/common/Command.cpp +++ b/examples/chip-tool/commands/common/Command.cpp @@ -17,6 +17,8 @@ */ #include "Command.h" +#include "CustomStringPrefix.h" +#include "platform/PlatformManager.h" #include #include @@ -362,10 +364,9 @@ bool Command::InitArgument(size_t argIndex, char * argValue) // We support two ways to pass an octet string argument. If it happens // to be all-ASCII, you can just pass it in. Otherwise you can pass in // "hex:" followed by the hex-encoded bytes. - size_t argLen = strlen(argValue); - static constexpr char hexPrefix[] = "hex:"; - constexpr size_t prefixLen = ArraySize(hexPrefix) - 1; // Don't count the null - if (strncmp(argValue, hexPrefix, prefixLen) == 0) + size_t argLen = strlen(argValue); + + if (IsHexString(argValue)) { // Hex-encoded. Decode it into a temporary buffer first, so if we // run into errors we can do correct "argument is not valid" logging @@ -381,7 +382,8 @@ bool Command::InitArgument(size_t argIndex, char * argValue) return false; } - size_t octetCount = chip::Encoding::HexToBytes(argValue + prefixLen, argLen - prefixLen, buffer.Get(), argLen); + size_t octetCount = + chip::Encoding::HexToBytes(argValue + kHexStringPrefixLen, argLen - kHexStringPrefixLen, buffer.Get(), argLen); if (octetCount == 0) { return false; @@ -393,13 +395,11 @@ bool Command::InitArgument(size_t argIndex, char * argValue) } // Just ASCII. Check for the "str:" prefix. - static constexpr char strPrefix[] = "str:"; - constexpr size_t strPrefixLen = ArraySize(strPrefix) - 1; // Don't count the null - if (strncmp(argValue, strPrefix, strPrefixLen) == 0) + if (IsStrString(argValue)) { // Skip the prefix - argValue += strPrefixLen; - argLen -= strPrefixLen; + argValue += kStrStringPrefixLen; + argLen -= kStrStringPrefixLen; } *value = chip::ByteSpan(chip::Uint8::from_char(argValue), argLen); return true; diff --git a/examples/chip-tool/commands/common/CustomStringPrefix.h b/examples/chip-tool/commands/common/CustomStringPrefix.h new file mode 100644 index 00000000000000..a3133b3876b393 --- /dev/null +++ b/examples/chip-tool/commands/common/CustomStringPrefix.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#pragma once + +static constexpr char kHexStringPrefix[] = "hex:"; +constexpr size_t kHexStringPrefixLen = ArraySize(kHexStringPrefix) - 1; // Don't count the null + +static constexpr char kStrStringPrefix[] = "str:"; +constexpr size_t kStrStringPrefixLen = ArraySize(kStrStringPrefix) - 1; // Don't count the null + +inline bool IsHexString(const char * str) +{ + return strncmp(str, kHexStringPrefix, kHexStringPrefixLen) == 0; +} + +inline bool IsStrString(const char * str) +{ + return strncmp(str, kStrStringPrefix, kStrStringPrefixLen) == 0; +}