diff --git a/examples/all-clusters-app/esp32/main/DeviceWithDisplay.cpp b/examples/all-clusters-app/esp32/main/DeviceWithDisplay.cpp index 55a77f4d3aaef4..011221e4629aa5 100644 --- a/examples/all-clusters-app/esp32/main/DeviceWithDisplay.cpp +++ b/examples/all-clusters-app/esp32/main/DeviceWithDisplay.cpp @@ -651,8 +651,11 @@ esp_err_t InitM5Stack(std::string qrCodeText) void InitDeviceDisplay() { - std::string qrCodeText; + // Create buffer for QR code that can fit max size and null terminator. + char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan qrCodeText(qrCodeBuffer); + // Get QR Code and emulate its content using NFC tag GetQRCode(qrCodeText, chip::RendezvousInformationFlags(CONFIG_RENDEZVOUS_MODE)); // Initialize the display device. diff --git a/examples/chef/esp32/main/main.cpp b/examples/chef/esp32/main/main.cpp index 03751d641dafd1..4d06267c55303e 100644 --- a/examples/chef/esp32/main/main.cpp +++ b/examples/chef/esp32/main/main.cpp @@ -137,7 +137,9 @@ const char * TAG = "chef-app"; #if CONFIG_HAVE_DISPLAY void printQRCode() { - std::string qrCodeText; + // Create buffer for QR code that can fit max size and null terminator. + char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan qrCodeText(qrCodeBuffer); GetQRCode(qrCodeText, chip::RendezvousInformationFlags(CONFIG_RENDEZVOUS_MODE)); @@ -153,7 +155,7 @@ void printQRCode() ScreenManager::Init(); ESP_LOGI(TAG, "Opening QR code screen"); - ESP_LOGI(TAG, "QR CODE Text: '%s'", qrCodeText.c_str()); + ESP_LOGI(TAG, "QR CODE Text: '%s'", qrCodeText.data()); ScreenManager::PushScreen(chip::Platform::New(qrCodeText)); } #endif // CONFIG_HAVE_DISPLAY diff --git a/examples/common/pigweed/rpc_services/Device.h b/examples/common/pigweed/rpc_services/Device.h index e0979365529f3f..3be6c8d6df47dc 100644 --- a/examples/common/pigweed/rpc_services/Device.h +++ b/examples/common/pigweed/rpc_services/Device.h @@ -146,10 +146,12 @@ class Device : public pw_rpc::nanopb::Device::Service snprintf(response.serial_number, sizeof(response.serial_number), CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER); } - std::string qrCodeText; + // Create buffer for QR code that can fit max size and null terminator. + char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan qrCodeText(qrCodeBuffer); if (GetQRCode(qrCodeText, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR) { - snprintf(response.pairing_info.qr_code, sizeof(response.pairing_info.qr_code), "%s", qrCodeText.c_str()); + snprintf(response.pairing_info.qr_code, sizeof(response.pairing_info.qr_code), "%s", qrCodeText.data()); GetQRCodeUrl(response.pairing_info.qr_code_url, sizeof(response.pairing_info.qr_code_url), qrCodeText); response.has_pairing_info = true; } diff --git a/examples/light-switch-app/efr32/src/AppTask.cpp b/examples/light-switch-app/efr32/src/AppTask.cpp index ea6ce7073eb128..0de6074a6eaa3b 100644 --- a/examples/light-switch-app/efr32/src/AppTask.cpp +++ b/examples/light-switch-app/efr32/src/AppTask.cpp @@ -239,11 +239,13 @@ CHIP_ERROR AppTask::Init() // Print setup info on LCD if available #ifdef DISPLAY_ENABLED - std::string QRCode; + // Create buffer for QR code that can fit max size and null terminator. + char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan QRCode(qrCodeBuffer); if (GetQRCode(QRCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR) { - LCDWriteQRCode((uint8_t *) QRCode.c_str()); + LCDWriteQRCode((uint8_t *) QRCode.data()); } else { diff --git a/examples/lighting-app/efr32/src/AppTask.cpp b/examples/lighting-app/efr32/src/AppTask.cpp index c61198b6954ce9..d9c5de9bc766b1 100644 --- a/examples/lighting-app/efr32/src/AppTask.cpp +++ b/examples/lighting-app/efr32/src/AppTask.cpp @@ -283,11 +283,13 @@ CHIP_ERROR AppTask::Init() // Print setup info on LCD if available #ifdef DISPLAY_ENABLED - std::string QRCode; + // Create buffer for QR code that can fit max size and null terminator. + char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan QRCode(qrCodeBuffer); if (GetQRCode(QRCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR) { - LCDWriteQRCode((uint8_t *) QRCode.c_str()); + LCDWriteQRCode((uint8_t *) QRCode.data()); } else { diff --git a/examples/lock-app/efr32/src/AppTask.cpp b/examples/lock-app/efr32/src/AppTask.cpp index 1f593f41322ab2..57b3c2478b5d0f 100644 --- a/examples/lock-app/efr32/src/AppTask.cpp +++ b/examples/lock-app/efr32/src/AppTask.cpp @@ -264,11 +264,13 @@ CHIP_ERROR AppTask::Init() // Print setup info on LCD if available #ifdef DISPLAY_ENABLED - std::string QRCode; + // Create buffer for QR code that can fit max size and null terminator. + char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan QRCode(qrCodeBuffer); if (GetQRCode(QRCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR) { - LCDWriteQRCode((uint8_t *) QRCode.c_str()); + LCDWriteQRCode((uint8_t *) QRCode.data()); } else { diff --git a/examples/ota-requestor-app/efr32/src/AppTask.cpp b/examples/ota-requestor-app/efr32/src/AppTask.cpp index 558db22f1860b5..e3255f3eace0df 100644 --- a/examples/ota-requestor-app/efr32/src/AppTask.cpp +++ b/examples/ota-requestor-app/efr32/src/AppTask.cpp @@ -170,11 +170,13 @@ CHIP_ERROR AppTask::Init() // Print setup info on LCD if available #ifdef DISPLAY_ENABLED - std::string QRCode; + // Create buffer for QR code that can fit max size and null terminator. + char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan QRCode(qrCodeBuffer); if (GetQRCode(QRCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR) { - LCDWriteQRCode((uint8_t *) QRCode.c_str()); + LCDWriteQRCode((uint8_t *) QRCode.data()); } else { diff --git a/examples/window-app/efr32/include/WindowAppImpl.h b/examples/window-app/efr32/include/WindowAppImpl.h index 7c03131955b524..34ab84f932dfa4 100644 --- a/examples/window-app/efr32/include/WindowAppImpl.h +++ b/examples/window-app/efr32/include/WindowAppImpl.h @@ -77,7 +77,10 @@ class WindowAppImpl : public WindowApp QueueHandle_t mQueue = nullptr; LEDWidget mStatusLED; LEDWidget mActionLED; - std::string mQRCode; + + // Get QR Code and emulate its content using NFC tag + char mQRCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan mQRCode(mQRCodeBuffer); Timer mIconTimer; LcdIcon mIcon = LcdIcon::None; }; diff --git a/examples/window-app/efr32/src/WindowAppImpl.cpp b/examples/window-app/efr32/src/WindowAppImpl.cpp index 5cfc4b6206c760..3ea70eda0781ca 100644 --- a/examples/window-app/efr32/src/WindowAppImpl.cpp +++ b/examples/window-app/efr32/src/WindowAppImpl.cpp @@ -435,7 +435,7 @@ void WindowAppImpl::UpdateLCD() { if (GetQRCode(mQRCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR) { - LCDWriteQRCode((uint8_t *) mQRCode.c_str()); + LCDWriteQRCode((uint8_t *) mQRCode.data()); } } #endif // QR_CODE_ENABLED diff --git a/src/app/server/OnboardingCodesUtil.cpp b/src/app/server/OnboardingCodesUtil.cpp index 8dc6e6e8a999e9..28451e207dbd36 100644 --- a/src/app/server/OnboardingCodesUtil.cpp +++ b/src/app/server/OnboardingCodesUtil.cpp @@ -50,7 +50,7 @@ void PrintOnboardingCodes(chip::RendezvousInformationFlags aRendezvousFlags) void PrintOnboardingCodes(const chip::PayloadContents & payload) { - char payloadBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength]; + char payloadBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; chip::MutableCharSpan qrCode(payloadBuffer); if (GetQRCode(qrCode, payload) == CHIP_NO_ERROR) @@ -86,7 +86,7 @@ void PrintOnboardingCodes(const chip::PayloadContents & payload) void ShareQRCodeOverNFC(chip::RendezvousInformationFlags aRendezvousFlags) { // Get QR Code and emulate its content using NFC tag - char payloadBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength]; + char payloadBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; chip::MutableCharSpan qrCode(payloadBuffer); ReturnOnFailure(GetQRCode(qrCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE))); @@ -154,8 +154,6 @@ CHIP_ERROR GetQRCode(chip::MutableCharSpan & aQRCode, chip::RendezvousInformatio CHIP_ERROR GetQRCode(chip::MutableCharSpan & aQRCode, const chip::PayloadContents & payload) { - // TODO: Usage of STL will significantly increase the image size, this should be changed to more efficient method for - // generating payload CHIP_ERROR err = chip::QRCodeBasicSetupPayloadGenerator(payload).payloadBase38Representation(aQRCode); if (err != CHIP_NO_ERROR) { @@ -166,7 +164,7 @@ CHIP_ERROR GetQRCode(chip::MutableCharSpan & aQRCode, const chip::PayloadContent return CHIP_NO_ERROR; } -CHIP_ERROR GetQRCodeUrl(char * aQRCodeUrl, size_t aUrlMaxSize, chip::MutableCharSpan & aQRCode) +CHIP_ERROR GetQRCodeUrl(char * aQRCodeUrl, size_t aUrlMaxSize, const chip::CharSpan & aQRCode) { VerifyOrReturnError(aQRCodeUrl, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(aUrlMaxSize >= (strlen(kQrCodeBaseUrl) + strlen(kUrlDataAssignmentPhrase) + aQRCode.size() + 1), diff --git a/src/app/server/OnboardingCodesUtil.h b/src/app/server/OnboardingCodesUtil.h index 00994dd52ffad3..26cc859514d2a7 100644 --- a/src/app/server/OnboardingCodesUtil.h +++ b/src/app/server/OnboardingCodesUtil.h @@ -23,11 +23,40 @@ void PrintOnboardingCodes(chip::RendezvousInformationFlags aRendezvousFlags); void PrintOnboardingCodes(const chip::PayloadContents & payload); void ShareQRCodeOverNFC(chip::RendezvousInformationFlags aRendezvousFlags); + +/** + * Creates a null-terminated QR code from the payload created based on rendezvous flag information. + * + * The resulting size of the QR code span will not include the null terminator. + */ CHIP_ERROR GetQRCode(chip::MutableCharSpan & aQRCode, chip::RendezvousInformationFlags aRendezvousFlags); + +/** + * Creates a null-terminated QR code based on the provided payload. + * + * The resulting size of the QR code span will not include the null terminator. + */ CHIP_ERROR GetQRCode(chip::MutableCharSpan & aQRCode, const chip::PayloadContents & payload); -CHIP_ERROR GetQRCodeUrl(char * aQRCodeUrl, size_t aUrlMaxSize, chip::MutableCharSpan & aQRCode); + +/** + * Creates a null-terminated QR code url. + */ +CHIP_ERROR GetQRCodeUrl(char * aQRCodeUrl, size_t aUrlMaxSize, const chip::CharSpan & aQRCode); + +/** + * Creates a null-terminated manual pairing code from the payload created based on rendezvous flag information. + * + * The resulting size of the manual pairing code span will not include the null terminator. + */ CHIP_ERROR GetManualPairingCode(chip::MutableCharSpan & aManualPairingCode, chip::RendezvousInformationFlags aRendezvousFlags); + +/** + * Creates a null-terminated manual pairing code based on the provided payload. + * + * The resulting size of the manual pairing code span will not include the null terminator. + */ CHIP_ERROR GetManualPairingCode(chip::MutableCharSpan & aManualPairingCode, const chip::PayloadContents & payload); + CHIP_ERROR GetPayloadContents(chip::PayloadContents & aPayload, chip::RendezvousInformationFlags aRendezvousFlags); /** diff --git a/src/controller/CommissioningWindowOpener.cpp b/src/controller/CommissioningWindowOpener.cpp index 9ff1c486ee6a8f..a6127d3a29848c 100644 --- a/src/controller/CommissioningWindowOpener.cpp +++ b/src/controller/CommissioningWindowOpener.cpp @@ -144,7 +144,7 @@ CHIP_ERROR CommissioningWindowOpener::OpenCommissioningWindowInternal(Operationa ReturnErrorOnFailure(cluster.InvokeCommand(request, this, OnOpenCommissioningWindowSuccess, OnOpenCommissioningWindowFailure, MakeOptional(kTimedInvokeTimeoutMs))); - char payloadBuffer[QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength]; + char payloadBuffer[QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; MutableCharSpan manualCode(payloadBuffer); ReturnErrorOnFailure(ManualSetupPayloadGenerator(mSetupPayload).payloadDecimalStringRepresentation(manualCode)); diff --git a/src/lib/shell/commands/OnboardingCodes.cpp b/src/lib/shell/commands/OnboardingCodes.cpp index 3acb3a4e6501f7..f977122158ca9e 100644 --- a/src/lib/shell/commands/OnboardingCodes.cpp +++ b/src/lib/shell/commands/OnboardingCodes.cpp @@ -36,21 +36,27 @@ namespace Shell { static CHIP_ERROR GetOnboardingQRCode(bool printHeader, chip::RendezvousInformationFlags aRendezvousFlags) { streamer_t * sout = streamer_get(); - std::string QRCode; + + // Create buffer for QR code that can fit max size and null terminator. + char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan QRCode(qrCodeBuffer); if (printHeader) { streamer_printf(sout, "QRCode: "); } ReturnErrorOnFailure(GetQRCode(QRCode, aRendezvousFlags)); - streamer_printf(sout, "%s\r\n", QRCode.c_str()); + streamer_printf(sout, "%s\r\n", QRCode.data()); return CHIP_NO_ERROR; } static CHIP_ERROR GetOnboardingQRCodeUrl(bool printHeader, chip::RendezvousInformationFlags aRendezvousFlags) { streamer_t * sout = streamer_get(); - std::string QRCode; + + // Create buffer for QR code that can fit max size and null terminator. + char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan QRCode(qrCodeBuffer); if (printHeader) { @@ -58,24 +64,27 @@ static CHIP_ERROR GetOnboardingQRCodeUrl(bool printHeader, chip::RendezvousInfor } ReturnErrorOnFailure(GetQRCode(QRCode, aRendezvousFlags)); - char qrCodeBuffer[CHIP_SHELL_MAX_BUFFER_SIZE]; + char qrCodeUrlBuffer[CHIP_SHELL_MAX_BUFFER_SIZE]; - ReturnErrorOnFailure(GetQRCodeUrl(qrCodeBuffer, sizeof(qrCodeBuffer), QRCode)); - streamer_printf(sout, "%s\r\n", qrCodeBuffer); + ReturnErrorOnFailure(GetQRCodeUrl(qrCodeUrlBuffer, sizeof(qrCodeUrlBuffer), QRCode)); + streamer_printf(sout, "%s\r\n", qrCodeUrlBuffer); return CHIP_NO_ERROR; } static CHIP_ERROR GetOnboardingManualPairingCode(bool printHeader, chip::RendezvousInformationFlags aRendezvousFlags) { streamer_t * sout = streamer_get(); - std::string manualPairingCode; + + // Create buffer for manual pariting code that can fit max size + check digit + null terminator. + char manualPairingCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kManualSetupLongCodeCharLength + 1]; + chip::MutableCharSpan manualPairingCode(manualPairingCodeBuffer); if (printHeader) { streamer_printf(sout, "ManualPairingCode: "); } ReturnErrorOnFailure(GetManualPairingCode(manualPairingCode, aRendezvousFlags)); - streamer_printf(sout, "%s\r\n", manualPairingCode.c_str()); + streamer_printf(sout, "%s\r\n", manualPairingCode.data()); return CHIP_NO_ERROR; } diff --git a/src/setup_payload/Base38Encode.cpp b/src/setup_payload/Base38Encode.cpp index f00f4b54602eff..2b53c9a691cfaf 100644 --- a/src/setup_payload/Base38Encode.cpp +++ b/src/setup_payload/Base38Encode.cpp @@ -81,6 +81,8 @@ CHIP_ERROR base38Encode(ByteSpan in_buf, MutableCharSpan & out_buf) if (out_idx < out_buf.size()) { out_buf.data()[out_idx] = '\0'; + // Reduce output span size to not include null-terminator. + out_buf.reduce_size(out_buf.size() - 1); } else { diff --git a/src/setup_payload/Base38Encode.h b/src/setup_payload/Base38Encode.h index 05d4f901e9f0e5..1da2f58a4e4c41 100644 --- a/src/setup_payload/Base38Encode.h +++ b/src/setup_payload/Base38Encode.h @@ -25,10 +25,16 @@ namespace chip { -// out_buf is null-terminated on success +/* + * The out_buf is null-terminated on success. + * + * The resulting size of the out_buf span will not include the null terminator. + */ CHIP_ERROR base38Encode(ByteSpan in_buf, MutableCharSpan & out_buf); -// returns size needed to store encoded string given number of input bytes +/* + * Returns size needed to store encoded string given number of input bytes including null terminator. + */ size_t base38EncodedLength(size_t num_bytes); } // namespace chip diff --git a/src/setup_payload/ManualSetupPayloadGenerator.cpp b/src/setup_payload/ManualSetupPayloadGenerator.cpp index a1e26dbcb93073..6567e5c5b8f090 100644 --- a/src/setup_payload/ManualSetupPayloadGenerator.cpp +++ b/src/setup_payload/ManualSetupPayloadGenerator.cpp @@ -152,6 +152,9 @@ CHIP_ERROR ManualSetupPayloadGenerator::payloadDecimalStringRepresentation(Mutab int checkDigit = Verhoeff10::CharToVal(Verhoeff10::ComputeCheckChar(outBuffer.data())); ReturnErrorOnFailure(decimalStringWithPadding(outBuffer.SubSpan(offset, 2), static_cast(checkDigit))); + // Reduce size of outBuffer by 1 to not include null terminator. + outBuffer.reduce_size(outBuffer.size() - 1); + return CHIP_NO_ERROR; } diff --git a/src/setup_payload/QRCodeSetupPayloadGenerator.h b/src/setup_payload/QRCodeSetupPayloadGenerator.h index c82aaa6ac71f77..e4407fa6aa67f7 100644 --- a/src/setup_payload/QRCodeSetupPayloadGenerator.h +++ b/src/setup_payload/QRCodeSetupPayloadGenerator.h @@ -112,6 +112,8 @@ class QRCodeBasicSetupPayloadGenerator * This function is called to encode the binary data of a payload to a * base38 null-terminated string. * + * The resulting size of the outBuffer span will not include the null terminator. + * * @param[out] outBuffer * The buffer to copy the base38 to. *