| @@ -353,6 +353,7 @@ OBJECTS := \ | |||
| $(OBJDIR)/juce_android_Windowing_2a620a72.o \ | |||
| $(OBJDIR)/juce_CharacterFunctions_b1a5ac62.o \ | |||
| $(OBJDIR)/juce_Identifier_e99ee619.o \ | |||
| $(OBJDIR)/juce_JSON_bbf64af8.o \ | |||
| $(OBJDIR)/juce_LocalisedStrings_3ddfa55e.o \ | |||
| $(OBJDIR)/juce_String_80587b01.o \ | |||
| $(OBJDIR)/juce_StringArray_4aaa67a2.o \ | |||
| @@ -1956,6 +1957,11 @@ $(OBJDIR)/juce_Identifier_e99ee619.o: ../../src/text/juce_Identifier.cpp | |||
| @echo "Compiling juce_Identifier.cpp" | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| $(OBJDIR)/juce_JSON_bbf64af8.o: ../../src/text/juce_JSON.cpp | |||
| -@mkdir -p $(OBJDIR) | |||
| @echo "Compiling juce_JSON.cpp" | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| $(OBJDIR)/juce_LocalisedStrings_3ddfa55e.o: ../../src/text/juce_LocalisedStrings.cpp | |||
| -@mkdir -p $(OBJDIR) | |||
| @echo "Compiling juce_LocalisedStrings.cpp" | |||
| @@ -348,6 +348,7 @@ | |||
| CE9A64287FCEF00DD2BA6AEE = { isa = PBXBuildFile; fileRef = FCD02A40985242A8A6648311; }; | |||
| 2AC6F3BFAAA21E21076A9F8D = { isa = PBXBuildFile; fileRef = 76E2084D2148068F9138A816; }; | |||
| B8DD4DB0BD1A6B38BBF92413 = { isa = PBXBuildFile; fileRef = 8273A206FB309671284959DD; }; | |||
| 1C0B1362E81C8B073BF0DCEC = { isa = PBXBuildFile; fileRef = 644FD6155385BC3AA270FB5D; }; | |||
| 63BEC07A51CB8E516B38ECD4 = { isa = PBXBuildFile; fileRef = 4A97C8D2FF6454DDD3AF4BE5; }; | |||
| C8F81E843F446868FAD88197 = { isa = PBXBuildFile; fileRef = B507B4A8712A54D7A8C03223; }; | |||
| 50D91A2EC0ABF894E612D936 = { isa = PBXBuildFile; fileRef = 23252E4C97AEFAE0C5EEAA77; }; | |||
| @@ -1052,12 +1053,14 @@ | |||
| FCD02A40985242A8A6648311 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_android_Windowing.cpp; path = ../../src/native/android/juce_android_Windowing.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 76E2084D2148068F9138A816 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_CharacterFunctions.cpp; path = ../../src/text/juce_CharacterFunctions.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 33F16EE4F38C9B76E7FAEF78 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharacterFunctions.h; path = ../../src/text/juce_CharacterFunctions.h; sourceTree = SOURCE_ROOT; }; | |||
| 4007410FACA2F865FD8EF769 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharPointer_UTF8.h; path = ../../src/text/juce_CharPointer_UTF8.h; sourceTree = SOURCE_ROOT; }; | |||
| 72F5ED2E8B945988C37EA9CF = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharPointer_ASCII.h; path = ../../src/text/juce_CharPointer_ASCII.h; sourceTree = SOURCE_ROOT; }; | |||
| 663746215E9BA6C761172B85 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharPointer_UTF16.h; path = ../../src/text/juce_CharPointer_UTF16.h; sourceTree = SOURCE_ROOT; }; | |||
| C3FD9D93626F80A45F9B6DDE = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharPointer_UTF32.h; path = ../../src/text/juce_CharPointer_UTF32.h; sourceTree = SOURCE_ROOT; }; | |||
| 72F5ED2E8B945988C37EA9CF = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharPointer_ASCII.h; path = ../../src/text/juce_CharPointer_ASCII.h; sourceTree = SOURCE_ROOT; }; | |||
| 4007410FACA2F865FD8EF769 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharPointer_UTF8.h; path = ../../src/text/juce_CharPointer_UTF8.h; sourceTree = SOURCE_ROOT; }; | |||
| 8273A206FB309671284959DD = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_Identifier.cpp; path = ../../src/text/juce_Identifier.cpp; sourceTree = SOURCE_ROOT; }; | |||
| BF888BC540B64D5C61E46A34 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Identifier.h; path = ../../src/text/juce_Identifier.h; sourceTree = SOURCE_ROOT; }; | |||
| 644FD6155385BC3AA270FB5D = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_JSON.cpp; path = ../../src/text/juce_JSON.cpp; sourceTree = SOURCE_ROOT; }; | |||
| CB092FB152F43900272F8E43 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_JSON.h; path = ../../src/text/juce_JSON.h; sourceTree = SOURCE_ROOT; }; | |||
| 4A97C8D2FF6454DDD3AF4BE5 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_LocalisedStrings.cpp; path = ../../src/text/juce_LocalisedStrings.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 2AA21CDC91EA122266EBD780 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_LocalisedStrings.h; path = ../../src/text/juce_LocalisedStrings.h; sourceTree = SOURCE_ROOT; }; | |||
| 35DA3E75DDB03BB35794289B = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_NewLine.h; path = ../../src/text/juce_NewLine.h; sourceTree = SOURCE_ROOT; }; | |||
| @@ -1894,12 +1897,14 @@ | |||
| C6B52BCD0CB1B809D6DE555A = { isa = PBXGroup; children = ( | |||
| 76E2084D2148068F9138A816, | |||
| 33F16EE4F38C9B76E7FAEF78, | |||
| 4007410FACA2F865FD8EF769, | |||
| 72F5ED2E8B945988C37EA9CF, | |||
| 663746215E9BA6C761172B85, | |||
| C3FD9D93626F80A45F9B6DDE, | |||
| 72F5ED2E8B945988C37EA9CF, | |||
| 4007410FACA2F865FD8EF769, | |||
| 8273A206FB309671284959DD, | |||
| BF888BC540B64D5C61E46A34, | |||
| 644FD6155385BC3AA270FB5D, | |||
| CB092FB152F43900272F8E43, | |||
| 4A97C8D2FF6454DDD3AF4BE5, | |||
| 2AA21CDC91EA122266EBD780, | |||
| 35DA3E75DDB03BB35794289B, | |||
| @@ -2391,6 +2396,7 @@ | |||
| CE9A64287FCEF00DD2BA6AEE, | |||
| 2AC6F3BFAAA21E21076A9F8D, | |||
| B8DD4DB0BD1A6B38BBF92413, | |||
| 1C0B1362E81C8B073BF0DCEC, | |||
| 63BEC07A51CB8E516B38ECD4, | |||
| C8F81E843F446868FAD88197, | |||
| 50D91A2EC0ABF894E612D936, | |||
| @@ -962,12 +962,14 @@ | |||
| <Filter Name="text"> | |||
| <File RelativePath="..\..\src\text\juce_CharacterFunctions.cpp"/> | |||
| <File RelativePath="..\..\src\text\juce_CharacterFunctions.h"/> | |||
| <File RelativePath="..\..\src\text\juce_CharPointer_UTF8.h"/> | |||
| <File RelativePath="..\..\src\text\juce_CharPointer_ASCII.h"/> | |||
| <File RelativePath="..\..\src\text\juce_CharPointer_UTF16.h"/> | |||
| <File RelativePath="..\..\src\text\juce_CharPointer_UTF32.h"/> | |||
| <File RelativePath="..\..\src\text\juce_CharPointer_ASCII.h"/> | |||
| <File RelativePath="..\..\src\text\juce_CharPointer_UTF8.h"/> | |||
| <File RelativePath="..\..\src\text\juce_Identifier.cpp"/> | |||
| <File RelativePath="..\..\src\text\juce_Identifier.h"/> | |||
| <File RelativePath="..\..\src\text\juce_JSON.cpp"/> | |||
| <File RelativePath="..\..\src\text\juce_JSON.h"/> | |||
| <File RelativePath="..\..\src\text\juce_LocalisedStrings.cpp"/> | |||
| <File RelativePath="..\..\src\text\juce_LocalisedStrings.h"/> | |||
| <File RelativePath="..\..\src\text\juce_NewLine.h"/> | |||
| @@ -962,12 +962,14 @@ | |||
| <Filter Name="text"> | |||
| <File RelativePath="..\..\src\text\juce_CharacterFunctions.cpp"/> | |||
| <File RelativePath="..\..\src\text\juce_CharacterFunctions.h"/> | |||
| <File RelativePath="..\..\src\text\juce_CharPointer_UTF8.h"/> | |||
| <File RelativePath="..\..\src\text\juce_CharPointer_ASCII.h"/> | |||
| <File RelativePath="..\..\src\text\juce_CharPointer_UTF16.h"/> | |||
| <File RelativePath="..\..\src\text\juce_CharPointer_UTF32.h"/> | |||
| <File RelativePath="..\..\src\text\juce_CharPointer_ASCII.h"/> | |||
| <File RelativePath="..\..\src\text\juce_CharPointer_UTF8.h"/> | |||
| <File RelativePath="..\..\src\text\juce_Identifier.cpp"/> | |||
| <File RelativePath="..\..\src\text\juce_Identifier.h"/> | |||
| <File RelativePath="..\..\src\text\juce_JSON.cpp"/> | |||
| <File RelativePath="..\..\src\text\juce_JSON.h"/> | |||
| <File RelativePath="..\..\src\text\juce_LocalisedStrings.cpp"/> | |||
| <File RelativePath="..\..\src\text\juce_LocalisedStrings.h"/> | |||
| <File RelativePath="..\..\src\text\juce_NewLine.h"/> | |||
| @@ -964,12 +964,14 @@ | |||
| <Filter Name="text"> | |||
| <File RelativePath="..\..\src\text\juce_CharacterFunctions.cpp"/> | |||
| <File RelativePath="..\..\src\text\juce_CharacterFunctions.h"/> | |||
| <File RelativePath="..\..\src\text\juce_CharPointer_UTF8.h"/> | |||
| <File RelativePath="..\..\src\text\juce_CharPointer_ASCII.h"/> | |||
| <File RelativePath="..\..\src\text\juce_CharPointer_UTF16.h"/> | |||
| <File RelativePath="..\..\src\text\juce_CharPointer_UTF32.h"/> | |||
| <File RelativePath="..\..\src\text\juce_CharPointer_ASCII.h"/> | |||
| <File RelativePath="..\..\src\text\juce_CharPointer_UTF8.h"/> | |||
| <File RelativePath="..\..\src\text\juce_Identifier.cpp"/> | |||
| <File RelativePath="..\..\src\text\juce_Identifier.h"/> | |||
| <File RelativePath="..\..\src\text\juce_JSON.cpp"/> | |||
| <File RelativePath="..\..\src\text\juce_JSON.h"/> | |||
| <File RelativePath="..\..\src\text\juce_LocalisedStrings.cpp"/> | |||
| <File RelativePath="..\..\src\text\juce_LocalisedStrings.h"/> | |||
| <File RelativePath="..\..\src\text\juce_NewLine.h"/> | |||
| @@ -436,6 +436,7 @@ | |||
| <ClCompile Include="..\..\src\native\android\juce_android_Windowing.cpp"/> | |||
| <ClCompile Include="..\..\src\text\juce_CharacterFunctions.cpp"/> | |||
| <ClCompile Include="..\..\src\text\juce_Identifier.cpp"/> | |||
| <ClCompile Include="..\..\src\text\juce_JSON.cpp"/> | |||
| <ClCompile Include="..\..\src\text\juce_LocalisedStrings.cpp"/> | |||
| <ClCompile Include="..\..\src\text\juce_String.cpp"/> | |||
| <ClCompile Include="..\..\src\text\juce_StringArray.cpp"/> | |||
| @@ -790,11 +791,12 @@ | |||
| <ClInclude Include="..\..\src\native\windows\juce_win32_NativeIncludes.h"/> | |||
| <ClInclude Include="..\..\src\native\android\juce_android_NativeIncludes.h"/> | |||
| <ClInclude Include="..\..\src\text\juce_CharacterFunctions.h"/> | |||
| <ClInclude Include="..\..\src\text\juce_CharPointer_UTF8.h"/> | |||
| <ClInclude Include="..\..\src\text\juce_CharPointer_ASCII.h"/> | |||
| <ClInclude Include="..\..\src\text\juce_CharPointer_UTF16.h"/> | |||
| <ClInclude Include="..\..\src\text\juce_CharPointer_UTF32.h"/> | |||
| <ClInclude Include="..\..\src\text\juce_CharPointer_ASCII.h"/> | |||
| <ClInclude Include="..\..\src\text\juce_CharPointer_UTF8.h"/> | |||
| <ClInclude Include="..\..\src\text\juce_Identifier.h"/> | |||
| <ClInclude Include="..\..\src\text\juce_JSON.h"/> | |||
| <ClInclude Include="..\..\src\text\juce_LocalisedStrings.h"/> | |||
| <ClInclude Include="..\..\src\text\juce_NewLine.h"/> | |||
| <ClInclude Include="..\..\src\text\juce_String.h"/> | |||
| @@ -1243,6 +1243,9 @@ | |||
| <ClCompile Include="..\..\src\text\juce_Identifier.cpp"> | |||
| <Filter>Juce\Source\text</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="..\..\src\text\juce_JSON.cpp"> | |||
| <Filter>Juce\Source\text</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="..\..\src\text\juce_LocalisedStrings.cpp"> | |||
| <Filter>Juce\Source\text</Filter> | |||
| </ClCompile> | |||
| @@ -2301,7 +2304,7 @@ | |||
| <ClInclude Include="..\..\src\text\juce_CharacterFunctions.h"> | |||
| <Filter>Juce\Source\text</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="..\..\src\text\juce_CharPointer_UTF8.h"> | |||
| <ClInclude Include="..\..\src\text\juce_CharPointer_ASCII.h"> | |||
| <Filter>Juce\Source\text</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="..\..\src\text\juce_CharPointer_UTF16.h"> | |||
| @@ -2310,12 +2313,15 @@ | |||
| <ClInclude Include="..\..\src\text\juce_CharPointer_UTF32.h"> | |||
| <Filter>Juce\Source\text</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="..\..\src\text\juce_CharPointer_ASCII.h"> | |||
| <ClInclude Include="..\..\src\text\juce_CharPointer_UTF8.h"> | |||
| <Filter>Juce\Source\text</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="..\..\src\text\juce_Identifier.h"> | |||
| <Filter>Juce\Source\text</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="..\..\src\text\juce_JSON.h"> | |||
| <Filter>Juce\Source\text</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="..\..\src\text\juce_LocalisedStrings.h"> | |||
| <Filter>Juce\Source\text</Filter> | |||
| </ClInclude> | |||
| @@ -348,6 +348,7 @@ | |||
| CE9A64287FCEF00DD2BA6AEE = { isa = PBXBuildFile; fileRef = FCD02A40985242A8A6648311; }; | |||
| 2AC6F3BFAAA21E21076A9F8D = { isa = PBXBuildFile; fileRef = 76E2084D2148068F9138A816; }; | |||
| B8DD4DB0BD1A6B38BBF92413 = { isa = PBXBuildFile; fileRef = 8273A206FB309671284959DD; }; | |||
| 1C0B1362E81C8B073BF0DCEC = { isa = PBXBuildFile; fileRef = 644FD6155385BC3AA270FB5D; }; | |||
| 63BEC07A51CB8E516B38ECD4 = { isa = PBXBuildFile; fileRef = 4A97C8D2FF6454DDD3AF4BE5; }; | |||
| C8F81E843F446868FAD88197 = { isa = PBXBuildFile; fileRef = B507B4A8712A54D7A8C03223; }; | |||
| 50D91A2EC0ABF894E612D936 = { isa = PBXBuildFile; fileRef = 23252E4C97AEFAE0C5EEAA77; }; | |||
| @@ -1052,12 +1053,14 @@ | |||
| FCD02A40985242A8A6648311 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_android_Windowing.cpp; path = ../../src/native/android/juce_android_Windowing.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 76E2084D2148068F9138A816 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_CharacterFunctions.cpp; path = ../../src/text/juce_CharacterFunctions.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 33F16EE4F38C9B76E7FAEF78 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharacterFunctions.h; path = ../../src/text/juce_CharacterFunctions.h; sourceTree = SOURCE_ROOT; }; | |||
| 4007410FACA2F865FD8EF769 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharPointer_UTF8.h; path = ../../src/text/juce_CharPointer_UTF8.h; sourceTree = SOURCE_ROOT; }; | |||
| 72F5ED2E8B945988C37EA9CF = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharPointer_ASCII.h; path = ../../src/text/juce_CharPointer_ASCII.h; sourceTree = SOURCE_ROOT; }; | |||
| 663746215E9BA6C761172B85 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharPointer_UTF16.h; path = ../../src/text/juce_CharPointer_UTF16.h; sourceTree = SOURCE_ROOT; }; | |||
| C3FD9D93626F80A45F9B6DDE = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharPointer_UTF32.h; path = ../../src/text/juce_CharPointer_UTF32.h; sourceTree = SOURCE_ROOT; }; | |||
| 72F5ED2E8B945988C37EA9CF = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharPointer_ASCII.h; path = ../../src/text/juce_CharPointer_ASCII.h; sourceTree = SOURCE_ROOT; }; | |||
| 4007410FACA2F865FD8EF769 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharPointer_UTF8.h; path = ../../src/text/juce_CharPointer_UTF8.h; sourceTree = SOURCE_ROOT; }; | |||
| 8273A206FB309671284959DD = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_Identifier.cpp; path = ../../src/text/juce_Identifier.cpp; sourceTree = SOURCE_ROOT; }; | |||
| BF888BC540B64D5C61E46A34 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Identifier.h; path = ../../src/text/juce_Identifier.h; sourceTree = SOURCE_ROOT; }; | |||
| 644FD6155385BC3AA270FB5D = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_JSON.cpp; path = ../../src/text/juce_JSON.cpp; sourceTree = SOURCE_ROOT; }; | |||
| CB092FB152F43900272F8E43 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_JSON.h; path = ../../src/text/juce_JSON.h; sourceTree = SOURCE_ROOT; }; | |||
| 4A97C8D2FF6454DDD3AF4BE5 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_LocalisedStrings.cpp; path = ../../src/text/juce_LocalisedStrings.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 2AA21CDC91EA122266EBD780 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_LocalisedStrings.h; path = ../../src/text/juce_LocalisedStrings.h; sourceTree = SOURCE_ROOT; }; | |||
| 35DA3E75DDB03BB35794289B = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_NewLine.h; path = ../../src/text/juce_NewLine.h; sourceTree = SOURCE_ROOT; }; | |||
| @@ -1894,12 +1897,14 @@ | |||
| C6B52BCD0CB1B809D6DE555A = { isa = PBXGroup; children = ( | |||
| 76E2084D2148068F9138A816, | |||
| 33F16EE4F38C9B76E7FAEF78, | |||
| 4007410FACA2F865FD8EF769, | |||
| 72F5ED2E8B945988C37EA9CF, | |||
| 663746215E9BA6C761172B85, | |||
| C3FD9D93626F80A45F9B6DDE, | |||
| 72F5ED2E8B945988C37EA9CF, | |||
| 4007410FACA2F865FD8EF769, | |||
| 8273A206FB309671284959DD, | |||
| BF888BC540B64D5C61E46A34, | |||
| 644FD6155385BC3AA270FB5D, | |||
| CB092FB152F43900272F8E43, | |||
| 4A97C8D2FF6454DDD3AF4BE5, | |||
| 2AA21CDC91EA122266EBD780, | |||
| 35DA3E75DDB03BB35794289B, | |||
| @@ -2395,6 +2400,7 @@ | |||
| CE9A64287FCEF00DD2BA6AEE, | |||
| 2AC6F3BFAAA21E21076A9F8D, | |||
| B8DD4DB0BD1A6B38BBF92413, | |||
| 1C0B1362E81C8B073BF0DCEC, | |||
| 63BEC07A51CB8E516B38ECD4, | |||
| C8F81E843F446868FAD88197, | |||
| 50D91A2EC0ABF894E612D936, | |||
| @@ -1497,18 +1497,20 @@ | |||
| resource="0" file="src/text/juce_CharacterFunctions.cpp"/> | |||
| <FILE id="McKZNzGvH" name="juce_CharacterFunctions.h" compile="0" resource="0" | |||
| file="src/text/juce_CharacterFunctions.h"/> | |||
| <FILE id="vCX7K0" name="juce_CharPointer_UTF8.h" compile="0" resource="0" | |||
| file="src/text/juce_CharPointer_UTF8.h"/> | |||
| <FILE id="rdfOEc" name="juce_CharPointer_ASCII.h" compile="0" resource="0" | |||
| file="src/text/juce_CharPointer_ASCII.h"/> | |||
| <FILE id="KKhKRD" name="juce_CharPointer_UTF16.h" compile="0" resource="0" | |||
| file="src/text/juce_CharPointer_UTF16.h"/> | |||
| <FILE id="rE1hlF" name="juce_CharPointer_UTF32.h" compile="0" resource="0" | |||
| file="src/text/juce_CharPointer_UTF32.h"/> | |||
| <FILE id="rdfOEc" name="juce_CharPointer_ASCII.h" compile="0" resource="0" | |||
| file="src/text/juce_CharPointer_ASCII.h"/> | |||
| <FILE id="vCX7K0" name="juce_CharPointer_UTF8.h" compile="0" resource="0" | |||
| file="src/text/juce_CharPointer_UTF8.h"/> | |||
| <FILE id="iGtCiI8" name="juce_Identifier.cpp" compile="1" resource="0" | |||
| file="src/text/juce_Identifier.cpp"/> | |||
| <FILE id="CPlhWqs" name="juce_Identifier.h" compile="0" resource="0" | |||
| file="src/text/juce_Identifier.h"/> | |||
| <FILE id="dkmz9Q" name="juce_JSON.cpp" compile="1" resource="0" file="src/text/juce_JSON.cpp"/> | |||
| <FILE id="Thklwk" name="juce_JSON.h" compile="0" resource="0" file="src/text/juce_JSON.h"/> | |||
| <FILE id="HCYu323Km" name="juce_LocalisedStrings.cpp" compile="1" resource="0" | |||
| file="src/text/juce_LocalisedStrings.cpp"/> | |||
| <FILE id="omEQRDHD" name="juce_LocalisedStrings.h" compile="0" resource="0" | |||
| @@ -147,6 +147,7 @@ | |||
| #include "../src/text/juce_StringPool.cpp" | |||
| #include "../src/text/juce_XmlDocument.cpp" | |||
| #include "../src/text/juce_XmlElement.cpp" | |||
| #include "../src/text/juce_JSON.cpp" | |||
| #include "../src/threads/juce_ReadWriteLock.cpp" | |||
| #include "../src/threads/juce_Thread.cpp" | |||
| #include "../src/threads/juce_ThreadPool.cpp" | |||
| @@ -4177,7 +4177,7 @@ Identifier::~Identifier() | |||
| bool Identifier::isValidIdentifier (const String& possibleIdentifier) noexcept | |||
| { | |||
| return possibleIdentifier.isNotEmpty() | |||
| && possibleIdentifier.containsOnly ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"); | |||
| && possibleIdentifier.containsOnly ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-:"); | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -4195,7 +4195,8 @@ enum VariantStreamMarkers | |||
| varMarker_BoolFalse = 3, | |||
| varMarker_Double = 4, | |||
| varMarker_String = 5, | |||
| varMarker_Int64 = 6 | |||
| varMarker_Int64 = 6, | |||
| varMarker_Array = 7 | |||
| }; | |||
| class var::VariantType | |||
| @@ -4210,6 +4211,7 @@ public: | |||
| virtual String toString (const ValueUnion&) const { return String::empty; } | |||
| virtual bool toBool (const ValueUnion&) const noexcept { return false; } | |||
| virtual ReferenceCountedObject* toObject (const ValueUnion&) const noexcept { return nullptr; } | |||
| virtual Array<var>* toArray (const ValueUnion&) const noexcept { return 0; } | |||
| virtual bool isVoid() const noexcept { return false; } | |||
| virtual bool isInt() const noexcept { return false; } | |||
| @@ -4218,6 +4220,7 @@ public: | |||
| virtual bool isDouble() const noexcept { return false; } | |||
| virtual bool isString() const noexcept { return false; } | |||
| virtual bool isObject() const noexcept { return false; } | |||
| virtual bool isArray() const noexcept { return false; } | |||
| virtual bool isMethod() const noexcept { return false; } | |||
| virtual void cleanUp (ValueUnion&) const noexcept {} | |||
| @@ -4405,6 +4408,40 @@ public: | |||
| } | |||
| }; | |||
| class var::VariantType_Array : public var::VariantType | |||
| { | |||
| public: | |||
| VariantType_Array() noexcept {} | |||
| static const VariantType_Array instance; | |||
| void cleanUp (ValueUnion& data) const noexcept { delete data.arrayValue; } | |||
| void createCopy (ValueUnion& dest, const ValueUnion& source) const { dest.arrayValue = new Array<var> (*(source.arrayValue)); } | |||
| String toString (const ValueUnion&) const { return "[Array]"; } | |||
| bool isArray() const noexcept { return true; } | |||
| Array<var>* toArray (const ValueUnion& data) const noexcept { return data.arrayValue; } | |||
| bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept | |||
| { | |||
| const Array<var>* const otherArray = otherType.toArray (otherData); | |||
| return otherArray != nullptr && *otherArray == *(data.arrayValue); | |||
| } | |||
| void writeToStream (const ValueUnion& data, OutputStream& output) const | |||
| { | |||
| MemoryOutputStream buffer (512); | |||
| const int numItems = data.arrayValue->size(); | |||
| buffer.writeCompressedInt (numItems); | |||
| for (int i = 0; i < numItems; ++i) | |||
| data.arrayValue->getReference(i).writeToStream (buffer); | |||
| output.writeCompressedInt (1 + buffer.getDataSize()); | |||
| output.writeByte (varMarker_Array); | |||
| output << buffer; | |||
| } | |||
| }; | |||
| class var::VariantType_Method : public var::VariantType | |||
| { | |||
| public: | |||
| @@ -4434,6 +4471,7 @@ const var::VariantType_Bool var::VariantType_Bool::instance; | |||
| const var::VariantType_Double var::VariantType_Double::instance; | |||
| const var::VariantType_String var::VariantType_String::instance; | |||
| const var::VariantType_Object var::VariantType_Object::instance; | |||
| const var::VariantType_Array var::VariantType_Array::instance; | |||
| const var::VariantType_Method var::VariantType_Method::instance; | |||
| var::var() noexcept : type (&VariantType_Void::instance) | |||
| @@ -4487,6 +4525,11 @@ var::var (const wchar_t* const value_) : type (&VariantType_String::instance) | |||
| new (value.stringValue) String (value_); | |||
| } | |||
| var::var (const Array<var>& value_) : type (&VariantType_Array::instance) | |||
| { | |||
| value.arrayValue = new Array<var> (value_); | |||
| } | |||
| var::var (ReferenceCountedObject* const object) : type (&VariantType_Object::instance) | |||
| { | |||
| value.objectValue = object; | |||
| @@ -4507,6 +4550,7 @@ bool var::isBool() const noexcept { return type->isBool(); } | |||
| bool var::isDouble() const noexcept { return type->isDouble(); } | |||
| bool var::isString() const noexcept { return type->isString(); } | |||
| bool var::isObject() const noexcept { return type->isObject(); } | |||
| bool var::isArray() const noexcept { return type->isArray(); } | |||
| bool var::isMethod() const noexcept { return type->isMethod(); } | |||
| var::operator int() const noexcept { return type->toInt (value); } | |||
| @@ -4517,6 +4561,7 @@ var::operator double() const noexcept { return type->toDouble (value); } | |||
| String var::toString() const { return type->toString (value); } | |||
| var::operator String() const { return type->toString (value); } | |||
| ReferenceCountedObject* var::getObject() const noexcept { return type->toObject (value); } | |||
| Array<var>* var::getArray() const noexcept { return type->toArray (value); } | |||
| DynamicObject* var::getDynamicObject() const noexcept { return dynamic_cast <DynamicObject*> (getObject()); } | |||
| void var::swapWith (var& other) noexcept | |||
| @@ -4533,6 +4578,7 @@ const var& var::operator= (const double newValue) { type->cleanUp (value); typ | |||
| const var& var::operator= (const char* const newValue) { var v (newValue); swapWith (v); return *this; } | |||
| const var& var::operator= (const wchar_t* const newValue) { var v (newValue); swapWith (v); return *this; } | |||
| const var& var::operator= (const String& newValue) { var v (newValue); swapWith (v); return *this; } | |||
| const var& var::operator= (const Array<var>& newValue) { var v (newValue); swapWith (v); return *this; } | |||
| const var& var::operator= (ReferenceCountedObject* newValue) { var v (newValue); swapWith (v); return *this; } | |||
| const var& var::operator= (MethodFunction newValue) { var v (newValue); swapWith (v); return *this; } | |||
| @@ -4553,38 +4599,6 @@ bool operator!= (const var& v1, const String& v2) { return v1.toString() != v | |||
| bool operator== (const var& v1, const char* const v2) { return v1.toString() == v2; } | |||
| bool operator!= (const var& v1, const char* const v2) { return v1.toString() != v2; } | |||
| void var::writeToStream (OutputStream& output) const | |||
| { | |||
| type->writeToStream (value, output); | |||
| } | |||
| var var::readFromStream (InputStream& input) | |||
| { | |||
| const int numBytes = input.readCompressedInt(); | |||
| if (numBytes > 0) | |||
| { | |||
| switch (input.readByte()) | |||
| { | |||
| case varMarker_Int: return var (input.readInt()); | |||
| case varMarker_Int64: return var (input.readInt64()); | |||
| case varMarker_BoolTrue: return var (true); | |||
| case varMarker_BoolFalse: return var (false); | |||
| case varMarker_Double: return var (input.readDouble()); | |||
| case varMarker_String: | |||
| { | |||
| MemoryOutputStream mo; | |||
| mo.writeFromInputStream (input, numBytes - 1); | |||
| return var (mo.toUTF8()); | |||
| } | |||
| default: input.skipNextBytes (numBytes - 1); break; | |||
| } | |||
| } | |||
| return var::null; | |||
| } | |||
| var var::operator[] (const Identifier& propertyName) const | |||
| { | |||
| DynamicObject* const o = getDynamicObject(); | |||
| @@ -4641,6 +4655,125 @@ var var::call (const Identifier& method, const var& arg1, const var& arg2, const | |||
| return invoke (method, args, 5); | |||
| } | |||
| int var::size() const | |||
| { | |||
| const Array<var>* const array = getArray(); | |||
| return array != nullptr ? array->size() : 0; | |||
| } | |||
| const var& var::operator[] (int arrayIndex) const | |||
| { | |||
| const Array<var>* const array = getArray(); | |||
| // When using this method, the var must actually be an array, and the index | |||
| // must be in-range! | |||
| jassert (array != nullptr && isPositiveAndBelow (arrayIndex, array->size())); | |||
| return array->getReference (arrayIndex); | |||
| } | |||
| var& var::operator[] (int arrayIndex) | |||
| { | |||
| const Array<var>* const array = getArray(); | |||
| // When using this method, the var must actually be an array, and the index | |||
| // must be in-range! | |||
| jassert (array != nullptr && isPositiveAndBelow (arrayIndex, array->size())); | |||
| return array->getReference (arrayIndex); | |||
| } | |||
| Array<var>* var::convertToArray() | |||
| { | |||
| Array<var>* array = getArray(); | |||
| if (array == nullptr) | |||
| { | |||
| const Array<var> tempVar; | |||
| var v (tempVar); | |||
| array = v.value.arrayValue; | |||
| if (! isVoid()) | |||
| array->add (*this); | |||
| swapWith (v); | |||
| } | |||
| return array; | |||
| } | |||
| void var::append (const var& value) | |||
| { | |||
| convertToArray()->add (value); | |||
| } | |||
| void var::remove (const int index) | |||
| { | |||
| Array<var>* const array = getArray(); | |||
| if (array != nullptr) | |||
| array->remove (index); | |||
| } | |||
| void var::insert (const int index, const var& value) | |||
| { | |||
| convertToArray()->insert (index, value); | |||
| } | |||
| void var::resize (const int numArrayElementsWanted) | |||
| { | |||
| convertToArray()->resize (numArrayElementsWanted); | |||
| } | |||
| int var::indexOf (const var& value) const | |||
| { | |||
| const Array<var>* const array = getArray(); | |||
| return array != nullptr ? array->indexOf (value) : -1; | |||
| } | |||
| void var::writeToStream (OutputStream& output) const | |||
| { | |||
| type->writeToStream (value, output); | |||
| } | |||
| var var::readFromStream (InputStream& input) | |||
| { | |||
| const int numBytes = input.readCompressedInt(); | |||
| if (numBytes > 0) | |||
| { | |||
| switch (input.readByte()) | |||
| { | |||
| case varMarker_Int: return var (input.readInt()); | |||
| case varMarker_Int64: return var (input.readInt64()); | |||
| case varMarker_BoolTrue: return var (true); | |||
| case varMarker_BoolFalse: return var (false); | |||
| case varMarker_Double: return var (input.readDouble()); | |||
| case varMarker_String: | |||
| { | |||
| MemoryOutputStream mo; | |||
| mo.writeFromInputStream (input, numBytes - 1); | |||
| return var (mo.toUTF8()); | |||
| } | |||
| case varMarker_Array: | |||
| { | |||
| var v; | |||
| Array<var>* const destArray = v.convertToArray(); | |||
| for (int i = input.readCompressedInt(); --i >= 0;) | |||
| destArray->add (readFromStream (input)); | |||
| return v; | |||
| } | |||
| default: input.skipNextBytes (numBytes - 1); break; | |||
| } | |||
| } | |||
| return var::null; | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| /*** End of inlined file: juce_Variant.cpp ***/ | |||
| @@ -4811,7 +4944,7 @@ const Identifier NamedValueSet::getName (const int index) const | |||
| return v->name; | |||
| } | |||
| var NamedValueSet::getValueAt (const int index) const | |||
| const var& NamedValueSet::getValueAt (const int index) const | |||
| { | |||
| const NamedValue* const v = values[index]; | |||
| jassert (v != nullptr); | |||
| @@ -8694,6 +8827,20 @@ bool FileOutputStream::write (const void* const src, const int numBytes) | |||
| return true; | |||
| } | |||
| void FileOutputStream::writeRepeatedByte (uint8 byte, int numBytes) | |||
| { | |||
| if (bytesInBuffer + numBytes < bufferSize) | |||
| { | |||
| memset (buffer + bytesInBuffer, byte, numBytes); | |||
| bytesInBuffer += numBytes; | |||
| currentPosition += numBytes; | |||
| } | |||
| else | |||
| { | |||
| OutputStream::writeRepeatedByte (byte, numBytes); | |||
| } | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| /*** End of inlined file: juce_FileOutputStream.cpp ***/ | |||
| @@ -10439,15 +10586,19 @@ void MemoryOutputStream::reset() noexcept | |||
| size = 0; | |||
| } | |||
| void MemoryOutputStream::prepareToWrite (int numBytes) | |||
| { | |||
| const size_t storageNeeded = position + numBytes; | |||
| if (storageNeeded >= data.getSize()) | |||
| data.ensureSize ((storageNeeded + jmin ((int) (storageNeeded / 2), 1024 * 1024) + 32) & ~31); | |||
| } | |||
| bool MemoryOutputStream::write (const void* const buffer, int howMany) | |||
| { | |||
| if (howMany > 0) | |||
| { | |||
| const size_t storageNeeded = position + howMany; | |||
| if (storageNeeded >= data.getSize()) | |||
| data.ensureSize ((storageNeeded + jmin ((int) (storageNeeded / 2), 1024 * 1024) + 32) & ~31); | |||
| prepareToWrite (howMany); | |||
| memcpy (static_cast<char*> (data.getData()) + position, buffer, howMany); | |||
| position += howMany; | |||
| size = jmax (size, position); | |||
| @@ -10456,6 +10607,17 @@ bool MemoryOutputStream::write (const void* const buffer, int howMany) | |||
| return true; | |||
| } | |||
| void MemoryOutputStream::writeRepeatedByte (uint8 byte, int howMany) | |||
| { | |||
| if (howMany > 0) | |||
| { | |||
| prepareToWrite (howMany); | |||
| memset (static_cast<char*> (data.getData()) + position, byte, howMany); | |||
| position += howMany; | |||
| size = jmax (size, position); | |||
| } | |||
| } | |||
| const void* MemoryOutputStream::getData() const noexcept | |||
| { | |||
| void* const d = data.getData(); | |||
| @@ -15618,21 +15780,9 @@ namespace XmlOutputFunctions | |||
| } | |||
| } | |||
| void writeSpaces (OutputStream& out, int numSpaces) | |||
| void writeSpaces (OutputStream& out, const int numSpaces) | |||
| { | |||
| if (numSpaces > 0) | |||
| { | |||
| const char blanks[] = " "; | |||
| const int blankSize = (int) numElementsInArray (blanks) - 1; | |||
| while (numSpaces > blankSize) | |||
| { | |||
| out.write (blanks, blankSize); | |||
| numSpaces -= blankSize; | |||
| } | |||
| out.write (blanks, numSpaces); | |||
| } | |||
| out.writeRepeatedByte (' ', numSpaces); | |||
| } | |||
| } | |||
| @@ -16278,6 +16428,506 @@ END_JUCE_NAMESPACE | |||
| /*** End of inlined file: juce_XmlElement.cpp ***/ | |||
| /*** Start of inlined file: juce_JSON.cpp ***/ | |||
| BEGIN_JUCE_NAMESPACE | |||
| class JSONParser | |||
| { | |||
| public: | |||
| static Result parseAny (String::CharPointerType& t, var& result) | |||
| { | |||
| t = t.findEndOfWhitespace(); | |||
| String::CharPointerType t2 (t); | |||
| switch (t2.getAndAdvance()) | |||
| { | |||
| case '{': t = t2; return parseObject (t, result); | |||
| case '[': t = t2; return parseArray (t, result); | |||
| case '"': t = t2; return parseString (t, result); | |||
| case '-': | |||
| t2 = t2.findEndOfWhitespace(); | |||
| if (! CharacterFunctions::isDigit (*t2)) | |||
| break; | |||
| t = t2; | |||
| return parseNumber (t, result, true); | |||
| case '0': case '1': case '2': case '3': case '4': | |||
| case '5': case '6': case '7': case '8': case '9': | |||
| return parseNumber (t, result, false); | |||
| case 't': // "true" | |||
| if (t2.getAndAdvance() == 'r' && t2.getAndAdvance() == 'u' && t2.getAndAdvance() == 'e') | |||
| { | |||
| t = t2; | |||
| result = var (true); | |||
| return Result::ok(); | |||
| } | |||
| break; | |||
| case 'f': // "false" | |||
| if (t2.getAndAdvance() == 'a' && t2.getAndAdvance() == 'l' | |||
| && t2.getAndAdvance() == 's' && t2.getAndAdvance() == 'e') | |||
| { | |||
| t = t2; | |||
| result = var (false); | |||
| return Result::ok(); | |||
| } | |||
| break; | |||
| case 'n': // "null" | |||
| if (t2.getAndAdvance() == 'u' && t2.getAndAdvance() == 'l' && t2.getAndAdvance() == 'l') | |||
| { | |||
| t = t2; | |||
| result = var::null; | |||
| return Result::ok(); | |||
| } | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| return createFail ("Syntax error", &t); | |||
| } | |||
| private: | |||
| static Result createFail (const char* const message, const String::CharPointerType* location = nullptr) | |||
| { | |||
| String m (message); | |||
| if (location != nullptr) | |||
| m << ": \"" << String (*location, 20) << '"'; | |||
| return Result::fail (m); | |||
| } | |||
| static Result parseNumber (String::CharPointerType& t, var& result, const bool isNegative) | |||
| { | |||
| String::CharPointerType oldT (t); | |||
| int64 intValue = t.getAndAdvance() - '0'; | |||
| jassert (intValue >= 0 && intValue < 10); | |||
| for (;;) | |||
| { | |||
| String::CharPointerType previousChar (t); | |||
| const juce_wchar c = t.getAndAdvance(); | |||
| const int digit = ((int) c) - '0'; | |||
| if (isPositiveAndBelow (digit, 10)) | |||
| { | |||
| intValue = intValue * 10 + digit; | |||
| continue; | |||
| } | |||
| if (c == 'e' || c == 'E' || c == '.') | |||
| { | |||
| t = oldT; | |||
| const double asDouble = CharacterFunctions::readDoubleValue (t); | |||
| result = isNegative ? -asDouble : asDouble; | |||
| return Result::ok(); | |||
| } | |||
| if (CharacterFunctions::isWhitespace (c) | |||
| || c == ',' || c == '}' || c == ']' || c == 0) | |||
| { | |||
| t = previousChar; | |||
| break; | |||
| } | |||
| return createFail ("Syntax error in number", &oldT); | |||
| } | |||
| const int64 correctedValue = isNegative ? -intValue : intValue; | |||
| if ((intValue >> 31) != 0) | |||
| result = correctedValue; | |||
| else | |||
| result = (int) correctedValue; | |||
| return Result::ok(); | |||
| } | |||
| static Result parseObject (String::CharPointerType& t, var& result) | |||
| { | |||
| DynamicObject* const resultObject = new DynamicObject(); | |||
| result = resultObject; | |||
| for (;;) | |||
| { | |||
| t = t.findEndOfWhitespace(); | |||
| String::CharPointerType oldT (t); | |||
| const juce_wchar c = t.getAndAdvance(); | |||
| if (c == '}') | |||
| break; | |||
| if (c == 0) | |||
| return createFail ("Unexpected end-of-input in object declaration"); | |||
| if (c == '"') | |||
| { | |||
| var propertyNameVar; | |||
| Result r (parseString (t, propertyNameVar)); | |||
| if (r.failed()) | |||
| return r; | |||
| const String propertyName (propertyNameVar.toString()); | |||
| if (propertyName.isNotEmpty()) | |||
| { | |||
| t = t.findEndOfWhitespace(); | |||
| oldT = t; | |||
| const juce_wchar c = t.getAndAdvance(); | |||
| if (c != ':') | |||
| return createFail ("Expected ':', but found", &oldT); | |||
| var propertyValue; | |||
| Result r (parseAny (t, propertyValue)); | |||
| if (r.failed()) | |||
| return r; | |||
| resultObject->setProperty (propertyName, propertyValue); | |||
| t = t.findEndOfWhitespace(); | |||
| oldT = t; | |||
| const juce_wchar nextChar = t.getAndAdvance(); | |||
| if (nextChar == ',') | |||
| continue; | |||
| else if (nextChar == '}') | |||
| break; | |||
| } | |||
| } | |||
| return createFail ("Expected object member declaration, but found", &oldT); | |||
| } | |||
| return Result::ok(); | |||
| } | |||
| static Result parseArray (String::CharPointerType& t, var& result) | |||
| { | |||
| result = var (Array<var>()); | |||
| Array<var>* const destArray = result.getArray(); | |||
| for (;;) | |||
| { | |||
| t = t.findEndOfWhitespace(); | |||
| String::CharPointerType oldT (t); | |||
| const juce_wchar c = t.getAndAdvance(); | |||
| if (c == ']') | |||
| break; | |||
| if (c == 0) | |||
| return createFail ("Unexpected end-of-input in array declaration"); | |||
| t = oldT; | |||
| destArray->add (var::null); | |||
| Result r (parseAny (t, destArray->getReference (destArray->size() - 1))); | |||
| if (r.failed()) | |||
| return r; | |||
| t = t.findEndOfWhitespace(); | |||
| oldT = t; | |||
| const juce_wchar nextChar = t.getAndAdvance(); | |||
| if (nextChar == ',') | |||
| continue; | |||
| else if (nextChar == ']') | |||
| break; | |||
| return createFail ("Expected object array item, but found", &oldT); | |||
| } | |||
| return Result::ok(); | |||
| } | |||
| static Result parseString (String::CharPointerType& t, var& result) | |||
| { | |||
| Array<juce_wchar> buffer; | |||
| buffer.ensureStorageAllocated (256); | |||
| for (;;) | |||
| { | |||
| juce_wchar c = t.getAndAdvance(); | |||
| if (c == '"') | |||
| break; | |||
| if (c == '\\') | |||
| { | |||
| c = t.getAndAdvance(); | |||
| switch (c) | |||
| { | |||
| case '"': | |||
| case '\\': | |||
| case '/': break; | |||
| case 'b': c = '\b'; break; | |||
| case 'f': c = '\f'; break; | |||
| case 'n': c = '\n'; break; | |||
| case 'r': c = '\r'; break; | |||
| case 't': c = '\t'; break; | |||
| case 'u': | |||
| { | |||
| c = 0; | |||
| for (int i = 4; --i >= 0;) | |||
| { | |||
| const int digitValue = CharacterFunctions::getHexDigitValue (t.getAndAdvance()); | |||
| if (digitValue < 0) | |||
| return createFail ("Syntax error in unicode escape sequence"); | |||
| c = (juce_wchar) ((c << 4) + digitValue); | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| if (c == 0) | |||
| return createFail ("Unexpected end-of-input in string constant"); | |||
| buffer.add (c); | |||
| } | |||
| buffer.add (0); | |||
| result = String (CharPointer_UTF32 (buffer.getRawDataPointer())); | |||
| return Result::ok(); | |||
| } | |||
| }; | |||
| class JSONFormatter | |||
| { | |||
| public: | |||
| static void write (OutputStream& out, const var& v, | |||
| const int indentLevel, const bool allOnOneLine) | |||
| { | |||
| if (v.isString()) | |||
| { | |||
| writeString (out, v.toString().getCharPointer()); | |||
| } | |||
| else if (v.isVoid()) | |||
| { | |||
| out << "null"; | |||
| } | |||
| else if (v.isBool()) | |||
| { | |||
| out << (static_cast<bool> (v) ? "true" : "false"); | |||
| } | |||
| else if (v.isArray()) | |||
| { | |||
| writeArray (out, *v.getArray(), indentLevel, allOnOneLine); | |||
| } | |||
| else if (v.isObject()) | |||
| { | |||
| DynamicObject* object = dynamic_cast<DynamicObject*> (v.getObject()); | |||
| jassert (object != nullptr); // Only DynamicObjects can be converted to JSON! | |||
| writeObject (out, *object, indentLevel, allOnOneLine); | |||
| } | |||
| else | |||
| { | |||
| jassert (! v.isMethod()); // Can't convert an object with methods to JSON! | |||
| out << v.toString(); | |||
| } | |||
| } | |||
| private: | |||
| enum { indentSize = 2 }; | |||
| static void writeEscapedChar (OutputStream& out, const unsigned short value) | |||
| { | |||
| out << "\\u" << String::toHexString ((int) value).paddedLeft ('0', 4); | |||
| } | |||
| static void writeString (OutputStream& out, String::CharPointerType t) | |||
| { | |||
| out << '"'; | |||
| for (;;) | |||
| { | |||
| const juce_wchar c (t.getAndAdvance()); | |||
| switch (c) | |||
| { | |||
| case 0: out << '"'; return; | |||
| case '\"': out << "\\\""; break; | |||
| case '\\': out << "\\\\"; break; | |||
| case '\b': out << "\\b"; break; | |||
| case '\f': out << "\\f"; break; | |||
| case '\t': out << "\\t"; break; | |||
| case '\r': out << "\\r"; break; | |||
| case '\n': out << "\\n"; break; | |||
| default: | |||
| if (c >= 32 && c < 127) | |||
| { | |||
| out << (char) c; | |||
| } | |||
| else | |||
| { | |||
| if (CharPointer_UTF16::getBytesRequiredFor (c) > 2) | |||
| { | |||
| CharPointer_UTF16::CharType chars[2]; | |||
| CharPointer_UTF16 utf16 (chars); | |||
| utf16.write (c); | |||
| for (int i = 0; i < 2; ++i) | |||
| writeEscapedChar (out, (unsigned short) chars[i]); | |||
| } | |||
| else | |||
| { | |||
| writeEscapedChar (out, (unsigned short) c); | |||
| } | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| static void writeSpaces (OutputStream& out, int numSpaces) | |||
| { | |||
| out.writeRepeatedByte (' ', numSpaces); | |||
| } | |||
| static void writeArray (OutputStream& out, const Array<var>& array, | |||
| const int indentLevel, const bool allOnOneLine) | |||
| { | |||
| out << '['; | |||
| if (! allOnOneLine) | |||
| out << newLine; | |||
| for (int i = 0; i < array.size(); ++i) | |||
| { | |||
| if (! allOnOneLine) | |||
| writeSpaces (out, indentLevel + indentSize); | |||
| write (out, array.getReference(i), indentLevel + indentSize, allOnOneLine); | |||
| if (i < array.size() - 1) | |||
| { | |||
| if (allOnOneLine) | |||
| out << ", "; | |||
| else | |||
| out << ',' << newLine; | |||
| } | |||
| else if (! allOnOneLine) | |||
| out << newLine; | |||
| } | |||
| if (! allOnOneLine) | |||
| writeSpaces (out, indentLevel); | |||
| out << ']'; | |||
| } | |||
| static void writeObject (OutputStream& out, DynamicObject& object, | |||
| const int indentLevel, const bool allOnOneLine) | |||
| { | |||
| NamedValueSet& props = object.getProperties(); | |||
| out << '{'; | |||
| if (! allOnOneLine) | |||
| out << newLine; | |||
| LinkedListPointer<NamedValueSet::NamedValue>* i = &(props.values); | |||
| for (;;) | |||
| { | |||
| NamedValueSet::NamedValue* const v = i->get(); | |||
| if (v == nullptr) | |||
| break; | |||
| if (! allOnOneLine) | |||
| writeSpaces (out, indentLevel + indentSize); | |||
| writeString (out, v->name); | |||
| out << ": "; | |||
| write (out, v->value, indentLevel + indentSize, allOnOneLine); | |||
| if (v->nextListItem.get() != nullptr) | |||
| { | |||
| if (allOnOneLine) | |||
| out << ", "; | |||
| else | |||
| out << ',' << newLine; | |||
| } | |||
| else if (! allOnOneLine) | |||
| out << newLine; | |||
| i = &(v->nextListItem); | |||
| } | |||
| if (! allOnOneLine) | |||
| writeSpaces (out, indentLevel); | |||
| out << '}'; | |||
| } | |||
| }; | |||
| var JSON::parse (const String& text) | |||
| { | |||
| var result; | |||
| String::CharPointerType t (text.getCharPointer()); | |||
| if (! JSONParser::parseAny (t, result)) | |||
| result = var::null; | |||
| return result; | |||
| } | |||
| var JSON::parse (InputStream& input) | |||
| { | |||
| return parse (input.readEntireStreamAsString()); | |||
| } | |||
| var JSON::parse (const File& file) | |||
| { | |||
| return parse (file.loadFileAsString()); | |||
| } | |||
| Result JSON::parse (const String& text, var& result) | |||
| { | |||
| String::CharPointerType t (text.getCharPointer()); | |||
| return JSONParser::parseAny (t, result); | |||
| } | |||
| String JSON::toString (const var& data, const bool allOnOneLine) | |||
| { | |||
| MemoryOutputStream mo (1024); | |||
| JSONFormatter::write (mo, data, 0, allOnOneLine); | |||
| return mo.toString(); | |||
| } | |||
| void JSON::writeToStream (OutputStream& output, const var& data, const bool allOnOneLine) | |||
| { | |||
| JSONFormatter::write (output, data, 0, allOnOneLine); | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| /*** End of inlined file: juce_JSON.cpp ***/ | |||
| /*** Start of inlined file: juce_ReadWriteLock.cpp ***/ | |||
| BEGIN_JUCE_NAMESPACE | |||
| @@ -243958,11 +244608,11 @@ bool SystemStats::isOperatingSystem64Bit() | |||
| #else | |||
| typedef BOOL (WINAPI* LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); | |||
| LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress (GetModuleHandle (L"kernel32"), "IsWow64Process"); | |||
| LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress (GetModuleHandle (_T("kernel32")), "IsWow64Process"); | |||
| BOOL isWow64 = FALSE; | |||
| return (fnIsWow64Process != 0) | |||
| return fnIsWow64Process != 0 | |||
| && fnIsWow64Process (GetCurrentProcess(), &isWow64) | |||
| && (isWow64 != FALSE); | |||
| #endif | |||
| @@ -246073,14 +246723,8 @@ void PlatformUtilities::registerFileAssociation (const String& fileExtension, | |||
| bool juce_IsRunningInWine() | |||
| { | |||
| HKEY key; | |||
| if (RegOpenKeyEx (HKEY_CURRENT_USER, _T("Software\\Wine"), 0, KEY_READ, &key) == ERROR_SUCCESS) | |||
| { | |||
| RegCloseKey (key); | |||
| return true; | |||
| } | |||
| return false; | |||
| HMODULE ntdll = GetModuleHandle (_T("ntdll.dll")); | |||
| return ntdll != 0 && GetProcAddress (ntdll, "wine_get_version") != 0; | |||
| } | |||
| const String JUCE_CALLTYPE PlatformUtilities::getCurrentCommandLineParams() | |||
| @@ -249045,6 +249689,14 @@ private: | |||
| #endif | |||
| } | |||
| static int getMinTimeBetweenMouseMoves() | |||
| { | |||
| if (SystemStats::getOperatingSystemType() >= SystemStats::WinVista) | |||
| return 0; | |||
| return 1000 / 60; // Throttling the incoming mouse-events seems to still be needed in XP.. | |||
| } | |||
| void doMouseMove (const Point<int>& position) | |||
| { | |||
| if (! isMouseOver) | |||
| @@ -249069,12 +249721,11 @@ private: | |||
| return; | |||
| } | |||
| // (Throttling the incoming queue of mouse-events seems to still be required in XP..) | |||
| static uint32 lastMouseTime = 0; | |||
| static int minTimeBetweenMouses = getMinTimeBetweenMouseMoves(); | |||
| const uint32 now = Time::getMillisecondCounter(); | |||
| const int maxMouseMovesPerSecond = 60; | |||
| if (now > lastMouseTime + 1000 / maxMouseMovesPerSecond) | |||
| if (now >= lastMouseTime + minTimeBetweenMouses) | |||
| { | |||
| lastMouseTime = now; | |||
| doMouseEvent (position); | |||
| @@ -73,7 +73,7 @@ namespace JuceDummyNamespace {} | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 53 | |||
| #define JUCE_BUILDNUMBER 97 | |||
| #define JUCE_BUILDNUMBER 98 | |||
| /** Current Juce version number. | |||
| @@ -7908,7 +7908,7 @@ public: | |||
| /** Checks a given string for characters that might not be valid in an Identifier. | |||
| Since Identifiers are used as a script variables and XML attributes, they should only contain | |||
| alphanumeric characters and underscores. | |||
| alphanumeric characters, underscores, or the '-' and ':' characters. | |||
| */ | |||
| static bool isValidIdentifier (const String& possibleIdentifier) noexcept; | |||
| @@ -8496,6 +8496,7 @@ public: | |||
| var (const char* value); | |||
| var (const wchar_t* value); | |||
| var (const String& value); | |||
| var (const Array<var>& value); | |||
| var (ReferenceCountedObject* object); | |||
| var (MethodFunction method) noexcept; | |||
| @@ -8507,6 +8508,7 @@ public: | |||
| const var& operator= (const char* value); | |||
| const var& operator= (const wchar_t* value); | |||
| const var& operator= (const String& value); | |||
| const var& operator= (const Array<var>& value); | |||
| const var& operator= (ReferenceCountedObject* object); | |||
| const var& operator= (MethodFunction method); | |||
| @@ -8519,6 +8521,7 @@ public: | |||
| operator double() const noexcept; | |||
| operator String() const; | |||
| String toString() const; | |||
| Array<var>* getArray() const noexcept; | |||
| ReferenceCountedObject* getObject() const noexcept; | |||
| DynamicObject* getDynamicObject() const noexcept; | |||
| @@ -8529,18 +8532,83 @@ public: | |||
| bool isDouble() const noexcept; | |||
| bool isString() const noexcept; | |||
| bool isObject() const noexcept; | |||
| bool isArray() const noexcept; | |||
| bool isMethod() const noexcept; | |||
| /** Writes a binary representation of this value to a stream. | |||
| The data can be read back later using readFromStream(). | |||
| /** Returns true if this var has the same value as the one supplied. | |||
| Note that this ignores the type, so a string var "123" and an integer var with the | |||
| value 123 are considered to be equal. | |||
| @see equalsWithSameType | |||
| */ | |||
| void writeToStream (OutputStream& output) const; | |||
| bool equals (const var& other) const noexcept; | |||
| /** Reads back a stored binary representation of a value. | |||
| The data in the stream must have been written using writeToStream(), or this | |||
| will have unpredictable results. | |||
| /** Returns true if this var has the same value and type as the one supplied. | |||
| This differs from equals() because e.g. "123" and 123 will be considered different. | |||
| @see equals | |||
| */ | |||
| static var readFromStream (InputStream& input); | |||
| bool equalsWithSameType (const var& other) const noexcept; | |||
| /** If the var is an array, this returns the number of elements. | |||
| If the var isn't actually an array, this will return 0. | |||
| */ | |||
| int size() const; | |||
| /** If the var is an array, this can be used to return one of its elements. | |||
| To call this method, you must make sure that the var is actually an array, and | |||
| that the index is a valid number. If these conditions aren't met, behaviour is | |||
| undefined. | |||
| For more control over the array's contents, you can call getArray() and manipulate | |||
| it directly as an Array<var>. | |||
| */ | |||
| const var& operator[] (int arrayIndex) const; | |||
| /** If the var is an array, this can be used to return one of its elements. | |||
| To call this method, you must make sure that the var is actually an array, and | |||
| that the index is a valid number. If these conditions aren't met, behaviour is | |||
| undefined. | |||
| For more control over the array's contents, you can call getArray() and manipulate | |||
| it directly as an Array<var>. | |||
| */ | |||
| var& operator[] (int arrayIndex); | |||
| /** Appends an element to the var, converting it to an array if it isn't already one. | |||
| If the var isn't an array, it will be converted to one, and if its value was non-void, | |||
| this value will be kept as the first element of the new array. The parameter value | |||
| will then be appended to it. | |||
| For more control over the array's contents, you can call getArray() and manipulate | |||
| it directly as an Array<var>. | |||
| */ | |||
| void append (const var& valueToAppend); | |||
| /** Inserts an element to the var, converting it to an array if it isn't already one. | |||
| If the var isn't an array, it will be converted to one, and if its value was non-void, | |||
| this value will be kept as the first element of the new array. The parameter value | |||
| will then be inserted into it. | |||
| For more control over the array's contents, you can call getArray() and manipulate | |||
| it directly as an Array<var>. | |||
| */ | |||
| void insert (int index, const var& value); | |||
| /** If the var is an array, this removes one of its elements. | |||
| If the index is out-of-range or the var isn't an array, nothing will be done. | |||
| For more control over the array's contents, you can call getArray() and manipulate | |||
| it directly as an Array<var>. | |||
| */ | |||
| void remove (int index); | |||
| /** Treating the var as an array, this resizes it to contain the specified number of elements. | |||
| If the var isn't an array, it will be converted to one, and if its value was non-void, | |||
| this value will be kept as the first element of the new array before resizing. | |||
| For more control over the array's contents, you can call getArray() and manipulate | |||
| it directly as an Array<var>. | |||
| */ | |||
| void resize (int numArrayElementsWanted); | |||
| /** If the var is an array, this searches it for the first occurrence of the specified value, | |||
| and returns its index. | |||
| If the var isn't an array, or if the value isn't found, this returns -1. | |||
| */ | |||
| int indexOf (const var& value) const; | |||
| /** If this variant is an object, this returns one of its properties. */ | |||
| var operator[] (const Identifier& propertyName) const; | |||
| @@ -8560,18 +8628,16 @@ public: | |||
| /** If this variant is an object, this invokes one of its methods with a list of arguments. */ | |||
| var invoke (const Identifier& method, const var* arguments, int numArguments) const; | |||
| /** Returns true if this var has the same value as the one supplied. | |||
| Note that this ignores the type, so a string var "123" and an integer var with the | |||
| value 123 are considered to be equal. | |||
| @see equalsWithSameType | |||
| /** Writes a binary representation of this value to a stream. | |||
| The data can be read back later using readFromStream(). | |||
| */ | |||
| bool equals (const var& other) const noexcept; | |||
| void writeToStream (OutputStream& output) const; | |||
| /** Returns true if this var has the same value and type as the one supplied. | |||
| This differs from equals() because e.g. "123" and 123 will be considered different. | |||
| @see equals | |||
| /** Reads back a stored binary representation of a value. | |||
| The data in the stream must have been written using writeToStream(), or this | |||
| will have unpredictable results. | |||
| */ | |||
| bool equalsWithSameType (const var& other) const noexcept; | |||
| static var readFromStream (InputStream& input); | |||
| private: | |||
| @@ -8583,6 +8649,7 @@ private: | |||
| class VariantType_Bool; friend class VariantType_Bool; | |||
| class VariantType_String; friend class VariantType_String; | |||
| class VariantType_Object; friend class VariantType_Object; | |||
| class VariantType_Array; friend class VariantType_Array; | |||
| class VariantType_Method; friend class VariantType_Method; | |||
| union ValueUnion | |||
| @@ -8593,12 +8660,14 @@ private: | |||
| double doubleValue; | |||
| char stringValue [sizeof (String)]; | |||
| ReferenceCountedObject* objectValue; | |||
| Array<var>* arrayValue; | |||
| MethodFunction methodValue; | |||
| }; | |||
| const VariantType* type; | |||
| ValueUnion value; | |||
| Array<var>* convertToArray(); | |||
| friend class DynamicObject; | |||
| var invokeMethod (DynamicObject*, const var*, int) const; | |||
| }; | |||
| @@ -8938,6 +9007,9 @@ private: | |||
| /*** End of inlined file: juce_LinkedListPointer.h ***/ | |||
| class XmlElement; | |||
| #ifndef DOXYGEN | |||
| class JSONFormatter; | |||
| #endif | |||
| /** Holds a set of named var objects. | |||
| @@ -8999,7 +9071,7 @@ public: | |||
| /** Returns the value of the item at a given index. | |||
| The index must be between 0 and size() - 1. | |||
| */ | |||
| var getValueAt (int index) const; | |||
| const var& getValueAt (int index) const; | |||
| /** Removes all values. */ | |||
| void clear(); | |||
| @@ -9041,6 +9113,8 @@ private: | |||
| friend class LinkedListPointer<NamedValue>; | |||
| LinkedListPointer<NamedValue> values; | |||
| friend class JSONFormatter; | |||
| }; | |||
| #endif // __JUCE_NAMEDVALUESET_JUCEHEADER__ | |||
| @@ -9439,6 +9513,9 @@ public: | |||
| /** Removes all properties and methods from the object. */ | |||
| void clear(); | |||
| /** Returns the NamedValueSet that holds the object's properties. */ | |||
| NamedValueSet& getProperties() noexcept { return properties; } | |||
| private: | |||
| NamedValueSet properties; | |||
| @@ -19285,6 +19362,7 @@ public: | |||
| int64 getPosition(); | |||
| bool setPosition (int64 pos); | |||
| bool write (const void* data, int numBytes); | |||
| void writeRepeatedByte (uint8 byte, int numTimesToRepeat); | |||
| private: | |||
| @@ -21122,6 +21200,7 @@ public: | |||
| int64 getPosition() { return position; } | |||
| bool setPosition (int64 newPosition); | |||
| int writeFromInputStream (InputStream& source, int64 maxNumBytesToWrite); | |||
| void writeRepeatedByte (uint8 byte, int numTimesToRepeat); | |||
| private: | |||
| @@ -21130,6 +21209,7 @@ private: | |||
| size_t position, size; | |||
| void trimExternalBlockSize(); | |||
| void prepareToWrite (int numBytes); | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryOutputStream); | |||
| }; | |||
| @@ -21802,6 +21882,98 @@ private: | |||
| #endif | |||
| #ifndef __JUCE_IDENTIFIER_JUCEHEADER__ | |||
| #endif | |||
| #ifndef __JUCE_JSON_JUCEHEADER__ | |||
| /*** Start of inlined file: juce_JSON.h ***/ | |||
| #ifndef __JUCE_JSON_JUCEHEADER__ | |||
| #define __JUCE_JSON_JUCEHEADER__ | |||
| class InputStream; | |||
| class OutputStream; | |||
| class File; | |||
| /** | |||
| Contains static methods for converting JSON-formatted text to and from var objects. | |||
| The var class is structurally compatible with JSON-formatted data, so these | |||
| functions allow you to parse JSON into a var object, and to convert a var | |||
| object to JSON-formatted text. | |||
| @see var | |||
| */ | |||
| class JSON | |||
| { | |||
| public: | |||
| /** Parses a string of JSON-formatted text, and returns a result code containing | |||
| any parse errors. | |||
| This will return the parsed structure in the parsedResult parameter, and will | |||
| return a Result object to indicate whether parsing was successful, and if not, | |||
| it will contain an error message. | |||
| If you're not interested in the error message, you can use one of the other | |||
| shortcut parse methods, which simply return a var::null if the parsing fails. | |||
| */ | |||
| static Result parse (const String& text, var& parsedResult); | |||
| /** Attempts to parse some JSON-formatted text, and returns the result as a var object. | |||
| If the parsing fails, this simply returns var::null - if you need to find out more | |||
| detail about the parse error, use the alternative parse() method which returns a Result. | |||
| */ | |||
| static var parse (const String& text); | |||
| /** Attempts to parse some JSON-formatted text from a file, and returns the result | |||
| as a var object. | |||
| Note that this is just a short-cut for reading the entire file into a string and | |||
| parsing the result. | |||
| If the parsing fails, this simply returns var::null - if you need to find out more | |||
| detail about the parse error, use the alternative parse() method which returns a Result. | |||
| */ | |||
| static var parse (const File& file); | |||
| /** Attempts to parse some JSON-formatted text from a stream, and returns the result | |||
| as a var object. | |||
| Note that this is just a short-cut for reading the entire stream into a string and | |||
| parsing the result. | |||
| If the parsing fails, this simply returns var::null - if you need to find out more | |||
| detail about the parse error, use the alternative parse() method which returns a Result. | |||
| */ | |||
| static var parse (InputStream& input); | |||
| /** Returns a string which contains a JSON-formatted representation of the var object. | |||
| If allOnOneLine is true, the result will be compacted into a single line of text | |||
| with no carriage-returns. If false, it will be laid-out in a more human-readable format. | |||
| @see writeToStream | |||
| */ | |||
| static String toString (const var& objectToFormat, | |||
| bool allOnOneLine = false); | |||
| /** Writes a JSON-formatted representation of the var object to the given stream. | |||
| If allOnOneLine is true, the result will be compacted into a single line of text | |||
| with no carriage-returns. If false, it will be laid-out in a more human-readable format. | |||
| @see toString | |||
| */ | |||
| static void writeToStream (OutputStream& output, | |||
| const var& objectToFormat, | |||
| bool allOnOneLine = false); | |||
| private: | |||
| JSON(); // This class can't be instantiated - just use its static methods. | |||
| }; | |||
| #endif // __JUCE_JSON_JUCEHEADER__ | |||
| /*** End of inlined file: juce_JSON.h ***/ | |||
| #endif | |||
| #ifndef __JUCE_LOCALISEDSTRINGS_JUCEHEADER__ | |||
| @@ -29,6 +29,9 @@ | |||
| #include "juce_Variant.h" | |||
| #include "../containers/juce_LinkedListPointer.h" | |||
| class XmlElement; | |||
| #ifndef DOXYGEN | |||
| class JSONFormatter; | |||
| #endif | |||
| //============================================================================== | |||
| @@ -137,6 +140,8 @@ private: | |||
| friend class LinkedListPointer<NamedValue>; | |||
| LinkedListPointer<NamedValue> values; | |||
| friend class JSONFormatter; | |||
| }; | |||
| @@ -38,7 +38,8 @@ enum VariantStreamMarkers | |||
| varMarker_BoolFalse = 3, | |||
| varMarker_Double = 4, | |||
| varMarker_String = 5, | |||
| varMarker_Int64 = 6 | |||
| varMarker_Int64 = 6, | |||
| varMarker_Array = 7 | |||
| }; | |||
| //============================================================================== | |||
| @@ -54,6 +55,7 @@ public: | |||
| virtual String toString (const ValueUnion&) const { return String::empty; } | |||
| virtual bool toBool (const ValueUnion&) const noexcept { return false; } | |||
| virtual ReferenceCountedObject* toObject (const ValueUnion&) const noexcept { return nullptr; } | |||
| virtual Array<var>* toArray (const ValueUnion&) const noexcept { return 0; } | |||
| virtual bool isVoid() const noexcept { return false; } | |||
| virtual bool isInt() const noexcept { return false; } | |||
| @@ -62,6 +64,7 @@ public: | |||
| virtual bool isDouble() const noexcept { return false; } | |||
| virtual bool isString() const noexcept { return false; } | |||
| virtual bool isObject() const noexcept { return false; } | |||
| virtual bool isArray() const noexcept { return false; } | |||
| virtual bool isMethod() const noexcept { return false; } | |||
| virtual void cleanUp (ValueUnion&) const noexcept {} | |||
| @@ -256,6 +259,41 @@ public: | |||
| } | |||
| }; | |||
| //============================================================================== | |||
| class var::VariantType_Array : public var::VariantType | |||
| { | |||
| public: | |||
| VariantType_Array() noexcept {} | |||
| static const VariantType_Array instance; | |||
| void cleanUp (ValueUnion& data) const noexcept { delete data.arrayValue; } | |||
| void createCopy (ValueUnion& dest, const ValueUnion& source) const { dest.arrayValue = new Array<var> (*(source.arrayValue)); } | |||
| String toString (const ValueUnion&) const { return "[Array]"; } | |||
| bool isArray() const noexcept { return true; } | |||
| Array<var>* toArray (const ValueUnion& data) const noexcept { return data.arrayValue; } | |||
| bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept | |||
| { | |||
| const Array<var>* const otherArray = otherType.toArray (otherData); | |||
| return otherArray != nullptr && *otherArray == *(data.arrayValue); | |||
| } | |||
| void writeToStream (const ValueUnion& data, OutputStream& output) const | |||
| { | |||
| MemoryOutputStream buffer (512); | |||
| const int numItems = data.arrayValue->size(); | |||
| buffer.writeCompressedInt (numItems); | |||
| for (int i = 0; i < numItems; ++i) | |||
| data.arrayValue->getReference(i).writeToStream (buffer); | |||
| output.writeCompressedInt (1 + buffer.getDataSize()); | |||
| output.writeByte (varMarker_Array); | |||
| output << buffer; | |||
| } | |||
| }; | |||
| //============================================================================== | |||
| class var::VariantType_Method : public var::VariantType | |||
| { | |||
| @@ -287,6 +325,7 @@ const var::VariantType_Bool var::VariantType_Bool::instance; | |||
| const var::VariantType_Double var::VariantType_Double::instance; | |||
| const var::VariantType_String var::VariantType_String::instance; | |||
| const var::VariantType_Object var::VariantType_Object::instance; | |||
| const var::VariantType_Array var::VariantType_Array::instance; | |||
| const var::VariantType_Method var::VariantType_Method::instance; | |||
| @@ -343,6 +382,11 @@ var::var (const wchar_t* const value_) : type (&VariantType_String::instance) | |||
| new (value.stringValue) String (value_); | |||
| } | |||
| var::var (const Array<var>& value_) : type (&VariantType_Array::instance) | |||
| { | |||
| value.arrayValue = new Array<var> (value_); | |||
| } | |||
| var::var (ReferenceCountedObject* const object) : type (&VariantType_Object::instance) | |||
| { | |||
| value.objectValue = object; | |||
| @@ -364,6 +408,7 @@ bool var::isBool() const noexcept { return type->isBool(); } | |||
| bool var::isDouble() const noexcept { return type->isDouble(); } | |||
| bool var::isString() const noexcept { return type->isString(); } | |||
| bool var::isObject() const noexcept { return type->isObject(); } | |||
| bool var::isArray() const noexcept { return type->isArray(); } | |||
| bool var::isMethod() const noexcept { return type->isMethod(); } | |||
| var::operator int() const noexcept { return type->toInt (value); } | |||
| @@ -374,6 +419,7 @@ var::operator double() const noexcept { return type->toDouble | |||
| String var::toString() const { return type->toString (value); } | |||
| var::operator String() const { return type->toString (value); } | |||
| ReferenceCountedObject* var::getObject() const noexcept { return type->toObject (value); } | |||
| Array<var>* var::getArray() const noexcept { return type->toArray (value); } | |||
| DynamicObject* var::getDynamicObject() const noexcept { return dynamic_cast <DynamicObject*> (getObject()); } | |||
| //============================================================================== | |||
| @@ -391,6 +437,7 @@ const var& var::operator= (const double newValue) { type->cleanUp (v | |||
| const var& var::operator= (const char* const newValue) { var v (newValue); swapWith (v); return *this; } | |||
| const var& var::operator= (const wchar_t* const newValue) { var v (newValue); swapWith (v); return *this; } | |||
| const var& var::operator= (const String& newValue) { var v (newValue); swapWith (v); return *this; } | |||
| const var& var::operator= (const Array<var>& newValue) { var v (newValue); swapWith (v); return *this; } | |||
| const var& var::operator= (ReferenceCountedObject* newValue) { var v (newValue); swapWith (v); return *this; } | |||
| const var& var::operator= (MethodFunction newValue) { var v (newValue); swapWith (v); return *this; } | |||
| @@ -414,38 +461,6 @@ bool operator!= (const var& v1, const char* const v2) { return v1.toString | |||
| //============================================================================== | |||
| void var::writeToStream (OutputStream& output) const | |||
| { | |||
| type->writeToStream (value, output); | |||
| } | |||
| var var::readFromStream (InputStream& input) | |||
| { | |||
| const int numBytes = input.readCompressedInt(); | |||
| if (numBytes > 0) | |||
| { | |||
| switch (input.readByte()) | |||
| { | |||
| case varMarker_Int: return var (input.readInt()); | |||
| case varMarker_Int64: return var (input.readInt64()); | |||
| case varMarker_BoolTrue: return var (true); | |||
| case varMarker_BoolFalse: return var (false); | |||
| case varMarker_Double: return var (input.readDouble()); | |||
| case varMarker_String: | |||
| { | |||
| MemoryOutputStream mo; | |||
| mo.writeFromInputStream (input, numBytes - 1); | |||
| return var (mo.toUTF8()); | |||
| } | |||
| default: input.skipNextBytes (numBytes - 1); break; | |||
| } | |||
| } | |||
| return var::null; | |||
| } | |||
| var var::operator[] (const Identifier& propertyName) const | |||
| { | |||
| DynamicObject* const o = getDynamicObject(); | |||
| @@ -502,5 +517,126 @@ var var::call (const Identifier& method, const var& arg1, const var& arg2, const | |||
| return invoke (method, args, 5); | |||
| } | |||
| //============================================================================== | |||
| int var::size() const | |||
| { | |||
| const Array<var>* const array = getArray(); | |||
| return array != nullptr ? array->size() : 0; | |||
| } | |||
| const var& var::operator[] (int arrayIndex) const | |||
| { | |||
| const Array<var>* const array = getArray(); | |||
| // When using this method, the var must actually be an array, and the index | |||
| // must be in-range! | |||
| jassert (array != nullptr && isPositiveAndBelow (arrayIndex, array->size())); | |||
| return array->getReference (arrayIndex); | |||
| } | |||
| var& var::operator[] (int arrayIndex) | |||
| { | |||
| const Array<var>* const array = getArray(); | |||
| // When using this method, the var must actually be an array, and the index | |||
| // must be in-range! | |||
| jassert (array != nullptr && isPositiveAndBelow (arrayIndex, array->size())); | |||
| return array->getReference (arrayIndex); | |||
| } | |||
| Array<var>* var::convertToArray() | |||
| { | |||
| Array<var>* array = getArray(); | |||
| if (array == nullptr) | |||
| { | |||
| const Array<var> tempVar; | |||
| var v (tempVar); | |||
| array = v.value.arrayValue; | |||
| if (! isVoid()) | |||
| array->add (*this); | |||
| swapWith (v); | |||
| } | |||
| return array; | |||
| } | |||
| void var::append (const var& value) | |||
| { | |||
| convertToArray()->add (value); | |||
| } | |||
| void var::remove (const int index) | |||
| { | |||
| Array<var>* const array = getArray(); | |||
| if (array != nullptr) | |||
| array->remove (index); | |||
| } | |||
| void var::insert (const int index, const var& value) | |||
| { | |||
| convertToArray()->insert (index, value); | |||
| } | |||
| void var::resize (const int numArrayElementsWanted) | |||
| { | |||
| convertToArray()->resize (numArrayElementsWanted); | |||
| } | |||
| int var::indexOf (const var& value) const | |||
| { | |||
| const Array<var>* const array = getArray(); | |||
| return array != nullptr ? array->indexOf (value) : -1; | |||
| } | |||
| //============================================================================== | |||
| void var::writeToStream (OutputStream& output) const | |||
| { | |||
| type->writeToStream (value, output); | |||
| } | |||
| var var::readFromStream (InputStream& input) | |||
| { | |||
| const int numBytes = input.readCompressedInt(); | |||
| if (numBytes > 0) | |||
| { | |||
| switch (input.readByte()) | |||
| { | |||
| case varMarker_Int: return var (input.readInt()); | |||
| case varMarker_Int64: return var (input.readInt64()); | |||
| case varMarker_BoolTrue: return var (true); | |||
| case varMarker_BoolFalse: return var (false); | |||
| case varMarker_Double: return var (input.readDouble()); | |||
| case varMarker_String: | |||
| { | |||
| MemoryOutputStream mo; | |||
| mo.writeFromInputStream (input, numBytes - 1); | |||
| return var (mo.toUTF8()); | |||
| } | |||
| case varMarker_Array: | |||
| { | |||
| var v; | |||
| Array<var>* const destArray = v.convertToArray(); | |||
| for (int i = input.readCompressedInt(); --i >= 0;) | |||
| destArray->add (readFromStream (input)); | |||
| return v; | |||
| } | |||
| default: input.skipNextBytes (numBytes - 1); break; | |||
| } | |||
| } | |||
| return var::null; | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -29,6 +29,7 @@ | |||
| #include "../text/juce_Identifier.h" | |||
| #include "../io/streams/juce_OutputStream.h" | |||
| #include "../io/streams/juce_InputStream.h" | |||
| #include "../containers/juce_Array.h" | |||
| #ifndef DOXYGEN | |||
| class ReferenceCountedObject; | |||
| @@ -70,6 +71,7 @@ public: | |||
| var (const char* value); | |||
| var (const wchar_t* value); | |||
| var (const String& value); | |||
| var (const Array<var>& value); | |||
| var (ReferenceCountedObject* object); | |||
| var (MethodFunction method) noexcept; | |||
| @@ -81,6 +83,7 @@ public: | |||
| const var& operator= (const char* value); | |||
| const var& operator= (const wchar_t* value); | |||
| const var& operator= (const String& value); | |||
| const var& operator= (const Array<var>& value); | |||
| const var& operator= (ReferenceCountedObject* object); | |||
| const var& operator= (MethodFunction method); | |||
| @@ -93,6 +96,7 @@ public: | |||
| operator double() const noexcept; | |||
| operator String() const; | |||
| String toString() const; | |||
| Array<var>* getArray() const noexcept; | |||
| ReferenceCountedObject* getObject() const noexcept; | |||
| DynamicObject* getDynamicObject() const noexcept; | |||
| @@ -103,25 +107,89 @@ public: | |||
| bool isDouble() const noexcept; | |||
| bool isString() const noexcept; | |||
| bool isObject() const noexcept; | |||
| bool isArray() const noexcept; | |||
| bool isMethod() const noexcept; | |||
| /** Returns true if this var has the same value as the one supplied. | |||
| Note that this ignores the type, so a string var "123" and an integer var with the | |||
| value 123 are considered to be equal. | |||
| @see equalsWithSameType | |||
| */ | |||
| bool equals (const var& other) const noexcept; | |||
| /** Returns true if this var has the same value and type as the one supplied. | |||
| This differs from equals() because e.g. "123" and 123 will be considered different. | |||
| @see equals | |||
| */ | |||
| bool equalsWithSameType (const var& other) const noexcept; | |||
| //============================================================================== | |||
| /** Writes a binary representation of this value to a stream. | |||
| The data can be read back later using readFromStream(). | |||
| /** If the var is an array, this returns the number of elements. | |||
| If the var isn't actually an array, this will return 0. | |||
| */ | |||
| void writeToStream (OutputStream& output) const; | |||
| int size() const; | |||
| /** If the var is an array, this can be used to return one of its elements. | |||
| To call this method, you must make sure that the var is actually an array, and | |||
| that the index is a valid number. If these conditions aren't met, behaviour is | |||
| undefined. | |||
| For more control over the array's contents, you can call getArray() and manipulate | |||
| it directly as an Array<var>. | |||
| */ | |||
| const var& operator[] (int arrayIndex) const; | |||
| /** If the var is an array, this can be used to return one of its elements. | |||
| To call this method, you must make sure that the var is actually an array, and | |||
| that the index is a valid number. If these conditions aren't met, behaviour is | |||
| undefined. | |||
| For more control over the array's contents, you can call getArray() and manipulate | |||
| it directly as an Array<var>. | |||
| */ | |||
| var& operator[] (int arrayIndex); | |||
| /** Appends an element to the var, converting it to an array if it isn't already one. | |||
| If the var isn't an array, it will be converted to one, and if its value was non-void, | |||
| this value will be kept as the first element of the new array. The parameter value | |||
| will then be appended to it. | |||
| For more control over the array's contents, you can call getArray() and manipulate | |||
| it directly as an Array<var>. | |||
| */ | |||
| void append (const var& valueToAppend); | |||
| /** Inserts an element to the var, converting it to an array if it isn't already one. | |||
| If the var isn't an array, it will be converted to one, and if its value was non-void, | |||
| this value will be kept as the first element of the new array. The parameter value | |||
| will then be inserted into it. | |||
| For more control over the array's contents, you can call getArray() and manipulate | |||
| it directly as an Array<var>. | |||
| */ | |||
| void insert (int index, const var& value); | |||
| /** Reads back a stored binary representation of a value. | |||
| The data in the stream must have been written using writeToStream(), or this | |||
| will have unpredictable results. | |||
| /** If the var is an array, this removes one of its elements. | |||
| If the index is out-of-range or the var isn't an array, nothing will be done. | |||
| For more control over the array's contents, you can call getArray() and manipulate | |||
| it directly as an Array<var>. | |||
| */ | |||
| static var readFromStream (InputStream& input); | |||
| void remove (int index); | |||
| /** Treating the var as an array, this resizes it to contain the specified number of elements. | |||
| If the var isn't an array, it will be converted to one, and if its value was non-void, | |||
| this value will be kept as the first element of the new array before resizing. | |||
| For more control over the array's contents, you can call getArray() and manipulate | |||
| it directly as an Array<var>. | |||
| */ | |||
| void resize (int numArrayElementsWanted); | |||
| /** If the var is an array, this searches it for the first occurrence of the specified value, | |||
| and returns its index. | |||
| If the var isn't an array, or if the value isn't found, this returns -1. | |||
| */ | |||
| int indexOf (const var& value) const; | |||
| //============================================================================== | |||
| /** If this variant is an object, this returns one of its properties. */ | |||
| var operator[] (const Identifier& propertyName) const; | |||
| //============================================================================== | |||
| /** If this variant is an object, this invokes one of its methods with no arguments. */ | |||
| var call (const Identifier& method) const; | |||
| /** If this variant is an object, this invokes one of its methods with one argument. */ | |||
| @@ -138,19 +206,16 @@ public: | |||
| var invoke (const Identifier& method, const var* arguments, int numArguments) const; | |||
| //============================================================================== | |||
| /** Returns true if this var has the same value as the one supplied. | |||
| Note that this ignores the type, so a string var "123" and an integer var with the | |||
| value 123 are considered to be equal. | |||
| @see equalsWithSameType | |||
| /** Writes a binary representation of this value to a stream. | |||
| The data can be read back later using readFromStream(). | |||
| */ | |||
| bool equals (const var& other) const noexcept; | |||
| void writeToStream (OutputStream& output) const; | |||
| /** Returns true if this var has the same value and type as the one supplied. | |||
| This differs from equals() because e.g. "123" and 123 will be considered different. | |||
| @see equals | |||
| /** Reads back a stored binary representation of a value. | |||
| The data in the stream must have been written using writeToStream(), or this | |||
| will have unpredictable results. | |||
| */ | |||
| bool equalsWithSameType (const var& other) const noexcept; | |||
| static var readFromStream (InputStream& input); | |||
| private: | |||
| //============================================================================== | |||
| @@ -162,6 +227,7 @@ private: | |||
| class VariantType_Bool; friend class VariantType_Bool; | |||
| class VariantType_String; friend class VariantType_String; | |||
| class VariantType_Object; friend class VariantType_Object; | |||
| class VariantType_Array; friend class VariantType_Array; | |||
| class VariantType_Method; friend class VariantType_Method; | |||
| union ValueUnion | |||
| @@ -172,12 +238,14 @@ private: | |||
| double doubleValue; | |||
| char stringValue [sizeof (String)]; | |||
| ReferenceCountedObject* objectValue; | |||
| Array<var>* arrayValue; | |||
| MethodFunction methodValue; | |||
| }; | |||
| const VariantType* type; | |||
| ValueUnion value; | |||
| Array<var>* convertToArray(); | |||
| friend class DynamicObject; | |||
| var invokeMethod (DynamicObject*, const var*, int) const; | |||
| }; | |||
| @@ -33,7 +33,7 @@ | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 53 | |||
| #define JUCE_BUILDNUMBER 97 | |||
| #define JUCE_BUILDNUMBER 98 | |||
| /** Current Juce version number. | |||
| @@ -121,4 +121,19 @@ bool FileOutputStream::write (const void* const src, const int numBytes) | |||
| return true; | |||
| } | |||
| void FileOutputStream::writeRepeatedByte (uint8 byte, int numBytes) | |||
| { | |||
| if (bytesInBuffer + numBytes < bufferSize) | |||
| { | |||
| memset (buffer + bytesInBuffer, byte, numBytes); | |||
| bytesInBuffer += numBytes; | |||
| currentPosition += numBytes; | |||
| } | |||
| else | |||
| { | |||
| OutputStream::writeRepeatedByte (byte, numBytes); | |||
| } | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -83,6 +83,7 @@ public: | |||
| int64 getPosition(); | |||
| bool setPosition (int64 pos); | |||
| bool write (const void* data, int numBytes); | |||
| void writeRepeatedByte (uint8 byte, int numTimesToRepeat); | |||
| private: | |||
| @@ -77,15 +77,19 @@ void MemoryOutputStream::reset() noexcept | |||
| size = 0; | |||
| } | |||
| void MemoryOutputStream::prepareToWrite (int numBytes) | |||
| { | |||
| const size_t storageNeeded = position + numBytes; | |||
| if (storageNeeded >= data.getSize()) | |||
| data.ensureSize ((storageNeeded + jmin ((int) (storageNeeded / 2), 1024 * 1024) + 32) & ~31); | |||
| } | |||
| bool MemoryOutputStream::write (const void* const buffer, int howMany) | |||
| { | |||
| if (howMany > 0) | |||
| { | |||
| const size_t storageNeeded = position + howMany; | |||
| if (storageNeeded >= data.getSize()) | |||
| data.ensureSize ((storageNeeded + jmin ((int) (storageNeeded / 2), 1024 * 1024) + 32) & ~31); | |||
| prepareToWrite (howMany); | |||
| memcpy (static_cast<char*> (data.getData()) + position, buffer, howMany); | |||
| position += howMany; | |||
| size = jmax (size, position); | |||
| @@ -94,6 +98,17 @@ bool MemoryOutputStream::write (const void* const buffer, int howMany) | |||
| return true; | |||
| } | |||
| void MemoryOutputStream::writeRepeatedByte (uint8 byte, int howMany) | |||
| { | |||
| if (howMany > 0) | |||
| { | |||
| prepareToWrite (howMany); | |||
| memset (static_cast<char*> (data.getData()) + position, byte, howMany); | |||
| position += howMany; | |||
| size = jmax (size, position); | |||
| } | |||
| } | |||
| const void* MemoryOutputStream::getData() const noexcept | |||
| { | |||
| void* const d = data.getData(); | |||
| @@ -108,7 +108,7 @@ public: | |||
| int64 getPosition() { return position; } | |||
| bool setPosition (int64 newPosition); | |||
| int writeFromInputStream (InputStream& source, int64 maxNumBytesToWrite); | |||
| void writeRepeatedByte (uint8 byte, int numTimesToRepeat); | |||
| private: | |||
| //============================================================================== | |||
| @@ -117,6 +117,7 @@ private: | |||
| size_t position, size; | |||
| void trimExternalBlockSize(); | |||
| void prepareToWrite (int numBytes); | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryOutputStream); | |||
| }; | |||
| @@ -260,6 +260,9 @@ | |||
| #ifndef __JUCE_IDENTIFIER_JUCEHEADER__ | |||
| #include "text/juce_Identifier.h" | |||
| #endif | |||
| #ifndef __JUCE_JSON_JUCEHEADER__ | |||
| #include "text/juce_JSON.h" | |||
| #endif | |||
| #ifndef __JUCE_LOCALISEDSTRINGS_JUCEHEADER__ | |||
| #include "text/juce_LocalisedStrings.h" | |||
| #endif | |||
| @@ -0,0 +1,532 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-11 by Raw Material Software Ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||
| Public License (Version 2), as published by the Free Software Foundation. | |||
| A copy of the license is included in the JUCE distribution, or can be found | |||
| online at www.gnu.org/licenses. | |||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
| ------------------------------------------------------------------------------ | |||
| To release a closed-source product which uses JUCE, commercial licenses are | |||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||
| ============================================================================== | |||
| */ | |||
| #include "../core/juce_StandardHeader.h" | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "juce_JSON.h" | |||
| #include "../io/files/juce_File.h" | |||
| #include "../io/streams/juce_MemoryOutputStream.h" | |||
| #include "../containers/juce_DynamicObject.h" | |||
| //============================================================================== | |||
| class JSONParser | |||
| { | |||
| public: | |||
| static Result parseAny (String::CharPointerType& t, var& result) | |||
| { | |||
| t = t.findEndOfWhitespace(); | |||
| String::CharPointerType t2 (t); | |||
| switch (t2.getAndAdvance()) | |||
| { | |||
| case '{': t = t2; return parseObject (t, result); | |||
| case '[': t = t2; return parseArray (t, result); | |||
| case '"': t = t2; return parseString (t, result); | |||
| case '-': | |||
| t2 = t2.findEndOfWhitespace(); | |||
| if (! CharacterFunctions::isDigit (*t2)) | |||
| break; | |||
| t = t2; | |||
| return parseNumber (t, result, true); | |||
| case '0': case '1': case '2': case '3': case '4': | |||
| case '5': case '6': case '7': case '8': case '9': | |||
| return parseNumber (t, result, false); | |||
| case 't': // "true" | |||
| if (t2.getAndAdvance() == 'r' && t2.getAndAdvance() == 'u' && t2.getAndAdvance() == 'e') | |||
| { | |||
| t = t2; | |||
| result = var (true); | |||
| return Result::ok(); | |||
| } | |||
| break; | |||
| case 'f': // "false" | |||
| if (t2.getAndAdvance() == 'a' && t2.getAndAdvance() == 'l' | |||
| && t2.getAndAdvance() == 's' && t2.getAndAdvance() == 'e') | |||
| { | |||
| t = t2; | |||
| result = var (false); | |||
| return Result::ok(); | |||
| } | |||
| break; | |||
| case 'n': // "null" | |||
| if (t2.getAndAdvance() == 'u' && t2.getAndAdvance() == 'l' && t2.getAndAdvance() == 'l') | |||
| { | |||
| t = t2; | |||
| result = var::null; | |||
| return Result::ok(); | |||
| } | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| return createFail ("Syntax error", &t); | |||
| } | |||
| private: | |||
| static Result createFail (const char* const message, const String::CharPointerType* location = nullptr) | |||
| { | |||
| String m (message); | |||
| if (location != nullptr) | |||
| m << ": \"" << String (*location, 20) << '"'; | |||
| return Result::fail (m); | |||
| } | |||
| static Result parseNumber (String::CharPointerType& t, var& result, const bool isNegative) | |||
| { | |||
| String::CharPointerType oldT (t); | |||
| int64 intValue = t.getAndAdvance() - '0'; | |||
| jassert (intValue >= 0 && intValue < 10); | |||
| for (;;) | |||
| { | |||
| String::CharPointerType previousChar (t); | |||
| const juce_wchar c = t.getAndAdvance(); | |||
| const int digit = ((int) c) - '0'; | |||
| if (isPositiveAndBelow (digit, 10)) | |||
| { | |||
| intValue = intValue * 10 + digit; | |||
| continue; | |||
| } | |||
| if (c == 'e' || c == 'E' || c == '.') | |||
| { | |||
| t = oldT; | |||
| const double asDouble = CharacterFunctions::readDoubleValue (t); | |||
| result = isNegative ? -asDouble : asDouble; | |||
| return Result::ok(); | |||
| } | |||
| if (CharacterFunctions::isWhitespace (c) | |||
| || c == ',' || c == '}' || c == ']' || c == 0) | |||
| { | |||
| t = previousChar; | |||
| break; | |||
| } | |||
| return createFail ("Syntax error in number", &oldT); | |||
| } | |||
| const int64 correctedValue = isNegative ? -intValue : intValue; | |||
| if ((intValue >> 31) != 0) | |||
| result = correctedValue; | |||
| else | |||
| result = (int) correctedValue; | |||
| return Result::ok(); | |||
| } | |||
| static Result parseObject (String::CharPointerType& t, var& result) | |||
| { | |||
| DynamicObject* const resultObject = new DynamicObject(); | |||
| result = resultObject; | |||
| for (;;) | |||
| { | |||
| t = t.findEndOfWhitespace(); | |||
| String::CharPointerType oldT (t); | |||
| const juce_wchar c = t.getAndAdvance(); | |||
| if (c == '}') | |||
| break; | |||
| if (c == 0) | |||
| return createFail ("Unexpected end-of-input in object declaration"); | |||
| if (c == '"') | |||
| { | |||
| var propertyNameVar; | |||
| Result r (parseString (t, propertyNameVar)); | |||
| if (r.failed()) | |||
| return r; | |||
| const String propertyName (propertyNameVar.toString()); | |||
| if (propertyName.isNotEmpty()) | |||
| { | |||
| t = t.findEndOfWhitespace(); | |||
| oldT = t; | |||
| const juce_wchar c = t.getAndAdvance(); | |||
| if (c != ':') | |||
| return createFail ("Expected ':', but found", &oldT); | |||
| var propertyValue; | |||
| Result r (parseAny (t, propertyValue)); | |||
| if (r.failed()) | |||
| return r; | |||
| resultObject->setProperty (propertyName, propertyValue); | |||
| t = t.findEndOfWhitespace(); | |||
| oldT = t; | |||
| const juce_wchar nextChar = t.getAndAdvance(); | |||
| if (nextChar == ',') | |||
| continue; | |||
| else if (nextChar == '}') | |||
| break; | |||
| } | |||
| } | |||
| return createFail ("Expected object member declaration, but found", &oldT); | |||
| } | |||
| return Result::ok(); | |||
| } | |||
| static Result parseArray (String::CharPointerType& t, var& result) | |||
| { | |||
| result = var (Array<var>()); | |||
| Array<var>* const destArray = result.getArray(); | |||
| for (;;) | |||
| { | |||
| t = t.findEndOfWhitespace(); | |||
| String::CharPointerType oldT (t); | |||
| const juce_wchar c = t.getAndAdvance(); | |||
| if (c == ']') | |||
| break; | |||
| if (c == 0) | |||
| return createFail ("Unexpected end-of-input in array declaration"); | |||
| t = oldT; | |||
| destArray->add (var::null); | |||
| Result r (parseAny (t, destArray->getReference (destArray->size() - 1))); | |||
| if (r.failed()) | |||
| return r; | |||
| t = t.findEndOfWhitespace(); | |||
| oldT = t; | |||
| const juce_wchar nextChar = t.getAndAdvance(); | |||
| if (nextChar == ',') | |||
| continue; | |||
| else if (nextChar == ']') | |||
| break; | |||
| return createFail ("Expected object array item, but found", &oldT); | |||
| } | |||
| return Result::ok(); | |||
| } | |||
| static Result parseString (String::CharPointerType& t, var& result) | |||
| { | |||
| Array<juce_wchar> buffer; | |||
| buffer.ensureStorageAllocated (256); | |||
| for (;;) | |||
| { | |||
| juce_wchar c = t.getAndAdvance(); | |||
| if (c == '"') | |||
| break; | |||
| if (c == '\\') | |||
| { | |||
| c = t.getAndAdvance(); | |||
| switch (c) | |||
| { | |||
| case '"': | |||
| case '\\': | |||
| case '/': break; | |||
| case 'b': c = '\b'; break; | |||
| case 'f': c = '\f'; break; | |||
| case 'n': c = '\n'; break; | |||
| case 'r': c = '\r'; break; | |||
| case 't': c = '\t'; break; | |||
| case 'u': | |||
| { | |||
| c = 0; | |||
| for (int i = 4; --i >= 0;) | |||
| { | |||
| const int digitValue = CharacterFunctions::getHexDigitValue (t.getAndAdvance()); | |||
| if (digitValue < 0) | |||
| return createFail ("Syntax error in unicode escape sequence"); | |||
| c = (juce_wchar) ((c << 4) + digitValue); | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| if (c == 0) | |||
| return createFail ("Unexpected end-of-input in string constant"); | |||
| buffer.add (c); | |||
| } | |||
| buffer.add (0); | |||
| result = String (CharPointer_UTF32 (buffer.getRawDataPointer())); | |||
| return Result::ok(); | |||
| } | |||
| }; | |||
| //============================================================================== | |||
| class JSONFormatter | |||
| { | |||
| public: | |||
| static void write (OutputStream& out, const var& v, | |||
| const int indentLevel, const bool allOnOneLine) | |||
| { | |||
| if (v.isString()) | |||
| { | |||
| writeString (out, v.toString().getCharPointer()); | |||
| } | |||
| else if (v.isVoid()) | |||
| { | |||
| out << "null"; | |||
| } | |||
| else if (v.isBool()) | |||
| { | |||
| out << (static_cast<bool> (v) ? "true" : "false"); | |||
| } | |||
| else if (v.isArray()) | |||
| { | |||
| writeArray (out, *v.getArray(), indentLevel, allOnOneLine); | |||
| } | |||
| else if (v.isObject()) | |||
| { | |||
| DynamicObject* object = dynamic_cast<DynamicObject*> (v.getObject()); | |||
| jassert (object != nullptr); // Only DynamicObjects can be converted to JSON! | |||
| writeObject (out, *object, indentLevel, allOnOneLine); | |||
| } | |||
| else | |||
| { | |||
| jassert (! v.isMethod()); // Can't convert an object with methods to JSON! | |||
| out << v.toString(); | |||
| } | |||
| } | |||
| private: | |||
| enum { indentSize = 2 }; | |||
| static void writeEscapedChar (OutputStream& out, const unsigned short value) | |||
| { | |||
| out << "\\u" << String::toHexString ((int) value).paddedLeft ('0', 4); | |||
| } | |||
| static void writeString (OutputStream& out, String::CharPointerType t) | |||
| { | |||
| out << '"'; | |||
| for (;;) | |||
| { | |||
| const juce_wchar c (t.getAndAdvance()); | |||
| switch (c) | |||
| { | |||
| case 0: out << '"'; return; | |||
| case '\"': out << "\\\""; break; | |||
| case '\\': out << "\\\\"; break; | |||
| case '\b': out << "\\b"; break; | |||
| case '\f': out << "\\f"; break; | |||
| case '\t': out << "\\t"; break; | |||
| case '\r': out << "\\r"; break; | |||
| case '\n': out << "\\n"; break; | |||
| default: | |||
| if (c >= 32 && c < 127) | |||
| { | |||
| out << (char) c; | |||
| } | |||
| else | |||
| { | |||
| if (CharPointer_UTF16::getBytesRequiredFor (c) > 2) | |||
| { | |||
| CharPointer_UTF16::CharType chars[2]; | |||
| CharPointer_UTF16 utf16 (chars); | |||
| utf16.write (c); | |||
| for (int i = 0; i < 2; ++i) | |||
| writeEscapedChar (out, (unsigned short) chars[i]); | |||
| } | |||
| else | |||
| { | |||
| writeEscapedChar (out, (unsigned short) c); | |||
| } | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| static void writeSpaces (OutputStream& out, int numSpaces) | |||
| { | |||
| out.writeRepeatedByte (' ', numSpaces); | |||
| } | |||
| static void writeArray (OutputStream& out, const Array<var>& array, | |||
| const int indentLevel, const bool allOnOneLine) | |||
| { | |||
| out << '['; | |||
| if (! allOnOneLine) | |||
| out << newLine; | |||
| for (int i = 0; i < array.size(); ++i) | |||
| { | |||
| if (! allOnOneLine) | |||
| writeSpaces (out, indentLevel + indentSize); | |||
| write (out, array.getReference(i), indentLevel + indentSize, allOnOneLine); | |||
| if (i < array.size() - 1) | |||
| { | |||
| if (allOnOneLine) | |||
| out << ", "; | |||
| else | |||
| out << ',' << newLine; | |||
| } | |||
| else if (! allOnOneLine) | |||
| out << newLine; | |||
| } | |||
| if (! allOnOneLine) | |||
| writeSpaces (out, indentLevel); | |||
| out << ']'; | |||
| } | |||
| static void writeObject (OutputStream& out, DynamicObject& object, | |||
| const int indentLevel, const bool allOnOneLine) | |||
| { | |||
| NamedValueSet& props = object.getProperties(); | |||
| out << '{'; | |||
| if (! allOnOneLine) | |||
| out << newLine; | |||
| LinkedListPointer<NamedValueSet::NamedValue>* i = &(props.values); | |||
| for (;;) | |||
| { | |||
| NamedValueSet::NamedValue* const v = i->get(); | |||
| if (v == nullptr) | |||
| break; | |||
| if (! allOnOneLine) | |||
| writeSpaces (out, indentLevel + indentSize); | |||
| writeString (out, v->name); | |||
| out << ": "; | |||
| write (out, v->value, indentLevel + indentSize, allOnOneLine); | |||
| if (v->nextListItem.get() != nullptr) | |||
| { | |||
| if (allOnOneLine) | |||
| out << ", "; | |||
| else | |||
| out << ',' << newLine; | |||
| } | |||
| else if (! allOnOneLine) | |||
| out << newLine; | |||
| i = &(v->nextListItem); | |||
| } | |||
| if (! allOnOneLine) | |||
| writeSpaces (out, indentLevel); | |||
| out << '}'; | |||
| } | |||
| }; | |||
| //============================================================================== | |||
| var JSON::parse (const String& text) | |||
| { | |||
| var result; | |||
| String::CharPointerType t (text.getCharPointer()); | |||
| if (! JSONParser::parseAny (t, result)) | |||
| result = var::null; | |||
| return result; | |||
| } | |||
| var JSON::parse (InputStream& input) | |||
| { | |||
| return parse (input.readEntireStreamAsString()); | |||
| } | |||
| var JSON::parse (const File& file) | |||
| { | |||
| return parse (file.loadFileAsString()); | |||
| } | |||
| Result JSON::parse (const String& text, var& result) | |||
| { | |||
| String::CharPointerType t (text.getCharPointer()); | |||
| return JSONParser::parseAny (t, result); | |||
| } | |||
| String JSON::toString (const var& data, const bool allOnOneLine) | |||
| { | |||
| MemoryOutputStream mo (1024); | |||
| JSONFormatter::write (mo, data, 0, allOnOneLine); | |||
| return mo.toString(); | |||
| } | |||
| void JSON::writeToStream (OutputStream& output, const var& data, const bool allOnOneLine) | |||
| { | |||
| JSONFormatter::write (output, data, 0, allOnOneLine); | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -0,0 +1,115 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-11 by Raw Material Software Ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||
| Public License (Version 2), as published by the Free Software Foundation. | |||
| A copy of the license is included in the JUCE distribution, or can be found | |||
| online at www.gnu.org/licenses. | |||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
| ------------------------------------------------------------------------------ | |||
| To release a closed-source product which uses JUCE, commercial licenses are | |||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_JSON_JUCEHEADER__ | |||
| #define __JUCE_JSON_JUCEHEADER__ | |||
| #include "../core/juce_Result.h" | |||
| #include "../containers/juce_Variant.h" | |||
| class InputStream; | |||
| class OutputStream; | |||
| class File; | |||
| //============================================================================== | |||
| /** | |||
| Contains static methods for converting JSON-formatted text to and from var objects. | |||
| The var class is structurally compatible with JSON-formatted data, so these | |||
| functions allow you to parse JSON into a var object, and to convert a var | |||
| object to JSON-formatted text. | |||
| @see var | |||
| */ | |||
| class JSON | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** Parses a string of JSON-formatted text, and returns a result code containing | |||
| any parse errors. | |||
| This will return the parsed structure in the parsedResult parameter, and will | |||
| return a Result object to indicate whether parsing was successful, and if not, | |||
| it will contain an error message. | |||
| If you're not interested in the error message, you can use one of the other | |||
| shortcut parse methods, which simply return a var::null if the parsing fails. | |||
| */ | |||
| static Result parse (const String& text, var& parsedResult); | |||
| /** Attempts to parse some JSON-formatted text, and returns the result as a var object. | |||
| If the parsing fails, this simply returns var::null - if you need to find out more | |||
| detail about the parse error, use the alternative parse() method which returns a Result. | |||
| */ | |||
| static var parse (const String& text); | |||
| /** Attempts to parse some JSON-formatted text from a file, and returns the result | |||
| as a var object. | |||
| Note that this is just a short-cut for reading the entire file into a string and | |||
| parsing the result. | |||
| If the parsing fails, this simply returns var::null - if you need to find out more | |||
| detail about the parse error, use the alternative parse() method which returns a Result. | |||
| */ | |||
| static var parse (const File& file); | |||
| /** Attempts to parse some JSON-formatted text from a stream, and returns the result | |||
| as a var object. | |||
| Note that this is just a short-cut for reading the entire stream into a string and | |||
| parsing the result. | |||
| If the parsing fails, this simply returns var::null - if you need to find out more | |||
| detail about the parse error, use the alternative parse() method which returns a Result. | |||
| */ | |||
| static var parse (InputStream& input); | |||
| //============================================================================== | |||
| /** Returns a string which contains a JSON-formatted representation of the var object. | |||
| If allOnOneLine is true, the result will be compacted into a single line of text | |||
| with no carriage-returns. If false, it will be laid-out in a more human-readable format. | |||
| @see writeToStream | |||
| */ | |||
| static String toString (const var& objectToFormat, | |||
| bool allOnOneLine = false); | |||
| /** Writes a JSON-formatted representation of the var object to the given stream. | |||
| If allOnOneLine is true, the result will be compacted into a single line of text | |||
| with no carriage-returns. If false, it will be laid-out in a more human-readable format. | |||
| @see toString | |||
| */ | |||
| static void writeToStream (OutputStream& output, | |||
| const var& objectToFormat, | |||
| bool allOnOneLine = false); | |||
| private: | |||
| //============================================================================== | |||
| JSON(); // This class can't be instantiated - just use its static methods. | |||
| }; | |||
| #endif // __JUCE_JSON_JUCEHEADER__ | |||
| @@ -193,21 +193,9 @@ namespace XmlOutputFunctions | |||
| } | |||
| } | |||
| void writeSpaces (OutputStream& out, int numSpaces) | |||
| void writeSpaces (OutputStream& out, const int numSpaces) | |||
| { | |||
| if (numSpaces > 0) | |||
| { | |||
| const char blanks[] = " "; | |||
| const int blankSize = (int) numElementsInArray (blanks) - 1; | |||
| while (numSpaces > blankSize) | |||
| { | |||
| out.write (blanks, blankSize); | |||
| numSpaces -= blankSize; | |||
| } | |||
| out.write (blanks, numSpaces); | |||
| } | |||
| out.writeRepeatedByte (' ', numSpaces); | |||
| } | |||
| } | |||