From 294bbdfe78493facaa46b3280a9c7dafd5ac7166 Mon Sep 17 00:00:00 2001 From: JoDavidsson <93616303+JoDavidsson@users.noreply.github.com> Date: Fri, 13 Feb 2026 08:24:15 +0100 Subject: [PATCH] fix(sdk): harden QR/Aruco APIs and detection wrappers --- sdk/include/Posemesh/Portals.hpp | 15 ++++++- sdk/platform/Web/ArucoDetection.js | 7 +++- sdk/platform/Web/QRDetection.js | 7 +++- sdk/src/ArucoDetection.cpp | 17 ++++++-- sdk/src/C/ArucoDetection.cpp | 46 +++++++++++++++++---- sdk/src/C/CalibrationHelpers.cpp | 7 ++++ sdk/src/C/Config.cpp | 22 ++++++++++ sdk/src/C/PoseEstimation.cpp | 16 ++++++++ sdk/src/C/QRDetection.cpp | 44 +++++++++++++++++--- sdk/src/QRDetection.cpp | 64 +++++++++++++++++++++--------- 10 files changed, 206 insertions(+), 39 deletions(-) diff --git a/sdk/include/Posemesh/Portals.hpp b/sdk/include/Posemesh/Portals.hpp index 5b65db21..e70627f5 100644 --- a/sdk/include/Posemesh/Portals.hpp +++ b/sdk/include/Posemesh/Portals.hpp @@ -2,6 +2,7 @@ #define __PORTALS_HPP__ #include +#include #include namespace psm { @@ -24,7 +25,19 @@ class Portals final { static std::string extractShortId(const std::string& portalContents) { - return portalContents.substr(m_aukiLighthousePrefix.size()); + auto it = std::search( + portalContents.begin(), + portalContents.end(), + m_aukiLighthousePrefix.begin(), + m_aukiLighthousePrefix.end(), + [](unsigned char ch1, unsigned char ch2) { + return std::toupper(ch1) == std::toupper(ch2); + }); + if (it == portalContents.end()) { + return portalContents; + } + it += m_aukiLighthousePrefix.size(); + return std::string(it, portalContents.end()); } private: diff --git a/sdk/platform/Web/ArucoDetection.js b/sdk/platform/Web/ArucoDetection.js index 867ce3ab..60129191 100644 --- a/sdk/platform/Web/ArucoDetection.js +++ b/sdk/platform/Web/ArucoDetection.js @@ -41,11 +41,11 @@ __internalPosemeshAPI.builderFunctions.push(function() { }; __internalPosemesh.ArucoDetection.detectArucoFromLuminanceLandmarkObservations = function(imageBytes, width, height, markerFormat) { - let imageBytesVector = undefined; + let imageBytesVector = undefined, observations = undefined; try { imageBytesVector = __internalPosemeshAPI.toVectorUint8(imageBytes) let result = [] - let observations = __internalPosemesh.ArucoDetection.__detectArucoFromLuminanceLandmarkObservations(imageBytesVector, width, height, markerFormat) + observations = __internalPosemesh.ArucoDetection.__detectArucoFromLuminanceLandmarkObservations(imageBytesVector, width, height, markerFormat) for (let i = 0; i < observations.size(); i++) { result.push(observations.get(i)) @@ -53,6 +53,9 @@ __internalPosemeshAPI.builderFunctions.push(function() { return result; } finally { + if (observations) { + observations.delete(); + } if (imageBytesVector) { imageBytesVector.delete(); } diff --git a/sdk/platform/Web/QRDetection.js b/sdk/platform/Web/QRDetection.js index 2c8c0ce7..bba14ffb 100644 --- a/sdk/platform/Web/QRDetection.js +++ b/sdk/platform/Web/QRDetection.js @@ -41,11 +41,11 @@ __internalPosemeshAPI.builderFunctions.push(function() { }; __internalPosemesh.QRDetection.detectQRFromLuminanceLandmarkObservations = function(imageBytes, width, height) { - let imageBytesVector = undefined; + let imageBytesVector = undefined, observations = undefined; try { imageBytesVector = __internalPosemeshAPI.toVectorUint8(imageBytes) let result = [] - let observations = __internalPosemesh.QRDetection.__detectQRFromLuminanceLandmarkObservations(imageBytesVector, width, height) + observations = __internalPosemesh.QRDetection.__detectQRFromLuminanceLandmarkObservations(imageBytesVector, width, height) for (let i = 0; i < observations.size(); i++) { result.push(observations.get(i)) @@ -53,6 +53,9 @@ __internalPosemeshAPI.builderFunctions.push(function() { return result; } finally { + if (observations) { + observations.delete(); + } if (imageBytesVector) { imageBytesVector.delete(); } diff --git a/sdk/src/ArucoDetection.cpp b/sdk/src/ArucoDetection.cpp index d325821c..4bc0389a 100644 --- a/sdk/src/ArucoDetection.cpp +++ b/sdk/src/ArucoDetection.cpp @@ -71,6 +71,9 @@ bool ArucoDetection::detectArucoFromLuminance( std::vector& outContents, std::vector& outCorners) { + outContents.clear(); + outCorners.clear(); + try { if (width <= 0) { throw std::invalid_argument("width"); @@ -78,6 +81,9 @@ bool ArucoDetection::detectArucoFromLuminance( if (height <= 0) { throw std::invalid_argument("height"); } + if (!imageBytes) { + throw std::invalid_argument("imageBytes"); + } if (imageBytesSize != width * height * sizeof(std::uint8_t)) { throw std::invalid_argument("imageBytesSize"); } @@ -102,7 +108,7 @@ bool ArucoDetection::detectArucoFromLuminance( outContents.reserve(contentsFound.size()); outCorners.clear(); - outCorners.reserve(cornersFound.size()); + outCorners.reserve(cornersFound.size() * 4); for (std::size_t i = 0; i < contentsFound.size(); ++i) { outContents.push_back(std::to_string(contentsFound[i])); @@ -207,10 +213,15 @@ std::vector ArucoDetection::detectArucoFromLuminance( std::vector observations; if (detected) { - for (int i = 0; i < outContents.size(); i++) { + if (outCorners.size() < outContents.size() * 4) { + std::cerr << "ArucoDetection::detectArucoFromLuminance(): Observation corner count mismatch." << std::endl; + return observations; + } + for (std::size_t i = 0; i < outContents.size(); i++) { + const std::size_t cornerBaseIndex = i * 4; for (int j = 0; j < 4; j++) { LandmarkObservation l; - l.setPosition(outCorners[i * 4 + j]); + l.setPosition(outCorners[cornerBaseIndex + j]); l.setType(arucoMarkerFormatToString(markerFormat)); std::string content = outContents[i]; if (Portals::isAukiQR(content)) { diff --git a/sdk/src/C/ArucoDetection.cpp b/sdk/src/C/ArucoDetection.cpp index 38f4cb46..28b8aef3 100644 --- a/sdk/src/C/ArucoDetection.cpp +++ b/sdk/src/C/ArucoDetection.cpp @@ -25,6 +25,19 @@ bool PSM_API psm_aruco_detection_detect_aruco( assert(!"psm_aruco_detection_detect_aruco(): out_corners is null"); return false; } + *out_contents = nullptr; + if (out_contents_count) { + *out_contents_count = 0; + } + *out_corners = nullptr; + if (out_corners_count) { + *out_corners_count = 0; + } + if (!image_bytes && image_bytes_size != 0) { + assert(!"psm_aruco_detection_detect_aruco(): image_bytes is null and image_bytes_size is non-zero"); + return false; + } + std::vector contents; std::vector corners; const bool result = psm::ArucoDetection::detectArucoFromLuminance(image_bytes, image_bytes_size, width, height, (psm::ArucoMarkerFormat)marker_format, contents, corners); @@ -43,12 +56,15 @@ bool PSM_API psm_aruco_detection_detect_aruco( contents_buffer_size += content.size() + 1; } std::unique_ptr contents_buffer(new (std::nothrow) char[contents_buffer_size]); + if (!contents_buffer) { + return false; + } char** contents_prefix_ptr = reinterpret_cast(contents_buffer.get()); char* contents_content_ptr = contents_buffer.get() + contents_prefix_offset; for (const auto& content : contents) { *contents_prefix_ptr = contents_content_ptr; contents_prefix_ptr++; - std::memcpy(contents_content_ptr, content.data(), content.size() + 1); + std::memcpy(contents_content_ptr, content.c_str(), content.size() + 1); contents_content_ptr += content.size() + 1; } *contents_prefix_ptr = nullptr; @@ -63,6 +79,9 @@ bool PSM_API psm_aruco_detection_detect_aruco( const auto corners_prefix_offset = corners_buffer_size; corners_buffer_size += corners.size() * sizeof(psm_vector2_t); std::unique_ptr corners_buffer(new (std::nothrow) char[corners_buffer_size]); + if (!corners_buffer) { + return false; + } psm_vector2_t** corners_prefix_ptr = reinterpret_cast(corners_buffer.get()); psm_vector2_t* corners_content_ptr = reinterpret_cast(corners_buffer.get() + corners_prefix_offset); for (auto& corner : corners) { @@ -88,7 +107,7 @@ void PSM_API psm_aruco_detection_detect_aruco_free(const char* const* contents, { delete[] const_cast(reinterpret_cast(contents)); if (corners) { - for (const auto* const* corner = corners; corner; ++corner) { + for (const auto* const* corner = corners; *corner; ++corner) { (*corner)->~Vector2(); } delete[] const_cast(reinterpret_cast(corners)); @@ -108,9 +127,19 @@ bool PSM_API psm_aruco_detection_detect_aruco_landmark_observations( assert(!"psm_aruco_detection_detect_aruco_landmark_observations(): out_observations is null"); return false; } - std::vector contents; - std::vector corners; - std::vector image_bytes_vector(image_bytes, image_bytes + image_bytes_size); + *out_observations = nullptr; + if (out_observations_count) { + *out_observations_count = 0; + } + if (!image_bytes && image_bytes_size != 0) { + assert(!"psm_aruco_detection_detect_aruco_landmark_observations(): image_bytes is null and image_bytes_size is non-zero"); + return false; + } + + std::vector image_bytes_vector; + if (image_bytes_size > 0) { + image_bytes_vector.assign(image_bytes, image_bytes + image_bytes_size); + } const std::vector observations = psm::ArucoDetection::detectArucoFromLuminance(image_bytes_vector, width, height, (psm::ArucoMarkerFormat)marker_format); if (observations.size() == 0) { return false; @@ -126,7 +155,10 @@ bool PSM_API psm_aruco_detection_detect_aruco_landmark_observations( landmark_observation_buffer_size = ((landmark_observation_buffer_size + alignof(psm_landmark_observation_t) - 1) / alignof(psm_landmark_observation_t)) * alignof(psm_landmark_observation_t); // Ensure alignment const auto landmark_observation_prefix_offset = landmark_observation_buffer_size; landmark_observation_buffer_size += observations.size() * sizeof(psm_landmark_observation_t); - std::unique_ptr landmark_observation_buffer(new (std::nothrow) psm_landmark_observation_t[landmark_observation_buffer_size]); + std::unique_ptr landmark_observation_buffer(new (std::nothrow) char[landmark_observation_buffer_size]); + if (!landmark_observation_buffer) { + return false; + } psm_landmark_observation_t** landmark_observation_prefix_ptr = reinterpret_cast(landmark_observation_buffer.get()); psm_landmark_observation_t* landmark_observation_content_ptr = reinterpret_cast(landmark_observation_buffer.get() + landmark_observation_prefix_offset); for (auto& observation : observations) { @@ -150,6 +182,6 @@ void PSM_API psm_aruco_detection_detect_aruco_landmark_observations_free(const p for (const auto* const* observation = observations; *observation; ++observation) { (*observation)->~LandmarkObservation(); } - delete[] const_cast(reinterpret_cast(observations)); + delete[] const_cast(reinterpret_cast(observations)); } } diff --git a/sdk/src/C/CalibrationHelpers.cpp b/sdk/src/C/CalibrationHelpers.cpp index 98b8e3ef..67c4f6fd 100644 --- a/sdk/src/C/CalibrationHelpers.cpp +++ b/sdk/src/C/CalibrationHelpers.cpp @@ -6,9 +6,16 @@ const psm_matrix4x4_t* psm_calibration_helpers_get_calibration_matrix(psm_pose_t* domain, psm_pose_t* observed, bool only_rotate_around_y) { + if (!domain || !observed) { + return nullptr; + } + psm::Matrix4x4 calibrationMatrix = psm::CalibrationHelpers::getCalibrationMatrix(*static_cast(domain), *static_cast(observed), only_rotate_around_y); psm_matrix4x4_t* result = psm_matrix4x4_create(); + if (!result) { + return nullptr; + } psm_matrix4x4_set_m00(result, calibrationMatrix.getM00()); psm_matrix4x4_set_m10(result, calibrationMatrix.getM10()); psm_matrix4x4_set_m20(result, calibrationMatrix.getM20()); diff --git a/sdk/src/C/Config.cpp b/sdk/src/C/Config.cpp index 494b1de0..625f6d7c 100644 --- a/sdk/src/C/Config.cpp +++ b/sdk/src/C/Config.cpp @@ -62,6 +62,9 @@ const char* const* psm_config_get_bootstraps(const psm_config_t* config, uint32_ buffer_size += bootstrap.size() + 1; } char* buffer = new (std::nothrow) char[buffer_size]; + if (!buffer) { + return nullptr; + } char** prefix_ptr = reinterpret_cast(buffer); char* content_ptr = buffer + prefix_offset; for (const auto& bootstrap : bootstraps) { @@ -128,6 +131,9 @@ const char* const* psm_config_get_relays(const psm_config_t* config, uint32_t* o buffer_size += relay.size() + 1; } char* buffer = new (std::nothrow) char[buffer_size]; + if (!buffer) { + return nullptr; + } char** prefix_ptr = reinterpret_cast(buffer); char* content_ptr = buffer + prefix_offset; for (const auto& relay : relays) { @@ -195,6 +201,12 @@ const uint8_t* psm_config_get_private_key(const psm_config_t* config, uint32_t* } auto* result = new (std::nothrow) std::uint8_t[private_key.size()]; + if (!result) { + if (out_private_key_size) { + *out_private_key_size = 0; + } + return nullptr; + } std::memcpy(result, private_key.data(), private_key.size()); if (out_private_key_size) { *out_private_key_size = static_cast(private_key.size()); @@ -217,6 +229,10 @@ void psm_config_set_private_key(psm_config_t* config, const uint8_t* private_key assert(!"psm_config_set_private_key(): private_key is null and private_key_size is non-zero"); return; } + if (!private_key || private_key_size == 0) { + config->setPrivateKey(std::vector {}); + return; + } config->setPrivateKey(std::vector { private_key, private_key + private_key_size }); } @@ -234,6 +250,9 @@ const char* PSM_API psm_config_get_private_key_path(const psm_config_t* config) } auto* result = new (std::nothrow) char[private_key_path.size() + 1]; + if (!result) { + return nullptr; + } std::memcpy(result, private_key_path.c_str(), private_key_path.size() + 1); return result; } @@ -284,6 +303,9 @@ const char* PSM_API psm_config_get_name(const psm_config_t* config) } auto* result = new (std::nothrow) char[name.size() + 1]; + if (!result) { + return nullptr; + } std::memcpy(result, name.c_str(), name.size() + 1); return result; } diff --git a/sdk/src/C/PoseEstimation.cpp b/sdk/src/C/PoseEstimation.cpp index 7accd20b..1924380a 100644 --- a/sdk/src/C/PoseEstimation.cpp +++ b/sdk/src/C/PoseEstimation.cpp @@ -10,13 +10,29 @@ enum psm_pose_estimation_solve_pnp_result psm_pose_estimation_solve_pnp( psm_pose_t* out_pose, psm_solve_pnp_method_e method) { + if (!landmarks || landmarks_count <= 0) { + return PSM_POSE_ESTIMATION_SOLVE_PNP_RESULT_FAILED; + } + if (!landmark_observations || landmark_observations_count <= 0) { + return PSM_POSE_ESTIMATION_SOLVE_PNP_RESULT_FAILED; + } + if (!camera_matrix || !out_pose) { + return PSM_POSE_ESTIMATION_SOLVE_PNP_RESULT_FAILED; + } + std::vector l(landmarks_count); for (int i = 0; i < landmarks_count; i++) { + if (!landmarks[i]) { + return PSM_POSE_ESTIMATION_SOLVE_PNP_RESULT_FAILED; + } l[i] = *(landmarks[i]); } std::vector lo(landmark_observations_count); for (int i = 0; i < landmark_observations_count; i++) { + if (!landmark_observations[i]) { + return PSM_POSE_ESTIMATION_SOLVE_PNP_RESULT_FAILED; + } lo[i] = *(landmark_observations[i]); } diff --git a/sdk/src/C/QRDetection.cpp b/sdk/src/C/QRDetection.cpp index 6f5c240f..3f2b3be7 100644 --- a/sdk/src/C/QRDetection.cpp +++ b/sdk/src/C/QRDetection.cpp @@ -24,6 +24,19 @@ bool PSM_API psm_qr_detection_detect_qr( assert(!"psm_qr_detection_detect_qr(): out_corners is null"); return false; } + *out_contents = nullptr; + if (out_contents_count) { + *out_contents_count = 0; + } + *out_corners = nullptr; + if (out_corners_count) { + *out_corners_count = 0; + } + if (!image_bytes && image_bytes_size != 0) { + assert(!"psm_qr_detection_detect_qr(): image_bytes is null and image_bytes_size is non-zero"); + return false; + } + std::vector contents; std::vector corners; const bool result = psm::QRDetection::detectQRFromLuminance(image_bytes, image_bytes_size, width, height, contents, corners); @@ -42,12 +55,15 @@ bool PSM_API psm_qr_detection_detect_qr( contents_buffer_size += content.size() + 1; } std::unique_ptr contents_buffer(new (std::nothrow) char[contents_buffer_size]); + if (!contents_buffer) { + return false; + } char** contents_prefix_ptr = reinterpret_cast(contents_buffer.get()); char* contents_content_ptr = contents_buffer.get() + contents_prefix_offset; for (const auto& content : contents) { *contents_prefix_ptr = contents_content_ptr; contents_prefix_ptr++; - std::memcpy(contents_content_ptr, content.data(), content.size() + 1); + std::memcpy(contents_content_ptr, content.c_str(), content.size() + 1); contents_content_ptr += content.size() + 1; } *contents_prefix_ptr = nullptr; @@ -62,6 +78,9 @@ bool PSM_API psm_qr_detection_detect_qr( const auto corners_prefix_offset = corners_buffer_size; corners_buffer_size += corners.size() * sizeof(psm_vector2_t); std::unique_ptr corners_buffer(new (std::nothrow) char[corners_buffer_size]); + if (!corners_buffer) { + return false; + } psm_vector2_t** corners_prefix_ptr = reinterpret_cast(corners_buffer.get()); psm_vector2_t* corners_content_ptr = reinterpret_cast(corners_buffer.get() + corners_prefix_offset); for (auto& corner : corners) { @@ -106,9 +125,19 @@ bool PSM_API psm_qr_detection_detect_qr_landmark_observations( assert(!"psm_qr_detection_detect_qr_landmark_observations(): out_observations is null"); return false; } - std::vector contents; - std::vector corners; - std::vector image_bytes_vector(image_bytes, image_bytes + image_bytes_size); + *out_observations = nullptr; + if (out_observations_count) { + *out_observations_count = 0; + } + if (!image_bytes && image_bytes_size != 0) { + assert(!"psm_qr_detection_detect_qr_landmark_observations(): image_bytes is null and image_bytes_size is non-zero"); + return false; + } + + std::vector image_bytes_vector; + if (image_bytes_size > 0) { + image_bytes_vector.assign(image_bytes, image_bytes + image_bytes_size); + } const std::vector observations = psm::QRDetection::detectQRFromLuminance(image_bytes_vector, width, height); if (observations.size() == 0) { return false; @@ -124,7 +153,10 @@ bool PSM_API psm_qr_detection_detect_qr_landmark_observations( landmark_observation_buffer_size = ((landmark_observation_buffer_size + alignof(psm_landmark_observation_t) - 1) / alignof(psm_landmark_observation_t)) * alignof(psm_landmark_observation_t); // Ensure alignment const auto landmark_observation_prefix_offset = landmark_observation_buffer_size; landmark_observation_buffer_size += observations.size() * sizeof(psm_landmark_observation_t); - std::unique_ptr landmark_observation_buffer(new (std::nothrow) psm_landmark_observation_t[landmark_observation_buffer_size]); + std::unique_ptr landmark_observation_buffer(new (std::nothrow) char[landmark_observation_buffer_size]); + if (!landmark_observation_buffer) { + return false; + } psm_landmark_observation_t** landmark_observation_prefix_ptr = reinterpret_cast(landmark_observation_buffer.get()); psm_landmark_observation_t* landmark_observation_content_ptr = reinterpret_cast(landmark_observation_buffer.get() + landmark_observation_prefix_offset); for (auto& observation : observations) { @@ -148,6 +180,6 @@ void PSM_API psm_qr_detection_detect_qr_landmark_observations_free(const psm_lan for (const auto* const* observation = observations; *observation; ++observation) { (*observation)->~LandmarkObservation(); } - delete[] const_cast(reinterpret_cast(observations)); + delete[] const_cast(reinterpret_cast(observations)); } } diff --git a/sdk/src/QRDetection.cpp b/sdk/src/QRDetection.cpp index 7e7a6a85..1adf2376 100644 --- a/sdk/src/QRDetection.cpp +++ b/sdk/src/QRDetection.cpp @@ -16,6 +16,9 @@ bool QRDetection::detectQRFromLuminance( std::vector& outContents, std::vector& outCorners) { + outContents.clear(); + outCorners.clear(); + try { if (width <= 0) { throw std::invalid_argument("width"); @@ -23,6 +26,9 @@ bool QRDetection::detectQRFromLuminance( if (height <= 0) { throw std::invalid_argument("height"); } + if (!imageBytes) { + throw std::invalid_argument("imageBytes"); + } if (imageBytesSize != width * height * sizeof(std::uint8_t)) { throw std::invalid_argument("imageBytesSize"); } @@ -30,28 +36,45 @@ bool QRDetection::detectQRFromLuminance( // Hacky, but we aren't gonna modify cvImage so this way we skip unnecessary copying const cv::Mat cvImage(cv::Size(width, height), CV_8U, const_cast(imageBytes)); - const cv::QRCodeDetector qrDetector; + cv::QRCodeDetector qrDetector; std::vector cornersFound; std::vector contentsFound; - const bool detected = qrDetector.detectAndDecodeMulti(cvImage, contentsFound, cornersFound); - if (detected) { - outContents.clear(); - outContents.reserve(contentsFound.size()); - for (const auto& s : contentsFound) { - outContents.push_back(s); - } - outCorners.clear(); - outCorners.reserve(cornersFound.size()); - for (const auto& p : cornersFound) { - Vector2 corner; - corner.setX(p.x); - corner.setY(p.y); - outCorners.push_back(std::move(corner)); + bool detected = qrDetector.detectAndDecodeMulti(cvImage, contentsFound, cornersFound); + if (!detected) { + std::vector singleCorners; + std::string singleContent = qrDetector.detectAndDecode(cvImage, singleCorners); + if (!singleContent.empty() && singleCorners.size() == 4) { + contentsFound.push_back(std::move(singleContent)); + cornersFound.reserve(singleCorners.size()); + for (const auto& corner : singleCorners) { + cornersFound.emplace_back(static_cast(corner.x), static_cast(corner.y)); + } + detected = true; } - } else { + } + + if (!detected) { + return false; + } + + if (cornersFound.size() != contentsFound.size() * 4) { + std::cerr << "QRDetection::detectQRFromLuminance(): Invalid corner output count from decoder." << std::endl; return false; } + + outContents.reserve(contentsFound.size()); + for (const auto& s : contentsFound) { + outContents.push_back(s); + } + + outCorners.reserve(cornersFound.size()); + for (const auto& p : cornersFound) { + Vector2 corner; + corner.setX(p.x); + corner.setY(p.y); + outCorners.push_back(std::move(corner)); + } } catch (const cv::Exception& e) { std::cerr << "QRDetection::detectQRFromLuminance(): An OpenCV exception occurred: " << e.what() << std::endl; return false; @@ -91,10 +114,15 @@ std::vector QRDetection::detectQRFromLuminance( std::vector observations; if (detected) { - for (int i = 0; i < outContents.size(); i++) { + if (outCorners.size() < outContents.size() * 4) { + std::cerr << "QRDetection::detectQRFromLuminance(): Observation corner count mismatch." << std::endl; + return observations; + } + for (std::size_t i = 0; i < outContents.size(); i++) { + const std::size_t cornerBaseIndex = i * 4; for (int j = 0; j < 4; j++) { LandmarkObservation l; - l.setPosition(outCorners[i * 4 + j]); + l.setPosition(outCorners[cornerBaseIndex + j]); l.setType("qr"); std::string content = outContents[i]; if (Portals::isAukiQR(content)) {