From 34854d87f4f18fb1d4e6874104f2e3f834df0cc8 Mon Sep 17 00:00:00 2001 From: Tuan Nghia Nguyen Date: Wed, 8 Apr 2026 15:22:48 +1000 Subject: [PATCH] Fix Uncode server API --- modules/ANSUtilities/ANSUtilities.cpp | 43 ++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/modules/ANSUtilities/ANSUtilities.cpp b/modules/ANSUtilities/ANSUtilities.cpp index 74f4c57..9529969 100644 --- a/modules/ANSUtilities/ANSUtilities.cpp +++ b/modules/ANSUtilities/ANSUtilities.cpp @@ -18,6 +18,15 @@ std::timed_mutex timeImageMutex; namespace ANSCENTER { + // Helper: detect if a std::string is actually UTF-16LE (e.g. from LabVIEW). + // Heuristic: length >= 4, even, and first printable ASCII char is followed by 0x00. + static bool IsLikelyUTF16LE(const std::string& str) { + if (str.size() < 4 || (str.size() % 2 != 0)) return false; + unsigned char b0 = static_cast(str[0]); + unsigned char b1 = static_cast(str[1]); + return (b0 >= 0x20 && b0 <= 0x7E && b1 == 0x00); + } + static void VerifyGlobalANSUltilityLicense(const std::string& licenseKey) { try { static const std::vector> licenseChecks = { @@ -1148,9 +1157,9 @@ namespace ANSCENTER for (int i = offset; i + 1 < endPos; i += 2) { uint16_t codepoint = static_cast(utf16leBytes[i]) | (static_cast(utf16leBytes[i + 1]) << 8); - // Pass through printable ASCII including space (0x20-0x7E) - // Escape control characters and non-ASCII as \uXXXX - if (codepoint >= 0x20 && codepoint <= 0x7E) { + // Pass through printable ASCII (0x20-0x7E) and common whitespace (tab, LF, CR) + // Escape other control characters and non-ASCII as \uXXXX + if ((codepoint >= 0x20 && codepoint <= 0x7E) || codepoint == 0x09 || codepoint == 0x0A || codepoint == 0x0D) { result += static_cast(codepoint); } else { char buf[7]; @@ -1163,17 +1172,22 @@ namespace ANSCENTER std::string ANSUtilities::ConvertUTF8ToUnicodeEscapes(const std::string& utf8Str) { if (utf8Str.empty()) return ""; + // Auto-detect UTF-16LE input (LabVIEW may pass UTF-16LE strings) + if (IsLikelyUTF16LE(utf8Str)) { + std::string asUtf8 = ConvertUTF16LEToUTF8(utf8Str.data(), static_cast(utf8Str.size())); + return ConvertUTF8ToUnicodeEscapes(asUtf8); + } std::string result; result.reserve(utf8Str.size() * 2); size_t i = 0; while (i < utf8Str.size()) { unsigned char c = static_cast(utf8Str[i]); - if (c >= 0x20 && c <= 0x7E) { - // Printable ASCII including space (0x20-0x7E) — pass through as-is + if ((c >= 0x20 && c <= 0x7E) || c == '\t' || c == '\n' || c == '\r') { + // Printable ASCII (0x20-0x7E) and common whitespace (tab, LF, CR) — pass through result += utf8Str[i]; i++; } else if (c <= 0x7F) { - // Control chars (0x00-0x1F), DEL (0x7F) — escape as \uXXXX + // Other control chars (0x00-0x08, 0x0B, 0x0C, 0x0E-0x1F), DEL (0x7F) — escape as \uXXXX char buf[7]; snprintf(buf, sizeof(buf), "\\u%04x", c); result += buf; @@ -1239,6 +1253,11 @@ namespace ANSCENTER std::string ANSUtilities::DoubleEscapeUnicode(const std::string& str) { if (str.empty()) return ""; + // Auto-detect UTF-16LE input (LabVIEW may pass UTF-16LE strings) + if (IsLikelyUTF16LE(str)) { + std::string asUtf8 = ConvertUTF16LEToUTF8(str.data(), static_cast(str.size())); + return DoubleEscapeUnicode(asUtf8); + } std::string result; result.reserve(str.size() + str.size() / 4); for (size_t i = 0; i < str.size(); i++) { @@ -1253,11 +1272,21 @@ namespace ANSCENTER } std::string ANSUtilities::ConvertUTF8ToDoubleEscapedUnicode(const std::string& utf8Str) { - return DoubleEscapeUnicode(ConvertUTF8ToUnicodeEscapes(utf8Str)); + if (utf8Str.empty()) return ""; + // Auto-detect UTF-16LE input (LabVIEW may pass UTF-16LE strings) + std::string inputStr = IsLikelyUTF16LE(utf8Str) + ? ConvertUTF16LEToUTF8(utf8Str.data(), static_cast(utf8Str.size())) + : utf8Str; + return DoubleEscapeUnicode(ConvertUTF8ToUnicodeEscapes(inputStr)); } std::string ANSUtilities::UnescapeDoubleEscapedUnicode(const std::string& str) { if (str.empty()) return ""; + // Auto-detect UTF-16LE input (LabVIEW may pass UTF-16LE strings) + if (IsLikelyUTF16LE(str)) { + std::string asUtf8 = ConvertUTF16LEToUTF8(str.data(), static_cast(str.size())); + return UnescapeDoubleEscapedUnicode(asUtf8); + } // Quick scan: if no \\u pattern exists, return original string unchanged bool found = false; for (size_t i = 0; i + 2 < str.size(); i++) {