diff --git a/examples/DemoRunner/Builds/Android/app/CMakeLists.txt b/examples/DemoRunner/Builds/Android/app/CMakeLists.txt
index caac7696a5..395683d043 100644
--- a/examples/DemoRunner/Builds/Android/app/CMakeLists.txt
+++ b/examples/DemoRunner/Builds/Android/app/CMakeLists.txt
@@ -1211,8 +1211,11 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_core/text/juce_CharacterFunctions.h"
"../../../../../modules/juce_core/text/juce_CharPointer_ASCII.h"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF8.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF8_test.cpp"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF16.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF16_test.cpp"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF32.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF32_test.cpp"
"../../../../../modules/juce_core/text/juce_Identifier.cpp"
"../../../../../modules/juce_core/text/juce_Identifier.h"
"../../../../../modules/juce_core/text/juce_LocalisedStrings.cpp"
@@ -3732,8 +3735,11 @@ set_source_files_properties(
"../../../../../modules/juce_core/text/juce_CharacterFunctions.h"
"../../../../../modules/juce_core/text/juce_CharPointer_ASCII.h"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF8.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF8_test.cpp"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF16.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF16_test.cpp"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF32.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF32_test.cpp"
"../../../../../modules/juce_core/text/juce_Identifier.cpp"
"../../../../../modules/juce_core/text/juce_Identifier.h"
"../../../../../modules/juce_core/text/juce_LocalisedStrings.cpp"
diff --git a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj
index 6f1d681359..70dde5ca09 100644
--- a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj
+++ b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj
@@ -1538,6 +1538,15 @@
true
+
+ true
+
+
+ true
+
+
+ true
+
true
diff --git a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters
index 7029bfed70..76dce8451d 100644
--- a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters
+++ b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters
@@ -2272,6 +2272,15 @@
JUCE Modules\juce_core\text
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
JUCE Modules\juce_core\text
diff --git a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj
index 47e9214d09..73191b956a 100644
--- a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj
+++ b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj
@@ -1538,6 +1538,15 @@
true
+
+ true
+
+
+ true
+
+
+ true
+
true
diff --git a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters
index 32e0c670d3..f9c09729b3 100644
--- a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters
+++ b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters
@@ -2272,6 +2272,15 @@
JUCE Modules\juce_core\text
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
JUCE Modules\juce_core\text
diff --git a/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt b/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt
index 49ac3d972f..11540368ed 100644
--- a/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt
+++ b/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt
@@ -1070,8 +1070,11 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_core/text/juce_CharacterFunctions.h"
"../../../../../modules/juce_core/text/juce_CharPointer_ASCII.h"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF8.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF8_test.cpp"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF16.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF16_test.cpp"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF32.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF32_test.cpp"
"../../../../../modules/juce_core/text/juce_Identifier.cpp"
"../../../../../modules/juce_core/text/juce_Identifier.h"
"../../../../../modules/juce_core/text/juce_LocalisedStrings.cpp"
@@ -3274,8 +3277,11 @@ set_source_files_properties(
"../../../../../modules/juce_core/text/juce_CharacterFunctions.h"
"../../../../../modules/juce_core/text/juce_CharPointer_ASCII.h"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF8.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF8_test.cpp"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF16.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF16_test.cpp"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF32.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF32_test.cpp"
"../../../../../modules/juce_core/text/juce_Identifier.cpp"
"../../../../../modules/juce_core/text/juce_Identifier.h"
"../../../../../modules/juce_core/text/juce_LocalisedStrings.cpp"
diff --git a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj
index e0c4545c40..b0be6a8ecb 100644
--- a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj
+++ b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj
@@ -1357,6 +1357,15 @@
true
+
+ true
+
+
+ true
+
+
+ true
+
true
diff --git a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters
index fad4989f63..8a6aeab3d4 100644
--- a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters
+++ b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters
@@ -1948,6 +1948,15 @@
JUCE Modules\juce_core\text
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
JUCE Modules\juce_core\text
diff --git a/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt b/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt
index 35aaefb72f..67c51dbb6a 100644
--- a/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt
+++ b/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt
@@ -1103,8 +1103,11 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_core/text/juce_CharacterFunctions.h"
"../../../../../modules/juce_core/text/juce_CharPointer_ASCII.h"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF8.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF8_test.cpp"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF16.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF16_test.cpp"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF32.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF32_test.cpp"
"../../../../../modules/juce_core/text/juce_Identifier.cpp"
"../../../../../modules/juce_core/text/juce_Identifier.h"
"../../../../../modules/juce_core/text/juce_LocalisedStrings.cpp"
@@ -3460,8 +3463,11 @@ set_source_files_properties(
"../../../../../modules/juce_core/text/juce_CharacterFunctions.h"
"../../../../../modules/juce_core/text/juce_CharPointer_ASCII.h"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF8.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF8_test.cpp"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF16.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF16_test.cpp"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF32.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF32_test.cpp"
"../../../../../modules/juce_core/text/juce_Identifier.cpp"
"../../../../../modules/juce_core/text/juce_Identifier.h"
"../../../../../modules/juce_core/text/juce_LocalisedStrings.cpp"
diff --git a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj
index f3bdde7465..fa6b36b5ad 100644
--- a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj
+++ b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj
@@ -1365,6 +1365,15 @@
true
+
+ true
+
+
+ true
+
+
+ true
+
true
diff --git a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters
index 0fe8b36cd1..e6804e8cd7 100644
--- a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters
+++ b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters
@@ -2023,6 +2023,15 @@
JUCE Modules\juce_core\text
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
JUCE Modules\juce_core\text
diff --git a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj
index ffc939e0b7..e928a8a358 100644
--- a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj
+++ b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj
@@ -1365,6 +1365,15 @@
true
+
+ true
+
+
+ true
+
+
+ true
+
true
diff --git a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters
index d45df19419..efa8516045 100644
--- a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters
+++ b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters
@@ -2023,6 +2023,15 @@
JUCE Modules\juce_core\text
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
JUCE Modules\juce_core\text
diff --git a/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj b/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj
index 4a9a026217..07366eb352 100644
--- a/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj
+++ b/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj
@@ -391,6 +391,15 @@
true
+
+ true
+
+
+ true
+
+
+ true
+
true
diff --git a/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj.filters b/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj.filters
index 62ed01bcd4..d7c6eba364 100644
--- a/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj.filters
+++ b/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj.filters
@@ -373,6 +373,15 @@
JUCE Modules\juce_core\text
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
JUCE Modules\juce_core\text
diff --git a/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt b/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt
index 179362384d..615876fb03 100644
--- a/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt
+++ b/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt
@@ -1074,8 +1074,11 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_core/text/juce_CharacterFunctions.h"
"../../../../../modules/juce_core/text/juce_CharPointer_ASCII.h"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF8.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF8_test.cpp"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF16.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF16_test.cpp"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF32.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF32_test.cpp"
"../../../../../modules/juce_core/text/juce_Identifier.cpp"
"../../../../../modules/juce_core/text/juce_Identifier.h"
"../../../../../modules/juce_core/text/juce_LocalisedStrings.cpp"
@@ -3358,8 +3361,11 @@ set_source_files_properties(
"../../../../../modules/juce_core/text/juce_CharacterFunctions.h"
"../../../../../modules/juce_core/text/juce_CharPointer_ASCII.h"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF8.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF8_test.cpp"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF16.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF16_test.cpp"
"../../../../../modules/juce_core/text/juce_CharPointer_UTF32.h"
+ "../../../../../modules/juce_core/text/juce_CharPointer_UTF32_test.cpp"
"../../../../../modules/juce_core/text/juce_Identifier.cpp"
"../../../../../modules/juce_core/text/juce_Identifier.h"
"../../../../../modules/juce_core/text/juce_LocalisedStrings.cpp"
diff --git a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj
index 376f5b0c44..21ddf0af4f 100644
--- a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj
+++ b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj
@@ -1357,6 +1357,15 @@
true
+
+ true
+
+
+ true
+
+
+ true
+
true
diff --git a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters
index 442642a432..8dfcb4fc88 100644
--- a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters
+++ b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters
@@ -1978,6 +1978,15 @@
JUCE Modules\juce_core\text
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
JUCE Modules\juce_core\text
diff --git a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj
index c2ab74e706..cf7123264a 100644
--- a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj
+++ b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj
@@ -508,6 +508,15 @@
true
+
+ true
+
+
+ true
+
+
+ true
+
true
diff --git a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters
index 65ecd8be7b..f1096edf0e 100644
--- a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters
+++ b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters
@@ -826,6 +826,15 @@
JUCE Modules\juce_core\text
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
JUCE Modules\juce_core\text
diff --git a/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj b/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj
index 60528b4ce6..c08062d0bc 100644
--- a/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj
+++ b/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj
@@ -508,6 +508,15 @@
true
+
+ true
+
+
+ true
+
+
+ true
+
true
diff --git a/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj.filters b/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj.filters
index 5d29a07652..04aa8b1112 100644
--- a/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj.filters
+++ b/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj.filters
@@ -826,6 +826,15 @@
JUCE Modules\juce_core\text
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
JUCE Modules\juce_core\text
diff --git a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj
index e231c78418..ee652babf7 100644
--- a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj
+++ b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj
@@ -1373,6 +1373,15 @@
true
+
+ true
+
+
+ true
+
+
+ true
+
true
diff --git a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters
index fac0ff7ff9..4e021c4aeb 100644
--- a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters
+++ b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters
@@ -2044,6 +2044,15 @@
JUCE Modules\juce_core\text
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
JUCE Modules\juce_core\text
diff --git a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj
index e33bb5e735..d3ac59a4de 100644
--- a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj
+++ b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj
@@ -1373,6 +1373,15 @@
true
+
+ true
+
+
+ true
+
+
+ true
+
true
diff --git a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters
index 679ddd5d78..258e625d23 100644
--- a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters
+++ b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters
@@ -2044,6 +2044,15 @@
JUCE Modules\juce_core\text
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
JUCE Modules\juce_core\text
diff --git a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj
index 3ef5abd964..32cf266d79 100644
--- a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj
+++ b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj
@@ -1356,6 +1356,15 @@
true
+
+ true
+
+
+ true
+
+
+ true
+
true
diff --git a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj.filters b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj.filters
index 68b921b926..64f6fa7ab4 100644
--- a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj.filters
+++ b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj.filters
@@ -1975,6 +1975,15 @@
JUCE Modules\juce_core\text
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
+
+ JUCE Modules\juce_core\text
+
JUCE Modules\juce_core\text
diff --git a/modules/juce_core/juce_core.cpp b/modules/juce_core/juce_core.cpp
index 569ee83710..a61a55d0d2 100644
--- a/modules/juce_core/juce_core.cpp
+++ b/modules/juce_core/juce_core.cpp
@@ -295,6 +295,9 @@
#include "containers/juce_FixedSizeFunction_test.cpp"
#include "javascript/juce_JSONSerialisation_test.cpp"
#include "memory/juce_SharedResourcePointer_test.cpp"
+ #include "text/juce_CharPointer_UTF8_test.cpp"
+ #include "text/juce_CharPointer_UTF16_test.cpp"
+ #include "text/juce_CharPointer_UTF32_test.cpp"
#if JUCE_MAC || JUCE_IOS
#include "native/juce_ObjCHelpers_mac_test.mm"
#endif
diff --git a/modules/juce_core/text/juce_CharPointer_ASCII.h b/modules/juce_core/text/juce_CharPointer_ASCII.h
index 4f8fc0c011..c62f108a43 100644
--- a/modules/juce_core/text/juce_CharPointer_ASCII.h
+++ b/modules/juce_core/text/juce_CharPointer_ASCII.h
@@ -366,7 +366,7 @@ public:
/** Returns true if the given unicode character can be represented in this encoding. */
static bool canRepresent (juce_wchar character) noexcept
{
- return ((unsigned int) character) < (unsigned int) 128;
+ return CharacterFunctions::isAscii (character);
}
/** Returns true if this data contains a valid string in this encoding. */
diff --git a/modules/juce_core/text/juce_CharPointer_UTF16.h b/modules/juce_core/text/juce_CharPointer_UTF16.h
index 1b588c8bdd..7a0f82243d 100644
--- a/modules/juce_core/text/juce_CharPointer_UTF16.h
+++ b/modules/juce_core/text/juce_CharPointer_UTF16.h
@@ -438,35 +438,32 @@ public:
/** Returns true if the given unicode character can be represented in this encoding. */
static bool canRepresent (juce_wchar character) noexcept
{
- auto n = (uint32) character;
- return n < 0x10ffff && (n < 0xd800 || n > 0xdfff);
+ return CharacterFunctions::isNonSurrogateCodePoint (character);
}
/** Returns true if this data contains a valid string in this encoding. */
- static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
+ static bool isValidString (const CharType* codeUnits, int maxBytesToRead)
{
- maxBytesToRead /= (int) sizeof (CharType);
+ const auto maxCodeUnitsToRead = (size_t) maxBytesToRead / sizeof (CharType);
- while (--maxBytesToRead >= 0 && *dataToTest != 0)
+ for (size_t codeUnitIndex = 0; codeUnitIndex < maxCodeUnitsToRead; ++codeUnitIndex)
{
- auto n = (uint32) (uint16) *dataToTest++;
+ const auto c = toCodePoint (codeUnits[codeUnitIndex]);
- if (n >= 0xd800)
- {
- if (n > 0x10ffff)
- return false;
+ if (c == 0)
+ return true;
- if (n <= 0xdfff)
- {
- if (n > 0xdc00)
- return false;
+ if (canRepresent (c))
+ continue;
- auto nextChar = (uint32) (uint16) *dataToTest++;
+ if (! CharacterFunctions::isHighSurrogate (c))
+ return false;
- if (nextChar < 0xdc00 || nextChar > 0xdfff)
- return false;
- }
- }
+ if (++codeUnitIndex >= maxCodeUnitsToRead)
+ return false;
+
+ if (! CharacterFunctions::isLowSurrogate (toCodePoint (codeUnits[codeUnitIndex])))
+ return false;
}
return true;
@@ -527,6 +524,16 @@ private:
return n;
}
+
+ static inline uint32 toUint32 (CharType c) noexcept
+ {
+ return (uint32) (uint16) c;
+ }
+
+ static inline juce_wchar toCodePoint (CharType c) noexcept
+ {
+ return (juce_wchar) toUint32 (c);
+ }
};
} // namespace juce
diff --git a/modules/juce_core/text/juce_CharPointer_UTF16_test.cpp b/modules/juce_core/text/juce_CharPointer_UTF16_test.cpp
new file mode 100644
index 0000000000..defbfd8733
--- /dev/null
+++ b/modules/juce_core/text/juce_CharPointer_UTF16_test.cpp
@@ -0,0 +1,118 @@
+/*
+ ==============================================================================
+
+ This file is part of the JUCE framework.
+ Copyright (c) Raw Material Software Limited
+
+ JUCE is an open source framework subject to commercial or open source
+ licensing.
+
+ By downloading, installing, or using the JUCE framework, or combining the
+ JUCE framework with any other source code, object code, content or any other
+ copyrightable work, you agree to the terms of the JUCE End User Licence
+ Agreement, and all incorporated terms including the JUCE Privacy Policy and
+ the JUCE Website Terms of Service, as applicable, which will bind you. If you
+ do not agree to the terms of these agreements, we will not license the JUCE
+ framework to you, and you must discontinue the installation or download
+ process and cease use of the JUCE framework.
+
+ JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
+ JUCE Privacy Policy: https://juce.com/juce-privacy-policy
+ JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
+
+ Or:
+
+ You may also use this code under the terms of the AGPLv3:
+ https://www.gnu.org/licenses/agpl-3.0.en.html
+
+ THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
+ WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
+
+ ==============================================================================
+*/
+
+namespace juce
+{
+
+class CharPointer_UTF16Test final : public UnitTest
+{
+public:
+ CharPointer_UTF16Test() : UnitTest { "CharPointer_UTF16Test", UnitTestCategories::text } {}
+
+ void runTest() final
+ {
+ const auto toCharType = [] (const std::vector& str)
+ {
+ return reinterpret_cast (str.data());
+ };
+
+ const auto getNumBytes = [] (const auto& str)
+ {
+ return (int) (sizeof (CharPointer_UTF16::CharType) * str.size());
+ };
+
+ beginTest ("String validation - empty string / null-terminator");
+ {
+ const std::vector string { 0x0 };
+ expect (CharPointer_UTF16::isValidString (string.data(), getNumBytes (string)));
+ }
+
+ beginTest ("String validation - ascii");
+ {
+ const std::vector string { 0x54, 0x65, 0x73, 0x74, 0x21, 0x0 }; // Test!
+ expect (CharPointer_UTF16::isValidString (toCharType (string), getNumBytes (string)));
+ }
+
+ beginTest ("String validation - 2-byte code points");
+ {
+ const std::vector string { 0x54, 0x65, 0x73, 0x74, 0x20ac, 0x0 }; // Test€
+ expect (CharPointer_UTF16::isValidString (toCharType (string), getNumBytes (string)));
+ }
+
+ beginTest ("String validation - surrogate pairs");
+ {
+ const std::vector string { 0x54, 0x65, 0x73, 0x74, 0xd83d, 0xde03, 0x0 }; // TestđŸ˜ƒ
+ expect (CharPointer_UTF16::isValidString (toCharType (string), getNumBytes (string)));
+ }
+
+ beginTest ("String validation - high-surrogate without a low-surrogate");
+ {
+ const std::vector string { 0x54, 0x65, 0x73, 0x74, 0xd83d, 0x0 };
+ expect (! CharPointer_UTF16::isValidString (toCharType (string), getNumBytes (string)));
+ }
+
+ beginTest ("String validation - low-surrogate without a high-surrogate");
+ {
+ const std::vector string { 0x54, 0x65, 0x73, 0x74, 0xde03, 0x0 };
+ expect (! CharPointer_UTF16::isValidString (toCharType (string), getNumBytes (string)));
+ }
+
+ beginTest ("String validation - characters after a null terminator are ignored");
+ {
+ const std::vector string { 0x54, 0x65, 0x73, 0x74, 0x0, 0xde03 };
+ expect (CharPointer_UTF16::isValidString (toCharType (string), getNumBytes (string)));
+ }
+
+ beginTest ("String validation - characters exceeding max bytes are ignored");
+ {
+ const std::vector string { 0x54, 0x65, 0x73, 0x74, 0xde03 };
+ expect (CharPointer_UTF16::isValidString (toCharType (string), 8));
+ }
+
+ beginTest ("String validation - all unicode characters");
+ {
+ for (uint32_t c = 0; c < 0x110000; ++c)
+ {
+ std::array string = {};
+ CharPointer_UTF16 utf16 { string.data() };
+ utf16.write ((juce_wchar) c);
+ expect (CharPointer_UTF16::isValidString (string.data(), 4) == CharPointer_UTF32::canRepresent ((juce_wchar) c));
+ }
+ }
+ }
+};
+
+static CharPointer_UTF16Test charPointer_UTF16Test;
+
+} // namespace juce
diff --git a/modules/juce_core/text/juce_CharPointer_UTF32.h b/modules/juce_core/text/juce_CharPointer_UTF32.h
index bfe1ad43b6..2eabf0b12c 100644
--- a/modules/juce_core/text/juce_CharPointer_UTF32.h
+++ b/modules/juce_core/text/juce_CharPointer_UTF32.h
@@ -357,17 +357,24 @@ public:
/** Returns true if the given unicode character can be represented in this encoding. */
static bool canRepresent (juce_wchar character) noexcept
{
- return ((uint32) character) < (uint32) 0x10ffff;
+ return CharacterFunctions::isNonSurrogateCodePoint (character);
}
/** Returns true if this data contains a valid string in this encoding. */
- static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
+ static bool isValidString (const CharType* codeUnits, int maxBytesToRead)
{
- maxBytesToRead /= (int) sizeof (CharType);
+ const auto maxCodeUnitsToRead = (size_t) maxBytesToRead / sizeof (CharType);
- while (--maxBytesToRead >= 0 && *dataToTest != 0)
- if (! canRepresent (*dataToTest++))
+ for (size_t codeUnitIndex = 0; codeUnitIndex < maxCodeUnitsToRead; ++codeUnitIndex)
+ {
+ const auto c = codeUnits[codeUnitIndex];
+
+ if (c == 0)
+ return true;
+
+ if (! canRepresent (c))
return false;
+ }
return true;
}
diff --git a/modules/juce_core/text/juce_CharPointer_UTF32_test.cpp b/modules/juce_core/text/juce_CharPointer_UTF32_test.cpp
new file mode 100644
index 0000000000..b46788c459
--- /dev/null
+++ b/modules/juce_core/text/juce_CharPointer_UTF32_test.cpp
@@ -0,0 +1,108 @@
+/*
+ ==============================================================================
+
+ This file is part of the JUCE framework.
+ Copyright (c) Raw Material Software Limited
+
+ JUCE is an open source framework subject to commercial or open source
+ licensing.
+
+ By downloading, installing, or using the JUCE framework, or combining the
+ JUCE framework with any other source code, object code, content or any other
+ copyrightable work, you agree to the terms of the JUCE End User Licence
+ Agreement, and all incorporated terms including the JUCE Privacy Policy and
+ the JUCE Website Terms of Service, as applicable, which will bind you. If you
+ do not agree to the terms of these agreements, we will not license the JUCE
+ framework to you, and you must discontinue the installation or download
+ process and cease use of the JUCE framework.
+
+ JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
+ JUCE Privacy Policy: https://juce.com/juce-privacy-policy
+ JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
+
+ Or:
+
+ You may also use this code under the terms of the AGPLv3:
+ https://www.gnu.org/licenses/agpl-3.0.en.html
+
+ THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
+ WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
+
+ ==============================================================================
+*/
+
+namespace juce
+{
+
+class CharPointer_UTF32Test final : public UnitTest
+{
+public:
+ CharPointer_UTF32Test() : UnitTest { "CharPointer_UTF32", UnitTestCategories::text } {}
+
+ void runTest() final
+ {
+ const auto toCharType = [] (const std::vector& str)
+ {
+ return reinterpret_cast (str.data());
+ };
+
+ const auto getNumBytes = [] (const auto& str)
+ {
+ return (int) (sizeof (CharPointer_UTF32::CharType) * str.size());
+ };
+
+ beginTest ("String validation - empty string / null-terminator");
+ {
+ const std::vector string { 0x0 };
+ expect (CharPointer_UTF32::isValidString (string.data(), getNumBytes (string)));
+ }
+
+ beginTest ("String validation - ascii");
+ {
+ const std::vector string { 0x54, 0x65, 0x73, 0x74, 0x21, 0x0 }; // Test!
+ expect (CharPointer_UTF32::isValidString (toCharType (string), getNumBytes (string)));
+ }
+
+ beginTest ("String validation - 2-byte code points");
+ {
+ const std::vector string { 0x54, 0x65, 0x73, 0x74, 0x20ac, 0x0 }; // Test€
+ expect (CharPointer_UTF32::isValidString (toCharType (string), getNumBytes (string)));
+ }
+
+ beginTest ("String validation - maximum code point");
+ {
+ const std::vector string1 { 0x54, 0x65, 0x73, 0x74, 0x10ffff, 0x0 };
+ expect (CharPointer_UTF32::isValidString (toCharType (string1), getNumBytes (string1)));
+
+ const std::vector string2 { 0x54, 0x65, 0x73, 0x74, 0x110000, 0x0 };
+ expect (! CharPointer_UTF32::isValidString (toCharType (string2), getNumBytes (string2)));
+ }
+
+ beginTest ("String validation - characters after a null terminator are ignored");
+ {
+ const std::vector string { 0x54, 0x65, 0x73, 0x74, 0x0, 0x110000 };
+ expect (CharPointer_UTF32::isValidString (toCharType (string), getNumBytes (string)));
+ }
+
+ beginTest ("String validation - characters exceeding max bytes are ignored");
+ {
+ const std::vector string { 0x54, 0x65, 0x73, 0x74, 0x110000 };
+ expect (CharPointer_UTF32::isValidString (toCharType (string), 8));
+ }
+
+ beginTest ("String validation - surrogate code points are invalid");
+ {
+ const std::vector highSurrogate { 0xd800 };
+ expect (! CharPointer_UTF32::isValidString (toCharType (highSurrogate), getNumBytes (highSurrogate)));
+
+ const std::vector lowSurrogate { 0xdfff };
+ expect (! CharPointer_UTF32::isValidString (toCharType (lowSurrogate), getNumBytes (lowSurrogate)));
+ }
+ }
+};
+
+
+static CharPointer_UTF32Test charPointer_UTF32Test;
+
+} // namespace juce
diff --git a/modules/juce_core/text/juce_CharPointer_UTF8.h b/modules/juce_core/text/juce_CharPointer_UTF8.h
index ca06656805..a13ff2cb7b 100644
--- a/modules/juce_core/text/juce_CharPointer_UTF8.h
+++ b/modules/juce_core/text/juce_CharPointer_UTF8.h
@@ -497,45 +497,80 @@ public:
/** Returns true if the given unicode character can be represented in this encoding. */
static bool canRepresent (juce_wchar character) noexcept
{
- return ((uint32) character) < (uint32) 0x10ffff;
+ return CharacterFunctions::isNonSurrogateCodePoint (character);
}
/** Returns true if this data contains a valid string in this encoding. */
- static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
+ static bool isValidString (const CharType* codeUnits, int maxBytesToRead)
{
- while (--maxBytesToRead >= 0 && *dataToTest != 0)
+ const auto maxCodeUnitsToRead = (size_t) maxBytesToRead / sizeof (CharType);
+
+ for (size_t codeUnitIndex = 0; codeUnitIndex < maxCodeUnitsToRead; ++codeUnitIndex)
{
- auto byte = (signed char) *dataToTest++;
+ const auto firstByte = (uint8_t) codeUnits[codeUnitIndex];
- if (byte < 0)
+ if (firstByte == 0)
+ return true;
+
+ if (CharacterFunctions::isAscii ((juce_wchar) firstByte))
+ continue;
+
+ auto numExtraBytes = [&]
{
- int bit = 0x40;
- int numExtraValues = 0;
+ if (firstByte < 0xc0)
+ return 0;
- while ((byte & bit) != 0)
- {
- if (bit < 8)
- return false;
+ if (firstByte < 0xe0)
+ return 1;
- ++numExtraValues;
- bit >>= 1;
+ if (firstByte < 0xf0)
+ return 2;
- if (bit == 8 && (numExtraValues > maxBytesToRead
- || *CharPointer_UTF8 (dataToTest - 1) > 0x10ffff))
- return false;
- }
+ if (firstByte <= 0xf4)
+ return 3;
- if (numExtraValues == 0)
+ return 0;
+ }();
+
+ if (numExtraBytes == 0)
+ return false;
+
+ auto bytes = (uint32_t) firstByte;
+
+ while (numExtraBytes--)
+ {
+ if (++codeUnitIndex >= maxCodeUnitsToRead)
return false;
- maxBytesToRead -= numExtraValues;
- if (maxBytesToRead < 0)
- return false;
-
- while (--numExtraValues >= 0)
- if ((*dataToTest++ & 0xc0) != 0x80)
- return false;
+ bytes <<= 8;
+ bytes |= (uint32_t) (uint8_t) codeUnits[codeUnitIndex];
}
+
+ if (constexpr uint32_t firstTwoByteCodePoint = 0xc280; bytes < firstTwoByteCodePoint)
+ return false;
+
+ if (constexpr uint32_t lastTwoByteCodePoint = 0xdfbf; bytes <= lastTwoByteCodePoint)
+ continue;
+
+ if (constexpr uint32_t firstThreeByteCodePoint = 0xe0a080; bytes < firstThreeByteCodePoint)
+ return false;
+
+ if (constexpr uint32_t firstSurrogateCodePoint = 0xeda080; bytes < firstSurrogateCodePoint)
+ continue;
+
+ if (constexpr uint32_t lastSurrogateCodePoint = 0xedbfbf; bytes <= lastSurrogateCodePoint)
+ return false;
+
+ if (constexpr uint32_t lastThreeByteCodePoint = 0xefbfbf; bytes <= lastThreeByteCodePoint)
+ continue;
+
+ if (constexpr uint32_t firstFourByteCodePoint = 0xf0908080; bytes < firstFourByteCodePoint)
+ return false;
+
+ if (constexpr uint32_t lastFourByteCodePoint = 0xf48fbfbf; bytes <= lastFourByteCodePoint)
+ continue;
+
+ return false;
}
return true;
diff --git a/modules/juce_core/text/juce_CharPointer_UTF8_test.cpp b/modules/juce_core/text/juce_CharPointer_UTF8_test.cpp
new file mode 100644
index 0000000000..c6fbe592db
--- /dev/null
+++ b/modules/juce_core/text/juce_CharPointer_UTF8_test.cpp
@@ -0,0 +1,91 @@
+/*
+ ==============================================================================
+
+ This file is part of the JUCE framework.
+ Copyright (c) Raw Material Software Limited
+
+ JUCE is an open source framework subject to commercial or open source
+ licensing.
+
+ By downloading, installing, or using the JUCE framework, or combining the
+ JUCE framework with any other source code, object code, content or any other
+ copyrightable work, you agree to the terms of the JUCE End User Licence
+ Agreement, and all incorporated terms including the JUCE Privacy Policy and
+ the JUCE Website Terms of Service, as applicable, which will bind you. If you
+ do not agree to the terms of these agreements, we will not license the JUCE
+ framework to you, and you must discontinue the installation or download
+ process and cease use of the JUCE framework.
+
+ JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
+ JUCE Privacy Policy: https://juce.com/juce-privacy-policy
+ JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
+
+ Or:
+
+ You may also use this code under the terms of the AGPLv3:
+ https://www.gnu.org/licenses/agpl-3.0.en.html
+
+ THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
+ WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
+
+ ==============================================================================
+*/
+
+namespace juce
+{
+
+class CharPointer_UTF8Test final : public UnitTest
+{
+public:
+ CharPointer_UTF8Test() : UnitTest { "CharPointer_UTF8", UnitTestCategories::text } {}
+
+ void runTest() final
+ {
+ beginTest ("String validation - empty string / null-terminator");
+ {
+ const std::vector string { 0x0 };
+ expect (CharPointer_UTF8::isValidString (string.data(), (int) string.size()));
+ }
+
+ beginTest ("String validation - ascii");
+ {
+ const std::vector string { 0x54, 0x65, 0x73, 0x74, 0x21, 0x0 }; // Test!
+ expect (CharPointer_UTF8::isValidString (string.data(), (int) string.size()));
+ }
+
+ beginTest ("String validation - continuation characters are invalid when not proceeded by the correct bytes");
+ {
+ const std::vector string { -1 };
+ expect (! CharPointer_UTF8::isValidString (string.data(), (int) string.size()));
+ }
+
+ beginTest ("String validation - characters after a null terminator are ignored");
+ {
+ const std::vector string { 0x54, 0x65, 0x73, 0x74, 0x0, -1 };
+ expect (CharPointer_UTF8::isValidString (string.data(), (int) string.size()));
+ }
+
+ beginTest ("String validation - characters exceeding max bytes are ignored");
+ {
+ const std::vector string { 0x54, 0x65, 0x73, 0x74, -1 };
+ expect (CharPointer_UTF8::isValidString (string.data(), 4));
+ }
+
+ beginTest ("String validation - all unicode characters");
+ {
+ for (uint32_t c = 0; c < 0x110000; ++c)
+ {
+ std::array string = {};
+ CharPointer_UTF8 utf8 { string.data() };
+ utf8.write ((juce_wchar) c);
+ expect (CharPointer_UTF8::isValidString (string.data(), (int) string.size()) == CharPointer_UTF32::canRepresent ((juce_wchar) c));
+ }
+ }
+ }
+};
+
+
+static CharPointer_UTF8Test charPointer_UTF8Test;
+
+} // namespace juce
diff --git a/modules/juce_core/text/juce_CharacterFunctions.h b/modules/juce_core/text/juce_CharacterFunctions.h
index aadb6a62e5..fde96a0563 100644
--- a/modules/juce_core/text/juce_CharacterFunctions.h
+++ b/modules/juce_core/text/juce_CharacterFunctions.h
@@ -150,6 +150,70 @@ public:
/** Converts a byte of Windows 1252 codepage to unicode. */
static juce_wchar getUnicodeCharFromWindows1252Codepage (uint8 windows1252Char) noexcept;
+ /** Returns true if a unicode code point is part of the basic multilingual plane.
+
+ @see isAscii, isNonSurrogateCodePoint
+ */
+ static constexpr bool isPartOfBasicMultilingualPlane (juce_wchar character) noexcept
+ {
+ return (uint32) character < 0x10000;
+ }
+
+ /** Returns true if a unicode code point is in the range os ASCII characters.
+
+ @see isAsciiControlCharacter, isPartOfBasicMultilingualPlane
+ */
+ static constexpr bool isAscii (juce_wchar character) noexcept
+ {
+ return (uint32) character < 128;
+ }
+
+ /** Returns true if a unicode code point is in the range of ASCII control characters.
+
+ @see isAscii
+ */
+ static constexpr bool isAsciiControlCharacter (juce_wchar character) noexcept
+ {
+ return (uint32) character < 32;
+ }
+
+ /** Returns true if a unicode code point is in the range of UTF-16 surrogate code units.
+
+ @see isHighSurrogate, isLowSurrogate
+ */
+ static constexpr bool isSurrogate (juce_wchar character) noexcept
+ {
+ const auto n = (uint32) character;
+ return 0xd800 <= n && n <= 0xdfff;
+ }
+
+ /** Returns true if a unicode code point is in the range of UTF-16 high surrogate code units.
+
+ @see isLowSurrogate, isSurrogate
+ */
+ static constexpr bool isHighSurrogate (juce_wchar character) noexcept
+ {
+ const auto n = (uint32) character;
+ return 0xd800 <= n && n <= 0xdbff;
+ }
+
+ /** Returns true if a unicode code point is in the range of UTF-16 low surrogate code units.
+
+ @see isHighSurrogate, isSurrogate
+ */
+ static constexpr bool isLowSurrogate (juce_wchar character) noexcept
+ {
+ const auto n = (uint32) character;
+ return 0xdc00 <= n && n <= 0xdfff;
+ }
+
+ /** Returns true if a unicode code point is in the range of valid unicode code points. */
+ static constexpr bool isNonSurrogateCodePoint (juce_wchar character) noexcept
+ {
+ const auto n = (uint32) character;
+ return n <= 0x10ffff && ! isSurrogate (character);
+ }
+
//==============================================================================
/** Parses a character string to read a floating-point number.
Note that this will advance the pointer that is passed in, leaving it at