From 07e3205c83c91b2bfdb7127990d222e355d1f659 Mon Sep 17 00:00:00 2001 From: Abhay Agarwal Date: Wed, 16 Sep 2026 07:52:05 +0200 Subject: [PATCH 1/2] fix(test): handle big-endian encoding in EncodeUCS2 test --- test/cpp/strings.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/test/cpp/strings.cpp b/test/cpp/strings.cpp index 9806886c..acb18b2a 100644 --- a/test/cpp/strings.cpp +++ b/test/cpp/strings.cpp @@ -26,7 +26,21 @@ NAN_METHOD(EncodeHex) { } NAN_METHOD(EncodeUCS2) { - info.GetReturnValue().Set(Encode(u"hello", 10, UCS2)); + // node::Encode(uint16_t*) reverses endianness on BE platforms. + // The char16_t literal u"hello" is BE on s390x but node::Encode expects LE, + // so we convert each code unit to LE explicitly before passing to Encode. + static const char16_t src[] = u"hello"; + static const size_t kNumChars = (sizeof(src) / sizeof(src[0])) - 1; // exclude NUL + uint16_t buf[kNumChars]; + for (size_t i = 0; i < kNumChars; i++) { + uint16_t v = static_cast(src[i]); +#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + buf[i] = static_cast((v >> 8) | (v << 8)); +#else + buf[i] = v; +#endif + } + info.GetReturnValue().Set(Encode(buf, kNumChars * sizeof(uint16_t), UCS2)); } Persistent returnUtf8String_persistent; From 177d37b05792056be1702e76e217e611b8592791 Mon Sep 17 00:00:00 2001 From: Abhay Agarwal Date: Sun, 27 Sep 2026 10:57:49 +0200 Subject: [PATCH 2/2] fix: handle big-endian encoding in Nan::Encode/TryEncode for UCS2 --- nan.h | 72 ++++++++++++++++++++++++++++++++++++++++++++ test/cpp/strings.cpp | 16 +--------- 2 files changed, 73 insertions(+), 15 deletions(-) diff --git a/nan.h b/nan.h index ae06696d..7aa02559 100644 --- a/nan.h +++ b/nan.h @@ -2435,6 +2435,16 @@ enum Encoding {ASCII, UTF8, BASE64, UCS2, BINARY, HEX, BUFFER}; # include "nan_string_bytes.h" // NOLINT(build/include) #endif +#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +namespace imp { +inline void SwapBytes16(const uint16_t* src, uint16_t* dst, size_t count) { + for (size_t i = 0; i < count; i++) { + dst[i] = static_cast((src[i] >> 8) | (src[i] << 8)); + } +} +} // namespace imp +#endif + #if NODE_MAJOR_VERSION >= 24 inline MaybeLocal TryEncode( const void *buf, size_t len, enum Encoding encoding = BINARY) { @@ -2442,10 +2452,22 @@ inline MaybeLocal TryEncode( node::encoding node_enc = static_cast(encoding); if (encoding == UCS2) { +#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + size_t count = len / 2; + uint16_t* swapped = new uint16_t[count]; + imp::SwapBytes16(reinterpret_cast(buf), swapped, count); + MaybeLocal result = node::TryEncode( + isolate + , swapped + , count); + delete[] swapped; + return result; +#else return node::TryEncode( isolate , reinterpret_cast(buf) , len / 2); +#endif } else { return node::TryEncode( isolate @@ -2469,10 +2491,22 @@ inline v8::Local Encode( node::encoding node_enc = static_cast(encoding); if (encoding == UCS2) { +#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + size_t count = len / 2; + uint16_t* swapped = new uint16_t[count]; + imp::SwapBytes16(reinterpret_cast(buf), swapped, count); + v8::Local result = node::Encode( + isolate + , swapped + , count); + delete[] swapped; + return result; +#else return node::Encode( isolate , reinterpret_cast(buf) , len / 2); +#endif } else { return node::Encode( isolate @@ -2481,14 +2515,51 @@ inline v8::Local Encode( , node_enc); } #elif (NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION) +# if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + if (encoding == UCS2) { + size_t count = len / 2; + uint16_t* swapped = new uint16_t[count]; + imp::SwapBytes16(reinterpret_cast(buf), swapped, count); + v8::Local result = node::Encode( + v8::Isolate::GetCurrent() + , reinterpret_cast(swapped) + , len + , static_cast(encoding)); + delete[] swapped; + return result; + } +# endif return node::Encode( v8::Isolate::GetCurrent() , buf, len , static_cast(encoding)); #else # if NODE_MODULE_VERSION >= NODE_0_10_MODULE_VERSION +# if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + if (encoding == UCS2) { + size_t count = len / 2; + uint16_t* swapped = new uint16_t[count]; + imp::SwapBytes16(reinterpret_cast(buf), swapped, count); + v8::Local result = + node::Encode(reinterpret_cast(swapped), len, + static_cast(encoding)); + delete[] swapped; + return result; + } +# endif return node::Encode(buf, len, static_cast(encoding)); # else +# if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + if (encoding == UCS2) { + size_t count = len / 2; + uint16_t* swapped = new uint16_t[count]; + imp::SwapBytes16(reinterpret_cast(buf), swapped, count); + v8::Local result = + imp::Encode(reinterpret_cast(swapped), len, encoding); + delete[] swapped; + return result; + } +# endif return imp::Encode(reinterpret_cast(buf), len, encoding); # endif #endif @@ -3200,3 +3271,4 @@ MakeMaybe(MaybeMaybe v) { } // end of namespace Nan #endif // NAN_H_ + diff --git a/test/cpp/strings.cpp b/test/cpp/strings.cpp index acb18b2a..9806886c 100644 --- a/test/cpp/strings.cpp +++ b/test/cpp/strings.cpp @@ -26,21 +26,7 @@ NAN_METHOD(EncodeHex) { } NAN_METHOD(EncodeUCS2) { - // node::Encode(uint16_t*) reverses endianness on BE platforms. - // The char16_t literal u"hello" is BE on s390x but node::Encode expects LE, - // so we convert each code unit to LE explicitly before passing to Encode. - static const char16_t src[] = u"hello"; - static const size_t kNumChars = (sizeof(src) / sizeof(src[0])) - 1; // exclude NUL - uint16_t buf[kNumChars]; - for (size_t i = 0; i < kNumChars; i++) { - uint16_t v = static_cast(src[i]); -#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - buf[i] = static_cast((v >> 8) | (v << 8)); -#else - buf[i] = v; -#endif - } - info.GetReturnValue().Set(Encode(buf, kNumChars * sizeof(uint16_t), UCS2)); + info.GetReturnValue().Set(Encode(u"hello", 10, UCS2)); } Persistent returnUtf8String_persistent;