@@ -242,8 +242,14 @@ bool OutputStream::writeText (const String& text, bool asUTF16, bool writeUTF16B
242242 continue ;
243243 }
244244
245- if (! writeShort ((short ) c))
246- return false ;
245+ CharPointer_UTF16::CharType buffer[2 ]{};
246+ CharPointer_UTF16 begin { buffer };
247+ auto end = begin;
248+ end.write (c);
249+
250+ for (const auto unit : makeRange (begin.getAddress (), end.getAddress ()))
251+ if (! writeShort ((short ) unit))
252+ return false ;
247253 }
248254 }
249255 else
@@ -403,4 +409,43 @@ JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const New
403409 return stream << stream.getNewLineString ();
404410}
405411
412+ #if JUCE_UNIT_TESTS
413+
414+ class OutputStreamUTF16Test final : public UnitTest
415+ {
416+ public:
417+ OutputStreamUTF16Test () : UnitTest { " OutputStream::writeText UTF16" , UnitTestCategories::streams } {}
418+
419+ void runTest () final
420+ {
421+ beginTest (" writeText UTF16 - Can support full unicode codepoints" );
422+ {
423+ static constexpr juce_wchar stringA[] { 0x1F600 , 0x00 }; // Grinning face emoji
424+ static constexpr juce_wchar stringB[] { 0xA , 0xB , 0xC , 0x0 }; // ASCII
425+ static constexpr juce_wchar stringC[] { 0xAAAA , 0xBBBB , 0xCCCC , 0x0 }; // two-byte characters
426+
427+ CharPointer_UTF32 pointers[] { CharPointer_UTF32 (stringA),
428+ CharPointer_UTF32 (stringB),
429+ CharPointer_UTF32 (stringC) };
430+
431+ for (auto originalPtr : pointers)
432+ {
433+ MemoryOutputStream stream;
434+ stream.writeText (originalPtr, true , false , " \n " );
435+
436+ expect (stream.getDataSize () != 0 );
437+
438+ CharPointer_UTF16 writtenPtr { reinterpret_cast <const CharPointer_UTF16::CharType*> (stream.getData ()) };
439+
440+ for (; *originalPtr != 0 ; ++originalPtr, ++writtenPtr)
441+ expect (*originalPtr == *writtenPtr);
442+ }
443+ }
444+ }
445+ };
446+
447+ static OutputStreamUTF16Test outputStreamUTF16Test;
448+
449+ #endif
450+
406451} // namespace juce
0 commit comments