Fix Uncode server API

This commit is contained in:
2026-04-08 15:22:48 +10:00
parent 69787b0ff0
commit 34854d87f4

View File

@@ -18,6 +18,15 @@ std::timed_mutex timeImageMutex;
namespace ANSCENTER 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<unsigned char>(str[0]);
unsigned char b1 = static_cast<unsigned char>(str[1]);
return (b0 >= 0x20 && b0 <= 0x7E && b1 == 0x00);
}
static void VerifyGlobalANSUltilityLicense(const std::string& licenseKey) { static void VerifyGlobalANSUltilityLicense(const std::string& licenseKey) {
try { try {
static const std::vector<std::pair<int, std::string>> licenseChecks = { static const std::vector<std::pair<int, std::string>> licenseChecks = {
@@ -1148,9 +1157,9 @@ namespace ANSCENTER
for (int i = offset; i + 1 < endPos; i += 2) { for (int i = offset; i + 1 < endPos; i += 2) {
uint16_t codepoint = static_cast<unsigned char>(utf16leBytes[i]) uint16_t codepoint = static_cast<unsigned char>(utf16leBytes[i])
| (static_cast<unsigned char>(utf16leBytes[i + 1]) << 8); | (static_cast<unsigned char>(utf16leBytes[i + 1]) << 8);
// Pass through printable ASCII including space (0x20-0x7E) // Pass through printable ASCII (0x20-0x7E) and common whitespace (tab, LF, CR)
// Escape control characters and non-ASCII as \uXXXX // Escape other control characters and non-ASCII as \uXXXX
if (codepoint >= 0x20 && codepoint <= 0x7E) { if ((codepoint >= 0x20 && codepoint <= 0x7E) || codepoint == 0x09 || codepoint == 0x0A || codepoint == 0x0D) {
result += static_cast<char>(codepoint); result += static_cast<char>(codepoint);
} else { } else {
char buf[7]; char buf[7];
@@ -1163,17 +1172,22 @@ namespace ANSCENTER
std::string ANSUtilities::ConvertUTF8ToUnicodeEscapes(const std::string& utf8Str) { std::string ANSUtilities::ConvertUTF8ToUnicodeEscapes(const std::string& utf8Str) {
if (utf8Str.empty()) return ""; 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<int>(utf8Str.size()));
return ConvertUTF8ToUnicodeEscapes(asUtf8);
}
std::string result; std::string result;
result.reserve(utf8Str.size() * 2); result.reserve(utf8Str.size() * 2);
size_t i = 0; size_t i = 0;
while (i < utf8Str.size()) { while (i < utf8Str.size()) {
unsigned char c = static_cast<unsigned char>(utf8Str[i]); unsigned char c = static_cast<unsigned char>(utf8Str[i]);
if (c >= 0x20 && c <= 0x7E) { if ((c >= 0x20 && c <= 0x7E) || c == '\t' || c == '\n' || c == '\r') {
// Printable ASCII including space (0x20-0x7E) — pass through as-is // Printable ASCII (0x20-0x7E) and common whitespace (tab, LF, CR) — pass through
result += utf8Str[i]; result += utf8Str[i];
i++; i++;
} else if (c <= 0x7F) { } 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]; char buf[7];
snprintf(buf, sizeof(buf), "\\u%04x", c); snprintf(buf, sizeof(buf), "\\u%04x", c);
result += buf; result += buf;
@@ -1239,6 +1253,11 @@ namespace ANSCENTER
std::string ANSUtilities::DoubleEscapeUnicode(const std::string& str) { std::string ANSUtilities::DoubleEscapeUnicode(const std::string& str) {
if (str.empty()) return ""; 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<int>(str.size()));
return DoubleEscapeUnicode(asUtf8);
}
std::string result; std::string result;
result.reserve(str.size() + str.size() / 4); result.reserve(str.size() + str.size() / 4);
for (size_t i = 0; i < str.size(); i++) { for (size_t i = 0; i < str.size(); i++) {
@@ -1253,11 +1272,21 @@ namespace ANSCENTER
} }
std::string ANSUtilities::ConvertUTF8ToDoubleEscapedUnicode(const std::string& utf8Str) { 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<int>(utf8Str.size()))
: utf8Str;
return DoubleEscapeUnicode(ConvertUTF8ToUnicodeEscapes(inputStr));
} }
std::string ANSUtilities::UnescapeDoubleEscapedUnicode(const std::string& str) { std::string ANSUtilities::UnescapeDoubleEscapedUnicode(const std::string& str) {
if (str.empty()) return ""; 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<int>(str.size()));
return UnescapeDoubleEscapedUnicode(asUtf8);
}
// Quick scan: if no \\u pattern exists, return original string unchanged // Quick scan: if no \\u pattern exists, return original string unchanged
bool found = false; bool found = false;
for (size_t i = 0; i + 2 < str.size(); i++) { for (size_t i = 0; i + 2 < str.size(); i++) {