Browse Source

--- Merging r16712 into '.':
U packages/fcl-json/tests/testjsondata.pp
U packages/fcl-json/tests/testjson.pp
A packages/fcl-json/tests/testjsonrtti.pp
U packages/fcl-json/tests/testjson.lpi
A packages/fcl-json/src/fpjsonrtti.pp
U packages/fcl-json/src/fpjson.pp
--- Merging r16713 into '.':
A packages/fcl-json/examples/demortti.pp
--- Merging r16716 into '.':
C packages/fcl-json/Makefile.fpc
C packages/fcl-json/Makefile
--- Merging r16768 into '.':
U packages/fcl-web/src/base/webpage.pp
U packages/fcl-web/src/base/fphtml.pp
Summary of conflicts:
Text conflicts: 2

# revisions: 16712,16713,16716,16768
------------------------------------------------------------------------
r16712 | michael | 2011-01-05 23:49:00 +0100 (Wed, 05 Jan 2011) | 1 line
Changed paths:
M /trunk/packages/fcl-json/src/fpjson.pp
A /trunk/packages/fcl-json/src/fpjsonrtti.pp
M /trunk/packages/fcl-json/tests/testjson.lpi
M /trunk/packages/fcl-json/tests/testjson.pp
M /trunk/packages/fcl-json/tests/testjsondata.pp
A /trunk/packages/fcl-json/tests/testjsonrtti.pp

* Support for RTTI streaming
------------------------------------------------------------------------
------------------------------------------------------------------------
r16713 | michael | 2011-01-05 23:54:45 +0100 (Wed, 05 Jan 2011) | 1 line
Changed paths:
A /trunk/packages/fcl-json/examples/demortti.pp

* Example for streaming
------------------------------------------------------------------------
------------------------------------------------------------------------
r16716 | michael | 2011-01-06 09:31:00 +0100 (Thu, 06 Jan 2011) | 1 line
Changed paths:
M /trunk/packages/fcl-json/Makefile
M /trunk/packages/fcl-json/Makefile.fpc

* Forgot to add fpjsonrtti to makefile
------------------------------------------------------------------------
------------------------------------------------------------------------
r16768 | joost | 2011-01-15 18:55:08 +0100 (Sat, 15 Jan 2011) | 2 lines
Changed paths:
M /trunk/packages/fcl-web/src/base/fphtml.pp
M /trunk/packages/fcl-web/src/base/webpage.pp

* Implemented IHTMLDesignable
* Fixed moving an element forward, so that it is inserted before the given element
------------------------------------------------------------------------

git-svn-id: branches/fixes_2_4@16976 -

marco 14 years ago
parent
commit
977b106d9a

+ 3 - 0
.gitattributes

@@ -1501,6 +1501,7 @@ packages/fcl-json/Makefile.fpc svneol=native#text/plain
 packages/fcl-json/examples/confdemo.lpi svneol=native#text/plain
 packages/fcl-json/examples/confdemo.pp svneol=native#text/plain
 packages/fcl-json/examples/demoformat.pp svneol=native#text/plain
+packages/fcl-json/examples/demortti.pp svneol=native#text/plain
 packages/fcl-json/examples/parsedemo.lpi svneol=native#text/plain
 packages/fcl-json/examples/parsedemo.pp svneol=native#text/plain
 packages/fcl-json/examples/simpledemo.lpi svneol=native#text/plain
@@ -1508,6 +1509,7 @@ packages/fcl-json/examples/simpledemo.pp svneol=native#text/plain
 packages/fcl-json/fpmake.pp svneol=native#text/plain
 packages/fcl-json/src/README.txt svneol=native#text/plain
 packages/fcl-json/src/fpjson.pp svneol=native#text/plain
+packages/fcl-json/src/fpjsonrtti.pp svneol=native#text/plain
 packages/fcl-json/src/jsonconf.pp svneol=native#text/plain
 packages/fcl-json/src/jsonparser.pp svneol=native#text/plain
 packages/fcl-json/src/jsonscanner.pp svneol=native#text/plain
@@ -1518,6 +1520,7 @@ packages/fcl-json/tests/testjsonconf.lpi svneol=native#text/plain
 packages/fcl-json/tests/testjsonconf.pp svneol=native#text/plain
 packages/fcl-json/tests/testjsondata.pp svneol=native#text/plain
 packages/fcl-json/tests/testjsonparser.pp svneol=native#text/plain
+packages/fcl-json/tests/testjsonrtti.pp svneol=native#text/plain
 packages/fcl-net/Makefile svneol=native#text/plain
 packages/fcl-net/Makefile.fpc svneol=native#text/plain
 packages/fcl-net/README.txt svneol=native#text/plain

+ 123 - 121
packages/fcl-json/Makefile

@@ -1,5 +1,5 @@
 #
-# Don't edit, this file is generated by FPCMake Version 2.0.0 [2010/08/25]
+# Don't edit, this file is generated by FPCMake Version 2.0.0 [2011/02/22]
 #
 default: all
 MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-qnx i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian m68k-linux m68k-freebsd m68k-netbsd m68k-amiga m68k-atari m68k-openbsd m68k-palmos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-solaris x86_64-darwin x86_64-win64 x86_64-embedded arm-linux arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian powerpc64-linux powerpc64-darwin powerpc64-embedded avr-embedded armeb-linux armeb-embedded mipsel-linux
@@ -267,364 +267,364 @@ PACKAGESDIR:=$(wildcard $(FPCDIR) $(FPCDIR)/packages $(FPCDIR)/packages/base $(F
 override PACKAGE_NAME=fcl-json
 override PACKAGE_VERSION=2.4.3
 ifeq ($(FULL_TARGET),i386-linux)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-go32v2)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-win32)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-os2)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-freebsd)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-beos)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-haiku)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-netbsd)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-solaris)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-qnx)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-netware)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-openbsd)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-wdosx)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-darwin)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-emx)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-watcom)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-netwlibc)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-wince)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-embedded)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-symbian)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),m68k-linux)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),m68k-freebsd)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),m68k-netbsd)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),m68k-amiga)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),m68k-atari)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),m68k-openbsd)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),m68k-palmos)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),m68k-embedded)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),powerpc-linux)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),powerpc-netbsd)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),powerpc-amiga)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),powerpc-macos)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),powerpc-darwin)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),powerpc-morphos)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),powerpc-embedded)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),sparc-linux)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),sparc-netbsd)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),sparc-solaris)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),sparc-embedded)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),x86_64-linux)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),x86_64-freebsd)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),x86_64-solaris)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),x86_64-darwin)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),x86_64-win64)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),x86_64-embedded)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),arm-linux)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),arm-palmos)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),arm-darwin)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),arm-wince)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),arm-gba)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),arm-nds)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),arm-embedded)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),arm-symbian)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),powerpc64-linux)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),powerpc64-darwin)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),powerpc64-embedded)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),avr-embedded)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),armeb-linux)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),armeb-embedded)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),mipsel-linux)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-linux)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-go32v2)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-win32)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-os2)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-freebsd)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-beos)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-haiku)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-netbsd)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-solaris)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-qnx)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-netware)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-openbsd)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-wdosx)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-darwin)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-emx)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-watcom)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-netwlibc)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-wince)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-embedded)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),i386-symbian)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),m68k-linux)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),m68k-freebsd)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),m68k-netbsd)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),m68k-amiga)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),m68k-atari)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),m68k-openbsd)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),m68k-palmos)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),m68k-embedded)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),powerpc-linux)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),powerpc-netbsd)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),powerpc-amiga)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),powerpc-macos)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),powerpc-darwin)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),powerpc-morphos)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),powerpc-embedded)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),sparc-linux)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),sparc-netbsd)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),sparc-solaris)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),sparc-embedded)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),x86_64-linux)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),x86_64-freebsd)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),x86_64-solaris)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),x86_64-darwin)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),x86_64-win64)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),x86_64-embedded)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),arm-linux)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),arm-palmos)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),arm-darwin)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),arm-wince)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),arm-gba)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),arm-nds)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),arm-embedded)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),arm-symbian)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),powerpc64-linux)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),powerpc64-darwin)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),powerpc64-embedded)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),avr-embedded)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),armeb-linux)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),armeb-embedded)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 ifeq ($(FULL_TARGET),mipsel-linux)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 endif
 override INSTALL_FPCPACKAGE=y
 ifeq ($(FULL_TARGET),i386-linux)
@@ -2679,3 +2679,5 @@ endif
 .NOTPARALLEL:
 jsonparser$(PPUEXT): jsonparser.pp fpjson$(PPUEXT) jsonscanner$(PPUEXT)
 jsonconf$(PPUEXT): jsonparser$(PPUEXT) fpjson$(PPUEXT)
+jsonconf$(PPUEXT): jsonparser$(PPUEXT) fpjson$(PPUEXT)
+fpjsonrtti$(PPUEXT): jsonparser$(PPUEXT) fpjson$(PPUEXT)

+ 5 - 3
packages/fcl-json/Makefile.fpc

@@ -7,8 +7,8 @@ name=fcl-json
 version=2.4.3
 
 [target]
-units=fpjson jsonscanner jsonparser jsonconf
-rsts=fpjson jsonscanner jsonparser jsonconf
+units=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
+rsts=fpjson jsonscanner jsonparser jsonconf fpjsonrtti
 
 [require]
 packages=fcl-base
@@ -28,4 +28,6 @@ fpcdir=../..
 
 jsonparser$(PPUEXT): jsonparser.pp fpjson$(PPUEXT) jsonscanner$(PPUEXT)
 
-jsonconf$(PPUEXT): jsonparser$(PPUEXT) fpjson$(PPUEXT)
+jsonconf$(PPUEXT): jsonparser$(PPUEXT) fpjson$(PPUEXT)
+jsonconf$(PPUEXT): jsonparser$(PPUEXT) fpjson$(PPUEXT)
+fpjsonrtti$(PPUEXT): jsonparser$(PPUEXT) fpjson$(PPUEXT)

+ 364 - 0
packages/fcl-json/examples/demortti.pp

@@ -0,0 +1,364 @@
+program demortti;
+
+{$mode objfpc}{$H+}
+
+uses
+  Classes, SysUtils, fpjson, fpjsonrtti, variants;
+
+{$R *.res}
+
+Var
+  JS : TJSONStreamer;
+
+Type
+
+  { TTestItem }
+
+  TTestItem = Class(TCollectionItem)
+  private
+    FStrProp: String;
+  Published
+    Property StrProp : String Read FStrProp Write FStrProp;
+  end;
+
+  { TCollComponent }
+
+  TCollComponent = Class(TComponent)
+  private
+    FCollProp: TCollection;
+  Published
+   Property CollProp : TCollection Read FCollProp Write FCollProp;
+  end;
+
+  { TCompComponent }
+
+  TCompComponent = Class(TComponent)
+  private
+    FCompProp: TComponent;
+  Published
+   Property CompProp : TComponent Read FCompProp Write FCompProp;
+  end;
+
+  TDice = (one,two,three,four,five,six);
+  TThrow = Set of TDice;
+
+  { TEnumComponent }
+
+  TEnumComponent = Class(TComponent)
+  private
+    FDice: TDice;
+  Published
+    Property Dice : TDice Read FDice Write FDice;
+  end;
+
+  { TSetComponent }
+
+  TSetComponent = Class(TComponent)
+  private
+    FThrow: TThrow;
+  Published
+    Property Throw : TThrow Read FThrow Write FThrow;
+  end;
+
+  { TChildComponent }
+
+  TChildComponent = Class(TComponent)
+  Protected
+    procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
+  end;
+
+  { TChildComponent }
+
+  procedure TChildComponent.GetChildren(Proc: TGetChildProc; Root: TComponent);
+
+  Var
+    I : Integer;
+
+  begin
+    Writeln('Children',ComponentCount);
+    For I:=0 to ComponentCount-1 do
+      Proc(Components[i]);
+  end;
+
+
+Procedure DumpObject(const Header : String; var O : TJSONData);
+
+begin
+  Writeln(Header,' : ');
+  Writeln(O.FormatJSON());
+  writeln();
+  FreeAndNil(O);
+  JS.Options:=[];
+end;
+
+Procedure DemoObject;
+
+Var
+  C : TComponent;
+  O : TJSONData;
+
+begin
+  C:=TComponent.Create(Nil);
+  try
+    C.Name:='DemoComponent';
+    C.Tag:=23;
+    O:=JS.ObjectToJSON(C);
+    DumpObject('Complete component',O);
+  finally
+    FreeAndNil(C);
+  end;
+end;
+
+Procedure DemoComponentObject;
+
+Var
+  C : TCompComponent;
+  O : TJSONData;
+
+begin
+  C:=TCompComponent.Create(Nil);
+  try
+    C.Name:='DemoComponent';
+    C.Tag:=23;
+    C.CompProp:=TCompComponent.Create(C);
+    C.CompProp.Name:='SubComponent';
+    C.CompProp.Tag:=45;
+    O:=JS.ObjectToJSON(C);
+    DumpObject('Component-valued property',O);
+    TCompComponent(C.CompProp).FComponentStyle:=[csSubComponent];
+    O:=JS.ObjectToJSON(C);
+    DumpObject('Component-valued property, csSubComponent in Componentstyle',O);
+    TCompComponent(C.CompProp).FComponentStyle:=[];
+    JS.options:=[jsoComponentsInline];
+    O:=JS.ObjectToJSON(C);
+    DumpObject('Component-valued property, options:=[jsoComponentsInline] ',O);
+  finally
+    FreeAndNil(C);
+  end;
+end;
+
+Procedure DemoChildObject;
+
+Var
+  C : TChildComponent;
+  O : TJSONData;
+
+begin
+  C:=TChildComponent.Create(Nil);
+  try
+    C.Name:='ParentComponent';
+    C.Tag:=23;
+    With TComponent.Create(C) do
+      begin
+      Name:='Child1';
+      Tag:=1;
+      end;
+    With TComponent.Create(C) do
+      begin
+      Name:='Child2';
+      Tag:=2;
+      end;
+    O:=JS.ObjectToJSON(C);
+    DumpObject('Component with children, default options',O);
+    JS.Options:=[jsoStreamChildren];
+    O:=JS.ObjectToJSON(C);
+    DumpObject('Component with children, Options:=[jsoStreamChildren]',O);
+  finally
+    FreeAndNil(C);
+  end;
+end;
+
+Procedure DemoEnumObject;
+
+Var
+  C : TEnumComponent;
+  O : TJSONData;
+
+begin
+  C:=TEnumComponent.Create(Nil);
+  try
+    C.Dice:=Three;
+    O:=JS.ObjectToJSON(C);
+    DumpObject('Enumerated-typed property, default settings',O);
+    JS.Options:=[jsoEnumeratedAsInteger];
+    O:=JS.ObjectToJSON(C);
+    DumpObject('Enumerated-typed property, Options:=[jsoEnumeratedAsInteger];',O);
+  finally
+    FreeAndNil(C);
+  end;
+end;
+
+Procedure DemoSetObject;
+
+Var
+  C : TSetComponent;
+  O : TJSONData;
+
+begin
+  C:=TSetComponent.Create(Nil);
+  try
+    C.Throw:=[two,five];
+    O:=JS.ObjectToJSON(C);
+    DumpObject('set-typed property, default settings',O);
+    JS.Options:=[jsoSetAsString];
+    O:=JS.ObjectToJSON(C);
+    DumpObject('Set-typed property, Options:=[jsoSetAsString];',O);
+    JS.Options:=[jsoSetAsString,jsoSetBrackets];
+    O:=JS.ObjectToJSON(C);
+    DumpObject('Set-typed property, Options:=[jsoSetAsString,jsoSetBrackets];',O);
+    JS.Options:=[jsoSetEnumeratedAsInteger];
+    O:=JS.ObjectToJSON(C);
+    DumpObject('Set-typed property, Options:=[jsoSetEnumeratedAsInteger];',O);
+  finally
+    FreeAndNil(C);
+  end;
+end;
+
+Procedure DemoObjectAsString;
+
+Var
+  C : TComponent;
+
+begin
+  C:=TComponent.Create(Nil);
+  try
+    C.Name:='DemoComponent';
+    C.Tag:=23;
+    Writeln('Complete component, directly as string :');
+    Writeln(JS.ObjectToJSONString(C));
+    JS.Options:=[jsoUseFormatString];
+    Writeln('Complete component, directly as string (Options:=[jsoUseFormatString]):');
+    Writeln(JS.ObjectToJSONString(C));
+    JS.Options:=[];
+    Writeln('');
+  finally
+    FreeAndNil(C);
+  end;
+end;
+
+Procedure DemoStrings;
+
+Var
+  S : TStrings;
+  O : TJSONData;
+  C : TComponent;
+
+begin
+  S:=TStringList.Create;
+  try
+    S.Add('One');
+    S.Add('two');
+    S.Add('Three');
+    O:=JS.StreamTStrings(S);
+    DumpObject('Default TStrings',O);
+    O:=JS.StreamTStringsArray(S);
+    DumpObject('TStrings as array',O);
+    C:=TComponent.Create(Nil);
+    try
+      C.Name:='SubComponent';
+      C.Tag:=12;
+      S.Objects[0]:=C;
+      O:=JS.StreamTStringsObject(S);
+      DumpObject('TStrings as object',O);
+      Writeln('TStrings Directly as JSON string, array');
+      Writeln(JS.StringsToJSON(S,False));
+      Writeln();
+      Writeln('TStrings Directly as JSON string, object');
+      Writeln(JS.StringsToJSON(S,True));
+      Writeln();
+      O:=JS.ObjectToJSON(S);
+      DumpObject('Passing TStrings to ObjctToJSON',O);
+      JS.Options:=[jsoTstringsAsArray];
+      O:=JS.ObjectToJSON(S);
+      DumpObject('Passing TStrings to ObjctToJSON (Options:=[jsoTstringsAsArray])',O);
+      JS.Options:=[jsoTstringsAsObject];
+      O:=JS.ObjectToJSON(S);
+      DumpObject('Passing TStrings to ObjctToJSON (Options:=[jsoTstringsAsObject])',O);
+    finally
+      FreeAndNil(C);
+    end;
+  finally
+    FreeAndNil(S);
+  end;
+end;
+
+Procedure DemoCollection;
+
+Var
+  C : TCollection;
+  CC : TCollComponent;
+  O : TJSONData;
+
+begin
+  C:=TCollection.Create(TTestItem);
+  try
+    (C.Add as TTestItem).StrProp:='One';
+    (C.Add as TTestItem).StrProp:='Two';
+    (C.Add as TTestItem).StrProp:='Three';
+    CC:=TCollComponent.Create(Nil);
+    try
+      CC.CollProp:=C;
+      O:=JS.ObjectToJSON(CC);
+      DumpObject('Collection property',O);
+      O:=JS.StreamCollection(C);
+      DumpObject('StreamCollection result',O);
+      O:=JS.ObjectToJSON(C);
+      DumpObject('Passing collection to ObjectToJSON (returns an object)',O);
+      Writeln('Direct Collection to JSON String :');
+      Writeln(JS.CollectionToJSON(C));
+      Writeln;
+    finally
+      FreeAndNil(CC);
+    end;
+  finally
+    FreeAndNil(C);
+  end;
+end;
+
+
+Procedure DemoVariant;
+
+Var
+  V : Variant;
+  O : TJSONData;
+  I : integer;
+
+begin
+  V:=3;
+  O:=JS.StreamVariant(V);
+  DumpObject('Simple integer variant streaming',O);
+  V:=EncodeDate(2010,12,24);
+  O:=JS.StreamVariant(V);
+  DumpObject('Date variant streaming',O);
+  JS.Options:=[jsoDateTimeAsString];
+  O:=JS.StreamVariant(V);
+  DumpObject('Date variant streaming (Options:=[jsoDateTimeAsString];)',O);
+  V:=VarArrayCreate([1,10],varInteger);
+  For I:=1 to 10 do
+    V[i]:=11-I;
+  O:=JS.StreamVariant(V);
+  DumpObject('Variant arrays also work',O);
+  Writeln('Variant to JSON string :');
+  Writeln(JS.VariantToJSON(V));
+  Writeln('Variant to JSON string, with formatting :');
+  JS.Options:=[jsoUseFormatString];
+  Writeln(JS.VariantToJSON(V));
+  JS.Options:=[];
+end;
+
+begin
+  JS:=TJSONStreamer.Create(Nil);
+  try
+    DemoObject;
+    DemoObjectAsString;
+    DemoComponentObject;
+    DemoEnumObject;
+    DemoSetObject;
+    DemoStrings;
+    DemoCollection;
+    DemoVariant;
+    DemoChildObject;
+  Finally
+    FreeAndNil(JS);
+  end;
+end.

+ 19 - 3
packages/fcl-json/src/fpjson.pp

@@ -382,7 +382,7 @@ Type
     // Examine
     procedure Iterate(Iterator : TJSONObjectIterator; Data: TObject);
     function IndexOf(Item: TJSONData): Integer;
-    Function IndexOfName(const AName: TJSONStringType): Integer;
+    Function IndexOfName(const AName: TJSONStringType; CaseInsensitive : Boolean = False): Integer;
     // Manipulate
     Procedure Clear;  override;
     function Add(const AName: TJSONStringType; AValue: TJSONData): Integer; overload;
@@ -416,11 +416,13 @@ Type
   
 Function StringToJSONString(const S : TJSONStringType) : TJSONStringType;
 Function JSONStringToString(const S : TJSONStringType) : TJSONStringType;
-
+Function JSONTypeName(JSONType : TJSONType) : String;
 
 
 implementation
 
+Uses typinfo;
+
 Resourcestring
   SErrCannotConvertFromNull = 'Cannot convert data from Null value';
   SErrCannotConvertToNull = 'Cannot convert data to Null value';
@@ -521,6 +523,11 @@ begin
   Result:=Result+Copy(S,J,I-J+1);
 end;
 
+function JSONTypeName(JSONType: TJSONType): String;
+begin
+  Result:=GetEnumName(TypeInfo(TJSONType),Ord(JSONType));
+end;
+
 
 
 { TJSONData }
@@ -1316,6 +1323,8 @@ begin
     if not (foSingleLineArray in Options) then
       Result:=Result+sLineBreak
     end;
+ if not (foSingleLineArray in Options) then
+    Result:=Result+IndentString(Options, CurrentIndent);
   Result:=Result+']';
 end;
 
@@ -1870,9 +1879,16 @@ begin
   Result:=FHash.IndexOf(Item);
 end;
 
-function TJSONObject.IndexOfName(const AName: TJSONStringType): Integer;
+function TJSONObject.IndexOfName(const AName: TJSONStringType; CaseInsensitive : Boolean = False): Integer;
+
 begin
   Result:=FHash.FindIndexOf(AName);
+  if (Result=-1) and CaseInsensitive then
+    begin
+    Result:=Count-1;
+    While (Result>=0) and (CompareText(Names[Result],AName)<>0) do
+      Dec(Result);
+    end;
 end;
 
 procedure TJSONObject.Clear;

+ 1014 - 0
packages/fcl-json/src/fpjsonrtti.pp

@@ -0,0 +1,1014 @@
+unit fpjsonrtti;
+
+{$mode objfpc}
+
+interface
+
+uses
+  Classes, SysUtils, typinfo, fpjson, rttiutils, jsonparser;
+
+Type
+
+  TJSONStreamEvent = Procedure (Sender : TObject; AObject : TObject; JSON : TJSONObject) of object;
+  TJSONPropertyEvent = Procedure (Sender : TObject; AObject : TObject; Info : PPropInfo; var Res : TJSONData) of object;
+
+  TJSONStreamOption = (jsoStreamChildren,         // If set, children will be streamed in 'Children' Property
+                       jsoEnumeratedAsInteger,    // Write enumerated as integer. Default is string.
+                       jsoSetAsString,            // Write Set as a string. Default is an array.
+                       jsoSetEnumeratedAsInteger, // Write enumerateds in set array as integers.
+                       jsoSetBrackets,            // Use brackets when creating set as array
+                       jsoComponentsInline,       // Always stream components inline. Default is to stream name, unless csSubcomponent in ComponentStyle
+                       jsoTStringsAsArray,        // Stream TStrings as an array of strings. Associated objects are not streamed.
+                       jsoTStringsAsObject,       // Stream TStrings as an object : string = { object }
+                       jsoDateTimeAsString,
+                       jsoUseFormatString);       // Use FormatString when creating JSON strings.
+  TJSONStreamOptions = Set of TJSONStreamOption;
+
+  TJSONFiler = Class(TComponent)
+  Protected
+    Procedure Error(Const Msg : String);
+    Procedure Error(Const FMT : String;  Args : Array of const);
+  end;
+
+  { TJSONStreamer }
+
+  TJSONStreamer = Class(TJSONFiler)
+  private
+    FAfterStreamObject: TJSONStreamEvent;
+    FBeforeStreamObject: TJSONStreamEvent;
+    FChildProperty: String;
+    FDateTimeFormat: String;
+    FOnStreamProperty: TJSONPropertyEvent;
+    FOptions: TJSONStreamOptions;
+    function GetChildProperty: String;
+    function IsChildStored: boolean;
+    function StreamChildren(AComp: TComponent): TJSONArray;
+  protected
+    function StreamClassProperty(Const AObject: TObject): TJSONData; virtual;
+    Function StreamProperty(Const AObject : TObject; Const PropertyName : String) : TJSONData;
+    Function StreamProperty(Const AObject : TObject; PropertyInfo : PPropInfo) : TJSONData;
+    Function FormatDateProp(const DateTime : TDateTime) : TJSONString;
+  Public
+    Constructor Create(AOwner : TComponent); override;
+    Destructor Destroy;override;
+    //
+    // Basic functions
+    //
+    // Use RTTI to stream object.
+    // If AObject is of type TStrings or TCollection, special treatment occurs:
+    // TStrings results in { Strings: [S,S,S] } or { Strings: { "S1" : O1, "S2" : O2 }} depending on Options.
+    // Collection results in { Items: [I,I,I] }
+    Function ObjectToJSON(Const AObject : TObject) : TJSONObject;
+    // Stream a collection - always returns an array
+    function StreamCollection(Const ACollection: TCollection): TJSONArray;
+    // Stream a TStrings instance as an array
+    function StreamTStringsArray(Const AStrings: TStrings): TJSONArray;
+    // Stream a TStrings instance as an object
+    function StreamTStringsObject(Const AStrings: TStrings): TJSONObject;
+    // Stream a TStrings instance. Takes into account Options.
+    function StreamTStrings(Const AStrings: TStrings): TJSONData;
+    // Stream a variant as JSON.
+    function StreamVariant(const Data: Variant): TJSONData; virtual;
+    //
+    // Some utility functions.
+    //
+    // Call ObjectToJSON and convert result to JSON String.
+    Function ObjectToJSONString(AObject : TObject) : TJSONStringType;
+    // Convert TSTrings to JSON string with array or Object.
+    Function StringsToJSON(Const Strings : TStrings; AsObject : Boolean = False) : TJSONStringType;
+    // Convert collection to JSON string
+    Function CollectionToJSON(Const ACollection : TCollection) : TJSONStringType;
+    // Convert variant to JSON String
+    Function VariantToJSON(Const Data : Variant) : TJSONStringType;
+  Published
+    // Format used when formatting DateTime values. Only used in conjunction with jsoDateTimeToString
+    Property DateTimeFormat : String Read FDateTimeFormat Write FDateTimeFormat;
+    // Options to use when streaming
+    Property Options : TJSONStreamOptions Read FOptions Write FOptions;
+    // Called before streaming an object with ObjectToJSON
+    Property BeforeStreamObject : TJSONStreamEvent Read FBeforeStreamObject Write FBeforeStreamObject;
+    // Called After streaming an object with ObjectToJSON
+    Property AfterStreamObject : TJSONStreamEvent Read FAfterStreamObject Write FAfterStreamObject;
+    // Called whenever a property was streamed. If Res is nil on return, no property is added.
+    Property OnStreamProperty : TJSONPropertyEvent Read FOnStreamProperty Write FOnStreamProperty;
+    // Property name to use when streaming child components. Default is "Children"
+    Property ChildProperty : String Read GetChildProperty Write FChildProperty Stored IsChildStored;
+  end;
+
+  { TJSONDeStreamer }
+  TJSONRestorePropertyEvent = Procedure (Sender : TObject; AObject : TObject; Info : PPropInfo; AValue : TJSONData; Var Handled : Boolean) of object;
+  TJSONPropertyErrorEvent = Procedure (Sender : TObject; AObject : TObject; Info : PPropInfo; AValue : TJSONData; Error : Exception; Var Continue : Boolean) of object;
+  TJSONGetObjectEvent = Procedure (Sender : TOBject; AObject : TObject; Info : PPropInfo; AData : TJSONObject; DataName : TJSONStringType; Var AValue : TObject);
+  TJSONDeStreamer = Class(TJSONFiler)
+  private
+    FAfterReadObject: TJSONStreamEvent;
+    FBeforeReadObject: TJSONStreamEvent;
+    FOnGetObject: TJSONGetObjectEvent;
+    FOnPropError: TJSONpropertyErrorEvent;
+    FOnRestoreProp: TJSONRestorePropertyEvent;
+    procedure DeStreamClassProperty(AObject: TObject; PropInfo: PPropInfo; PropData: TJSONData);
+  protected
+    function GetObject(AInstance : TObject; const APropName: TJSONStringType; D: TJSONObject; PropInfo: PPropInfo): TObject;
+    procedure DoRestoreProperty(AObject: TObject; PropInfo: PPropInfo;  PropData: TJSONData); virtual;
+    Function ObjectFromString(Const JSON : TJSONStringType) : TJSONData; virtual;
+    procedure RestoreProperty(AObject: TObject; PropInfo: PPropInfo; PropData: TJSONData);
+  Public
+    Constructor Create(AOwner : TComponent); override;
+    Destructor Destroy; override;
+    // Convert JSON object to properties of AObject
+    Procedure JSONToObject(Const JSON : TJSONStringType; AObject : TObject);
+    Procedure JSONToObject(Const JSON : TJSONObject; AObject : TObject);
+    // Convert JSON object/array to collection.
+    Procedure JSONToCollection(Const JSON : TJSONStringType; ACollection : TCollection);
+    Procedure JSONToCollection(Const JSON : TJSONData; ACollection : TCollection);
+    // Convert JSON array/object/string to TStrings
+    Procedure JSONToStrings(Const JSON : TJSONStringType; AStrings : TSTrings);
+    Procedure JSONToStrings(Const JSON : TJSONData; AStrings : TSTrings);
+    // Convert JSON data to a variant. Supports simple data types and arrays.
+    Function JSONToVariant(Data: TJSONData): Variant;
+    Function JSONToVariant(Data: TJSONStringType): Variant;
+    // Triggered at the start of each call to JSONToObject
+    Property BeforeReadObject : TJSONStreamEvent Read FBeforeReadObject Write FBeforeReadObject;
+    // Triggered at the end of each call to JSONToObject (not if exception happens)
+    Property AfterReadObject : TJSONStreamEvent Read FAfterReadObject Write FAfterReadObject;
+    // Called when a property will be restored. If 'Handled' is True on return, property is considered restored.
+    Property OnRestoreProperty : TJSONRestorePropertyEvent Read FOnRestoreProp Write FOnRestoreProp;
+    // Called when an error occurs when restoring a property. If Continue is False on return, exception is re-raised.
+    Property OnPropertyError : TJSONpropertyErrorEvent Read FOnPropError Write FOnPropError;
+    // Called when a object-typed property must be restored, and the property is Nil. Must return an instance for the property.
+    // Published Properties of the instance will be further restored with available data.
+    Property OngetObject : TJSONGetObjectEvent Read FOnGetObject Write FOnGetObject;
+  end;
+
+  EJSONRTTI = Class(Exception);
+
+
+implementation
+
+uses variants;
+
+ResourceString
+  SErrUnknownPropertyKind     = 'Unknown property kind for property : "%s"';
+  SErrUnsupportedPropertyKind = 'Unsupported property kind for property: "%s"';
+  SErrUnsupportedVariantType  = 'Unsupported variant type : %d';
+  SErrUnsupportedArrayType    = 'JSON array cannot be streamed to object of class "%s"';
+  SErrUnsupportedJSONType     = 'Cannot destream object from JSON data of type "%s"';
+  SErrUnsupportedCollectionType = 'Unsupported JSON type for collections: "%s"';
+  SErrUnsupportedCollectionItemType = 'Array element %d is not a valid type for a collection item: "%s"';
+  SErrUnsupportedStringsItemType = 'Array element %d is not a valid type for a stringlist item: "%s"';
+  SErrUnsupportedStringsType = 'Unsupported JSON type for stringlists: "%s"';
+  SErrUnsupportedStringsObjectType = 'Object Element %s is not a valid type for a stringlist object: "%s"';
+  SErrUnSupportedEnumDataType = 'Unsupported JSON type for enumerated property "%s" : "%s"';
+  SErrUnsupportedVariantJSONType = 'Unsupported JSON type for variant value : "%s"';
+  SErrUnsupportedObjectData = 'Unsupported JSON type for object property: "%s"';
+
+{ TStreamChildrenHelper }
+
+Type
+  TSet = set of 0..31; // Used to (de)stream set properties.
+
+  TStreamChildrenHelper = Class
+  Private
+   FChildren : TJSONArray;
+   FStreamer:TJSONStreamer;
+   procedure StreamChild(AChild: TComponent);
+  public
+    Function StreamChildren(AComponent : TComponent; AStreamer : TJSONStreamer): TJSONArray;
+  end;
+
+  THackComponent = Class(TComponent);
+
+{ TJSONDeStreamer }
+
+function TJSONDeStreamer.ObjectFromString(const JSON: TJSONStringType): TJSONData;
+
+begin
+  With TJSONParser.Create(JSON) do
+    try
+      Result:=Parse;
+    finally
+      Free;
+    end;
+end;
+
+constructor TJSONDeStreamer.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+end;
+
+destructor TJSONDeStreamer.Destroy;
+begin
+  inherited Destroy;
+end;
+
+procedure TJSONDeStreamer.JSONToObject(Const JSON: TJSONStringType; AObject: TObject);
+
+Var
+  D : TJSONData;
+
+begin
+  D:=ObjectFromString(JSON);
+  try
+    If D.JSONType=jtObject then
+      JSONToObject(D as TJSONObject,AObject)
+    else if D.JSONType=jtArray then
+      begin
+      If AObject is TStrings then
+        JSONToStrings(D,AObject as TSTrings)
+      else if AObject is TCollection then
+        JSONTOCollection(D,AObject as TCollection)
+      else
+        Error(SErrUnsupportedArrayType,[AObject.ClassName])
+      end
+    else if (D.JSONType=jtString) and (AObject is TStrings) then
+      JSONToStrings(D,AObject as TStrings)
+    else
+      Error(SErrUnsupportedJSONType,[JSONTypeName(D.JSONType)]);
+  finally
+    FreeAndNil(D);
+  end;
+end;
+
+Function TJSONDeStreamer.JSONToVariant(Data : TJSONData) : Variant;
+
+Var
+  I : integer;
+
+begin
+  Case Data.JSONType of
+    jtNumber :
+      Case TJSONNumber(Data).NumberType of
+        ntFloat   : Result:=Data.AsFloat;
+        ntInteger : Result:=Data.AsInteger;
+        ntInt64   : Result:=Data.Asint64;
+      end;
+    jtString :
+      Result:=Data.AsString;
+    jtBoolean:
+      Result:=Data.AsBoolean;
+    jtNull:
+      Result:=Null;
+    jtArray :
+      begin
+      Result:=VarArrayCreate([0,Data.Count-1],varVariant);
+      For I:=0 to Data.Count-1 do
+        Result[i]:=JSONToVariant(Data.Items[i]);
+      end;
+  else
+    Error(SErrUnsupportedVariantJSONType,[GetEnumName(TypeInfo(TJSONType),Ord(Data.JSONType))]);
+  end;
+end;
+
+function TJSONDeStreamer.JSONToVariant(Data: TJSONStringType): Variant;
+
+Var
+  D : TJSONData;
+
+begin
+  D:=ObjectFromString(Data);
+  try
+    Result:=JSONToVariant(D);
+  finally
+    D.Free;
+  end;
+end;
+
+procedure TJSONDeStreamer.DeStreamClassProperty(AObject : TObject;PropInfo : PPropInfo; PropData : TJSONData);
+
+Var
+  O : TObject;
+
+begin
+  O:=GetObjectProp(AObject,PropInfo);
+  If O is TStrings then
+    JSONToStrings(PropData,O as TStrings)
+  else if (O is TCollection) then
+    JSONToCollection(PropData,O as TCollection)
+  else
+    begin
+    If (O=Nil) then
+      begin
+      If (PropData.JSONType=jtString) then
+        O:=GetObject(AObject,PropData.AsString,Nil,PropInfo)
+      else if (PropData.JSONType=jtObject) then
+        O:=GetObject(AObject,'',PropData as TJSONObject,PropInfo)
+      else
+        Error(SErrUnsupportedObjectData,[JsonTypeName(PropData.JSONType){GetEnumName(TypeInfo(TJSONType),Ord(PropData.JSONType))}]);
+      SetObjectProp(AObject,PropInfo,O);
+      end;
+    If (O<>Nil) and (PropData.JSONType=jtObject) then
+      JSONToObject(PropData as TJSONObject,O);
+    end;
+end;
+
+procedure TJSONDeStreamer.RestoreProperty(AObject : TObject;PropInfo : PPropInfo; PropData : TJSONData);
+
+Var
+  B : Boolean;
+
+begin
+  try
+    B:=Not Assigned(FOnRestoreProp);
+    If Not B then
+      begin
+      FOnRestoreProp(Self,AObject,PropInfo,PropData,B);
+      If B then
+        exit;
+      end;
+    DoRestoreProperty(AObject,PropInfo,PropData);
+  except
+    On E : Exception do
+      If Assigned(FOnPropError) then
+        begin
+        B:=False;
+        FOnPropError(Self,AObject,PropInfo,PropData,E,B);
+        If Not B then
+          Raise;
+        end;
+  end;
+end;
+
+procedure TJSONDeStreamer.DoRestoreProperty(AObject : TObject;PropInfo : PPropInfo; PropData : TJSONData);
+
+Var
+  PI : PPropInfo;
+  TI : PTypeInfo;
+  I,J,S : Integer;
+  D : Double;
+  A : TJSONArray;
+  JS : TJSONStringType;
+begin
+  PI:=PropInfo;
+  TI:=PropInfo^.PropType;
+  case TI^.Kind of
+    tkUnknown :
+      Error(SErrUnknownPropertyKind,[PI^.Name]);
+    tkInteger :
+      SetOrdProp(AObject,PI,PropData.AsInteger);
+    tkInt64 :
+      SetOrdProp(AObject,PI,PropData.AsInt64);
+    tkEnumeration :
+      begin
+      if (PropData.JSONType=jtNumber) then
+        I:=PropData.AsInteger
+      else if PropData.JSONType=jtString then
+        I:=GetEnumValue(TI,PropData.AsString)
+      else
+        Error(SErrUnSupportedEnumDataType,[PI^.Name,GetEnumName(TypeInfo(TJSONType),Ord(PropData.JSONType))]);
+      SetOrdProp(AObject,PI,I);
+      end;
+    tkFloat :
+      begin
+      if (TI=TypeInfo(TDateTime)) and (PropData.JSONType=jtString) then
+        SetFloatProp(AObject,PI,StrToDateTime(PropData.AsString))
+      else
+        SetFloatProp(AObject,PI,PropData.AsFloat)
+      end;
+    tkSet :
+      If PropData.JSONType=jtString then
+        SetSetProp(AObject,PI,PropData.AsString)
+      else if (PropData.JSONType=jtArray) then
+        begin
+        A:=PropData as TJSONArray;
+        TI:=GetTypeData(TI)^.CompType;
+        S:=0;
+        For I:=0 to A.Count-1 do
+          begin
+          if A.types[i]=jtNumber then
+            J:=A.Integers[i]
+          else
+            J:=GetEnumValue(TI,A.strings[i]);
+          TSet(S):=TSet(S)+[j];
+          end;
+        SetOrdProp(AObject,PI,S);
+        end;
+    tkChar:
+      begin
+      JS:=PropData.AsString;
+      If (JS<>'') then
+        SetOrdProp(AObject,PI,Ord(JS[1]));
+      end;
+    tkSString,
+    tkLString,
+    tkAString:
+      SetStrProp(AObject,PI,PropData.AsString);
+    tkWString :
+      SetWideStrProp(AObject,PI,PropData.AsString);
+    tkVariant:
+      SetVariantProp(AObject,PI,JSONToVariant(PropData));
+    tkClass:
+      DeStreamClassProperty(AObject,PI,PropData);
+    tkWChar :
+      begin
+      JS:=PropData.asString;
+      If (JS<>'') then
+        SetOrdProp(AObject,PI,Ord(JS[1]));
+      end;
+    tkBool :
+      SetOrdProp(AObject,PI,Ord(PropData.AsBoolean));
+    tkQWord :
+      SetOrdProp(AObject,PI,Trunc(PropData.AsFloat));
+    tkObject,
+    tkArray,
+    tkRecord,
+    tkInterface,
+    tkDynArray,
+    tkInterfaceRaw,
+    tkProcVar,
+    tkMethod :
+      Error(SErrUnsupportedPropertyKind,[PI^.Name]);
+    tkUString :
+      SetUnicodeStrProp(AObject,PI,PropData.AsString);
+    tkUChar:
+      begin
+      JS:=PropData.asString;
+      If (JS<>'') then
+        SetOrdProp(AObject,PI,Ord(JS[1]));
+      end;
+  end;
+end;
+
+procedure TJSONDeStreamer.JSONToObject(Const JSON: TJSONObject; AObject: TObject);
+Var
+  I,J : Integer;
+  PIL : TPropInfoList;
+
+begin
+  If Assigned(FBeforeReadObject) then
+    FBeforeReadObject(Self,AObject,JSON);
+  If (AObject is TStrings) then
+    JSONToStrings(JSON,AObject as TStrings)
+  else If (AObject is TCollection) then
+    JSONToCollection(JSON, AObject as TCollection)
+  else
+    begin
+    Pil:=TPropInfoList.Create(AObject,tkProperties);
+    try
+      For I:=0 to PIL.Count-1 do
+        begin
+        J:=JSON.IndexOfName(Pil.Items[i]^.Name);
+        If (J<>-1) then
+          RestoreProperty(AObject,PIL.Items[i],JSON.Items[J]);
+        end;
+    finally
+      FreeAndNil(PIL);
+    end;
+    end;
+  If Assigned(FAfterReadObject) then
+    FAfterReadObject(Self,AObject,JSON)
+end;
+
+procedure TJSONDeStreamer.JSONToCollection(const JSON: TJSONStringType;
+  ACollection: TCollection);
+Var
+  D : TJSONData;
+
+begin
+  D:=ObjectFromString(JSON);
+  try
+    JSONToCollection(D,ACollection);
+  finally
+    D.Free;
+  end;
+end;
+
+procedure TJSONDeStreamer.JSONToCollection(const JSON: TJSONData;
+  ACollection: TCollection);
+
+Var
+  I : integer;
+  A : TJSONArray;
+  O : TJSONObject;
+
+begin
+  If (JSON.JSONType=jtArray) then
+    A:=JSON As TJSONArray
+  else if JSON.JSONType=jtObject then
+    A:=(JSON as TJSONObject).Arrays['Items']
+  else
+    Error(SErrUnsupportedCollectionType,[JSONTypeName(JSON.JSONType)]);
+  ACollection.Clear;
+  For I:=0 to A.Count-1 do
+    If (A.Types[i]<>jtObject) then
+      Error(SErrUnsupportedCollectionItemType,[I,JSONTypeName(A.Types[I])])
+    else
+      JSONToObject(A.Objects[i],ACollection.Add);
+end;
+
+procedure TJSONDeStreamer.JSONToStrings(const JSON: TJSONStringType;
+  AStrings: TSTrings);
+Var
+  D : TJSONData;
+
+begin
+  D:=ObjectFromString(JSON);
+  try
+    JSONToStrings(D,AStrings);
+  finally
+    D.Free;
+  end;
+end;
+
+Function TJSONDeStreamer.GetObject(AInstance : TObject; Const APropName : TJSONStringType; D : TJSONObject; PropInfo : PPropInfo) : TObject;
+
+Var
+  C : TClass;
+
+begin
+  Result:=Nil;
+  If Assigned(FOnGetObject) then
+    FOnGetObject(Self,AInstance,PropInfo,D,APropName,Result);
+  If (Result=Nil) and (AInstance is TComponent) and Assigned(PropInfo) then
+     begin
+     C:=GetTypeData(Propinfo^.PropType)^.ClassType;
+     If C.InheritsFrom(TComponent) then
+       Result:=TComponentClass(C).Create(TComponent(AInstance));
+     end;
+end;
+
+procedure TJSONDeStreamer.JSONToStrings(const JSON: TJSONData;
+  AStrings: TSTrings);
+
+Var
+  O  : TJSONObject;
+  D  : TJSONData;
+  I  : Integer;
+  IO : TObject;
+  N  : TJSONStringType;
+
+begin
+  Case JSON.JSONType of
+    jtString:
+      AStrings.Text:=JSON.AsString;
+    jtArray:
+      begin
+      AStrings.Clear;
+      For I:=0 to JSON.Count-1 do
+        begin
+        if not (JSON.Items[i].JSONType=jtString) then
+          Error(SErrUnsupportedStringsItemType,[i,JSONTypeName(JSON.Items[i].JSONType)]);
+        AStrings.Add(JSON.Items[i].AsString);
+        end;
+      end;
+    jtObject:
+      begin
+      O:=JSON As TJSONObject;
+      If (O.Count=1) and (O.Names[0]='Strings') and (O.Items[0].JSONType=jtArray) then
+        JSONToStrings(O.Items[0],AStrings)
+      else
+        begin
+        AStrings.Clear;
+        For I:=0 to O.Count-1 do
+          begin
+          D:=O.Items[i];
+          N:=O.Names[i];
+          If D.JSONType=jtNull then
+            IO:=Nil
+          else if D.JSONType=jtObject then
+            IO:=GetObject(AStrings,N,TJSONOBject(D),Nil)
+          else
+            Error(SErrUnsupportedStringsObjectType,[D,JSONTypeName(D.JSONType)]);
+          AStrings.AddObject(O.Names[i],IO);
+          end;
+        end;
+      end;
+  else
+    Error(SErrUnsupportedStringsType,[JSONTypeName(JSON.JSONType)]);
+  end;
+end;
+
+Procedure TStreamChildrenHelper.StreamChild(AChild : TComponent);
+
+begin
+  FChildren.Add(FStreamer.ObjectToJSON(AChild));
+end;
+
+Function TStreamChildrenHelper.StreamChildren(AComponent : TComponent; AStreamer : TJSONStreamer): TJSONArray;
+
+begin
+  FStreamer:=AStreamer;
+  Result:=TJSONArray.Create;
+  try
+    FChildren:=Result;
+    THackComponent(AComponent).GetChildren(@StreamChild,AComponent);
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+{ TJSONFiler }
+
+procedure TJSONFiler.Error(Const Msg: String);
+begin
+  Raise EJSONRTTI.Create(Name+' : '+Msg);
+end;
+
+procedure TJSONFiler.Error(Const FMT: String; Args: array of const);
+begin
+  Raise EJSONRTTI.CreateFmt(Name+' : '+FMT,Args);
+end;
+
+{ TJSONStreamer }
+
+constructor TJSONStreamer.Create(AOwner: TComponent);
+begin
+  Inherited;
+end;
+
+destructor TJSONStreamer.Destroy;
+begin
+  Inherited;
+end;
+
+
+Function TJSONStreamer.StreamChildren(AComp : TComponent) : TJSONArray;
+
+begin
+  With TStreamChildrenHelper.Create do
+    try
+      Result:=StreamChildren(AComp,Self);
+    finally
+      Free;
+    end;
+end;
+
+function TJSONStreamer.GetChildProperty: String;
+begin
+  Result:=FChildProperty;
+  If (Result='') then
+    Result:='Children';
+end;
+
+function TJSONStreamer.IsChildStored: boolean;
+begin
+  Result:=(GetChildProperty<>'Children');
+end;
+
+function TJSONStreamer.ObjectToJSON(Const AObject: TObject): TJSONObject;
+
+Var
+  PIL : TPropInfoList;
+  PD : TJSONData;
+  I : Integer;
+
+begin
+  Result:=Nil;
+  If (AObject=Nil) then
+    Exit;
+  Result:=TJSONObject.Create;
+  try
+    If Assigned(FBeforeStreamObject) then
+      FBeforeStreamObject(Self,AObject,Result);
+    If AObject is TStrings then
+      Result.Add('Strings',StreamTStrings(Tstrings(AObject)))
+    else If AObject is TCollection then
+      Result.Add('Items',StreamCollection(TCollection(AObject)))
+    else
+      begin
+      PIL:=TPropInfoList.Create(AObject,tkProperties);
+      try
+        For I:=0 to PIL.Count-1 do
+          begin
+          PD:=StreamProperty(AObject,PIL.Items[i]);
+          If (PD<>Nil) then
+            Result.Add(PIL.Items[I]^.Name,PD);
+          end;
+      finally
+        FReeAndNil(Pil);
+      end;
+      If (jsoStreamChildren in Options) and (AObject is TComponent) then
+        Result.Add(ChildProperty,StreamChildren(TComponent(AObject)));
+      If Assigned(FAfterStreamObject) then
+        FAfterStreamObject(Self,AObject,Result);
+      end;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+function TJSONStreamer.StreamProperty(Const AObject: TObject; Const PropertyName : String): TJSONData;
+
+begin
+  Result:=StreamProperty(AObject,GetPropInfo(AObject,PropertyName));
+end;
+
+Function TJSONStreamer.StreamVariant(Const Data : Variant): TJSONData;
+
+Var
+  A : TJSONArray;
+  I : Integer;
+
+begin
+  Result:=Nil;
+  If VarIsArray(Data) then
+    begin
+    A:=TJSONArray.Create;
+    try
+      For I:=VarArrayLowBound(Data,1) to VarArrayHighBound(Data,1) do
+        A.Add(StreamVariant(Data[i]));
+    except
+      FreeAndNil(A);
+      Raise;
+    end;
+    Exit(A);
+    end;
+  If VarIsEmpty(Data) or VarisNull(Data) or (Data=UnAssigned) then
+    Exit(TJSONNull.Create);
+  Case VarType(Data) of
+    varshortint,
+    varbyte,
+    varword,
+    varsmallint,
+    varinteger :
+      Result:=TJSONIntegerNumber.Create(Data);
+    varlongword,
+    varint64 :
+      Result:=TJSONInt64Number.Create(Data);
+    vardecimal,
+    varqword,
+    varsingle,
+    vardouble,
+    varCurrency :
+      Result:=TJSONFloatNumber.Create(Data);
+    varString,
+    varolestr :
+      Result:=TJSONString.Create(Data);
+    varboolean :
+      Result:=TJSONBoolean.Create(Data);
+    varDate :
+      if jsoDateTimeAsString in Options then
+        Result:=FormatDateProp(Data)
+      else
+        Result:=TJSONFloatNumber.Create(Data);
+  else
+    Error(SErrUnsupportedVariantType,[VarType(Data)])
+  end;
+end;
+
+function TJSONStreamer.ObjectToJSONString(AObject: TObject): TJSONStringType;
+
+Var
+  O : TJSONData;
+
+begin
+  O:=ObjectToJSON(AObject);
+  try
+    if (jsoUseFormatString in Options) then
+      Result:=O.FormatJSON()
+    else
+      Result:=O.AsJSON;
+  finally
+    FreeAndNil(O);
+  end;
+end;
+
+function TJSONStreamer.StringsToJSON(Const Strings: TStrings; AsObject: Boolean = False): TJSONStringType;
+
+Var
+  D : TJSONData;
+
+begin
+  If ASObject then
+    D:=StreamTSTringsObject(Strings)
+  else
+    D:=StreamTStringsArray(Strings);
+  try
+    if (jsoUseFormatString in Options) then
+      Result:=D.FormatJSON
+    else
+      Result:=D.AsJSON;
+  finally
+    FreeAndNil(D);
+  end;
+end;
+
+function TJSONStreamer.CollectionToJSON(const ACollection: TCollection
+  ): TJSONStringType;
+
+Var
+  D : TJSONArray;
+
+begin
+  D:=StreamCollection(ACollection);
+  try
+    if (jsoUseFormatString in Options) then
+      Result:=D.FormatJSON()
+    else
+    Result:=D.AsJSON;
+  finally
+    FreeAndNil(D);
+  end;
+end;
+
+function TJSONStreamer.VariantToJSON(const Data: Variant): TJSONStringType;
+
+Var
+  D : TJSONData;
+
+begin
+  D:=StreamVariant(Data);
+  try
+    if (jsoUseFormatString in Options) then
+      Result:=D.FormatJSON()
+    else
+      Result:=D.AsJSON;
+  finally
+    FreeAndNil(D);
+  end;
+end;
+
+Function TJSONStreamer.StreamTStringsArray(Const AStrings : TStrings) : TJSONArray;
+
+Var
+  I : Integer;
+
+begin
+  Result:=TJSONArray.Create;
+  try
+    For I:=0 to AStrings.Count-1 do
+      Result.Add(AStrings[i]);
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+function TJSONStreamer.StreamTStringsObject(Const AStrings: TStrings): TJSONObject;
+
+Var
+  I : Integer;
+  O : TJSONData;
+
+begin
+  Result:=TJSONObject.Create;
+  try
+    For I:=0 to AStrings.Count-1 do
+      begin
+      O:=ObjectToJSON(AStrings.Objects[i]);
+      If O=Nil then
+        O:=TJSONNull.Create;
+      Result.Add(AStrings[i],O);
+      end;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+function TJSONStreamer.StreamTStrings(Const AStrings: TStrings): TJSONData;
+begin
+  If jsoTStringsAsArray in Options then
+    Result:=StreamTStringsArray(AStrings)
+  else If jsoTStringsAsObject in Options then
+    Result:=StreamTStringsObject(AStrings)
+  else
+    Result:=TJSONString.Create(AStrings.Text);
+end;
+
+
+Function TJSONStreamer.StreamCollection(Const ACollection : TCollection) : TJSONArray;
+
+Var
+  I : Integer;
+
+begin
+  Result:=TJSONArray.Create;
+  try
+    For I:=0 to ACollection.Count-1 do
+      Result.Add(ObjectToJSON(ACollection.Items[i]));
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+Function TJSONStreamer.StreamClassProperty(Const AObject : TObject): TJSONData;
+
+Var
+  C : TCollection;
+  I : integer;
+
+begin
+  Result:=Nil;
+  If (AObject=Nil) then
+    Result:=TJSONNull.Create()
+  else if (AObject is TComponent) then
+    begin
+    if (csSubComponent in TComponent(AObject).ComponentStyle) or (jsoComponentsInline in Options) then
+      Result:=ObjectToJSON(AObject)
+    else
+      Result:=TJSONString.Create(TComponent(AObject).Name);
+    end
+  else if (AObject is TStrings) then
+    Result:=StreamTStrings(TStrings(AObject))
+  else if (AObject is TCollection) then
+    Result:=StreamCollection(TCollection(Aobject))
+  else // Normally, this is only TPersistent.
+    Result:=ObjectToJSON(AObject);
+end;
+
+function TJSONStreamer.StreamProperty(Const AObject: TObject; PropertyInfo: PPropInfo): TJSONData;
+
+Var
+  PI : PPropInfo;
+  PT : PTypeInfo;
+  S,I : integer;
+
+begin
+  Result:=Nil;
+  PI:=PropertyInfo;
+  PT:=PI^.PropType;
+  Case PT^.Kind of
+    tkUnknown :
+      Error(SErrUnknownPropertyKind,[PI^.Name]);
+    tkInteger :
+      Result:=TJSONIntegerNumber.Create(GetOrdProp(AObject,PI));
+    tkEnumeration :
+      if jsoEnumeratedAsInteger in Options then
+        Result:=TJSONIntegerNumber.Create(GetOrdProp(AObject,PI))
+      else
+        Result:=TJSONString.Create(GetEnumName(PT,GetOrdProp(AObject,PI)));
+    tkFloat :
+      if (PT=TypeInfo(TDateTime)) and (jsoDateTimeAsString in Options) then
+        Result:=FormatDateProp(GetFloatProp(AObject,PI))
+      else
+        Result:=TJSONFloatNumber.Create(GetFloatProp(AObject,PI));
+    tkSet :
+      If jsoSetAsString in Options then
+        Result:=TJSONString.Create(GetSetProp(AObject,PI,jsoSetBrackets in Options))
+      else
+        begin
+        PT:=GetTypeData(PT)^.CompType;
+        S:=GetOrdProp(AObject,PI);
+        Result:=TJSONArray.Create;
+        try
+          for i:=0 to 31 do
+            if (i in TSet(S)) then
+              if jsoSetEnumeratedAsInteger in Options then
+                TJSONArray(Result).Add(i)
+              else
+                TJSONArray(Result).Add(GetEnumName(PT, i));
+        except
+          FreeAndNil(Result);
+          Raise;
+        end;
+        end;
+    tkChar:
+      Result:=TJSONString.Create(Char(GetOrdProp(AObject,PI)));
+    tkSString,
+    tkLString,
+    tkAString:
+      Result:=TJSONString.Create(GetStrProp(AObject,PI));
+    tkWString :
+      Result:=TJSONString.Create(GetWideStrProp(AObject,PI));
+    tkVariant:
+      Result:=StreamVariant(GetVariantProp(AObject,PI));
+    tkClass:
+      Result:=StreamClassProperty(GetObjectProp(AObject,PI));
+    tkWChar :
+      Result:=TJSONString.Create(WideChar(GetOrdProp(AObject,PI)));
+    tkBool :
+      Result:=TJSONBoolean.Create(GetOrdProp(AObject,PropertyInfo)<>0);
+    tkInt64 :
+      Result:=TJSONInt64Number.Create(GetOrdProp(AObject,PropertyInfo));
+    tkQWord :
+      Result:=TJSONFloatNumber.Create(GetOrdProp(AObject,PropertyInfo));
+    tkObject,
+    tkArray,
+    tkRecord,
+    tkInterface,
+    tkDynArray,
+    tkInterfaceRaw,
+    tkProcVar,
+    tkMethod :
+      Error(SErrUnsupportedPropertyKind,[PI^.Name]);
+    tkUString :
+      Result:=TJSONString.Create(GetWideStrProp(AObject,PI));
+    tkUChar:
+      Result:=TJSONString.Create(UnicodeChar(GetOrdProp(AObject,PI)));
+  end;
+  If Assigned(FOnStreamProperty) then
+    FOnStreamProperty(Self,AObject,PI,Result);
+end;
+
+function TJSONStreamer.FormatDateProp(Const DateTime: TDateTime): TJSONString;
+
+Var
+  S: String;
+
+begin
+  if (DateTimeFormat<>'') then
+    S:=FormatDateTime(DateTimeFormat,DateTime)
+  else if Frac(DateTime)=0 then
+    S:=DateToStr(DateTime)
+  else if Trunc(DateTime)=0 then
+    S:=TimeToStr(DateTime)
+  else
+    S:=DateTimeToStr(DateTime);
+  Result:=TJSONString.Create(S);
+end;
+
+end.
+

+ 27 - 5
packages/fcl-json/tests/testjson.lpi

@@ -1,18 +1,20 @@
 <?xml version="1.0"?>
 <CONFIG>
   <ProjectOptions>
-    <Version Value="8"/>
+    <Version Value="9"/>
     <General>
       <Flags>
         <LRSInOutputDirectory Value="False"/>
       </Flags>
       <SessionStorage Value="InProjectDir"/>
       <MainUnit Value="0"/>
-      <TargetFileExt Value=""/>
     </General>
     <VersionInfo>
-      <StringTable Comments="" CompanyName="" FileDescription="" FileVersion="0.0.0.0" InternalName="" LegalCopyright="" LegalTrademarks="" OriginalFilename="" ProductName="" ProductVersion=""/>
+      <StringTable ProductVersion=""/>
     </VersionInfo>
+    <BuildModes Count="1">
+      <Item1 Name="default" Default="True"/>
+    </BuildModes>
     <PublishOptions>
       <Version Value="2"/>
       <IgnoreBinaries Value="False"/>
@@ -22,6 +24,7 @@
     <RunParams>
       <local>
         <FormatVersion Value="1"/>
+        <CommandLineParams Value="--format=plain --suite=TCJSONStreamer"/>
         <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
       </local>
     </RunParams>
@@ -39,7 +42,7 @@
         <PackageName Value="FCL"/>
       </Item4>
     </RequiredPackages>
-    <Units Count="3">
+    <Units Count="5">
       <Unit0>
         <Filename Value="testjson.pp"/>
         <IsPartOfProject Value="True"/>
@@ -55,19 +58,38 @@
         <IsPartOfProject Value="True"/>
         <UnitName Value="testjsondata"/>
       </Unit2>
+      <Unit3>
+        <Filename Value="testjsonrtti.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="testjsonrtti"/>
+      </Unit3>
+      <Unit4>
+        <Filename Value="../src/fpjsonrtti.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="fpjsonrtti"/>
+      </Unit4>
     </Units>
   </ProjectOptions>
   <CompilerOptions>
     <Version Value="9"/>
     <SearchPaths>
-      <OtherUnitFiles Value="../src/"/>
+      <OtherUnitFiles Value="../src"/>
     </SearchPaths>
     <Parsing>
       <SyntaxOptions>
         <UseAnsiStrings Value="False"/>
       </SyntaxOptions>
     </Parsing>
+    <Linking>
+      <Debugging>
+        <GenerateDebugInfo Value="True"/>
+        <UseHeaptrc Value="True"/>
+      </Debugging>
+    </Linking>
     <Other>
+      <CompilerMessages>
+        <UseMsgFile Value="True"/>
+      </CompilerMessages>
       <CompilerPath Value="$(CompPath)"/>
     </Other>
   </CompilerOptions>

+ 1 - 1
packages/fcl-json/tests/testjson.pp

@@ -18,7 +18,7 @@ program testjson;
 
 uses
   Classes, consoletestrunner, testjsondata, testjsonparser,
-  fpcunitconsolerunner;
+  fpcunitconsolerunner, testjsonrtti, fpjsonrtti;
 type
   { TLazTestRunner }
    TMyTestRunner = class(TTestRunner)

+ 36 - 0
packages/fcl-json/tests/testjsondata.pp

@@ -194,6 +194,7 @@ type
     procedure TestExtract;
     Procedure TestNonExistingAccessError;
     Procedure TestFormat;
+    Procedure TestFind;
   end;
 
 
@@ -1968,6 +1969,41 @@ begin
   end;
 end;
 
+procedure TTestObject.TestFind;
+
+Const
+  A = 'A';
+  S = 'A string';
+  B = 'a';
+  S2 = 'Another string';
+  C = 'c';
+  S3 = 'Yet Another string';
+
+Var
+  J : TJSONObject;
+
+begin
+  J:=TJSONObject.Create([A,S,B,S2,C,S3]);
+  try
+    TestJSONType(J,jtObject);
+    TestIsNull(J,False);
+    TestItemCount(J,3);
+    TestJSONType(J[A],jtString);
+    TestJSONType(J[B],jtString);
+    TestJSON(J,'{ "A" : "'+S+'", "a" : "'+S2+'", "c" : "'+S3+'" }');
+    AssertEquals('Nonexisting, case sensitive',-1,J.IndexOfName('D'));
+    AssertEquals('Nonexisting, case insensitive',-1,J.IndexOfName('D',True));
+    AssertEquals('1 Existing , case sensitive',0,J.IndexOfName(A));
+    AssertEquals('2 Existing exact match, case insensitive',0,J.IndexOfName(A,true));
+    AssertEquals('3 Existing , case sensitive',1,J.IndexOfName(B));
+    AssertEquals('4 Existing exact match, case insensitive',1,J.IndexOfName(B,true));
+    AssertEquals('5 Existing , case sensitive again',2,J.IndexOfName(C));
+    AssertEquals('6 Existing case-insensitive match, case insensitive',2,J.IndexOfName(Uppercase(C),true));
+  finally
+    FreeAndNil(J);
+  end;
+end;
+
 
 procedure TTestObject.TestCreateString;
 

+ 1770 - 0
packages/fcl-json/tests/testjsonrtti.pp

@@ -0,0 +1,1770 @@
+unit testjsonrtti;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, fpcunit, testutils, testregistry, typinfo, fpjson,
+  testcomps, testjsondata, fpjsonrtti;
+
+type
+
+  { TCJSONStreamer }
+
+  TCJSONStreamer = class(TTestJSON)
+  private
+    FRJ : TJSONStreamer;
+    FSR : TJSONObject;
+    FToFree : TObject;
+    FCalled : Boolean;
+    procedure DoStreamProperty1(Sender: TObject; AObject: TObject; Info: PPropInfo; var Res: TJSONData);
+  protected
+    procedure SetUp; override; 
+    procedure TearDown; override;
+    Procedure AssertEquals(AMessage : String; Expected,Actual : TJSONType); overload;
+    Procedure AssertPropCount(ACount : Integer);
+    Function  AssertProperty(APropName : String; AType : TJSONType) : TJSONData;
+    Procedure AssertProp(APropName : String; AValue : Boolean);
+    Procedure AssertProp(APropName : String; AValue : Integer);
+    procedure AssertProp(APropName : String; AValue: String);
+    procedure AssertProp(APropName : String; AValue: TJSONFloat);
+    procedure AssertProp(APropName : String; AValue : Array of String);
+    procedure AssertProp(APropName : String; AValue : Array of Integer);
+    function CreateVariantComp : TVariantComponent;
+    procedure AssertNullProp(APropName : String);
+    Function AssertObjectProp(APropName : String) : TJSONObject;
+    Function AssertArrayProp(APropName : String) : TJSONArray;
+    Function StreamObject(AObject : TObject) : TJSONObject;
+    Property RJ : TJSONStreamer read FRJ;
+    Property SR : TJSONObject Read FSR Write FSR;
+  published
+    procedure TestNil;
+    procedure TestEmpty;
+    procedure TestEmptyComponent;
+    procedure TestWriteBoolean;
+    procedure TestWriteInteger;
+    procedure TestWriteString;
+    procedure TestWriteFloat;
+    procedure TestWriteFloat2;
+    procedure TestWriteFloat3;
+    procedure TestWriteFloat4;
+    procedure TestWriteFloat5;
+    procedure TestEnum1;
+    procedure TestEnum2;
+    Procedure TestSet1;
+    Procedure TestSet2;
+    Procedure TestSet3;
+    Procedure TestSet4;
+    Procedure TestObjectNil;
+    Procedure TestComponentProp1;
+    Procedure TestComponentProp2;
+    Procedure TestCollectionProp1;
+    Procedure TestCollectionProp2;
+    Procedure TestPersistentProp1;
+    Procedure TestStringsProp1;
+    Procedure TestStringsProp2;
+    procedure TestStringsProp3;
+    procedure TestStringsProp4;
+    procedure TestStringsArray;
+    procedure TestStringsObject;
+    procedure TestStringsStream1;
+    procedure TestStringsStream2;
+    procedure TestStringsStream3;
+    procedure TestStringsStream4;
+    procedure TestStringsStream5;
+    procedure TestCollectionStream;
+    procedure TestCollectionStream2;
+    procedure TestOnStreamProperty;
+    Procedure TestDateTimeProp;
+    Procedure TestDateTimeProp2;
+    Procedure TestDateTimeProp3;
+    procedure TestDateTimeProp4;
+    procedure TestDateTimeProp5;
+    procedure TestDateTimeProp6;
+    procedure TestDateTimeProp7;
+    Procedure TestVariantShortint;
+    Procedure TestVariantbyte;
+    Procedure TestVariantword;
+    Procedure TestVariantsmallint;
+    Procedure TestVariantinteger;
+    Procedure TestVariantlongword;
+    Procedure TestVariantint64;
+    Procedure TestVariantqword;
+    Procedure TestVariantsingle;
+    Procedure TestVariantdouble;
+    Procedure TestVariantCurrency;
+    Procedure TestVariantString;
+    Procedure TestVariantolestr;
+    Procedure TestVariantboolean;
+    Procedure TestVariantDate;
+    procedure TestVariantDate2;
+    Procedure TestVariantArray;
+    Procedure TestMultipleProps;
+    Procedure TestObjectToJSONString;
+    Procedure TestStringsToJSONString;
+    Procedure TestCollectionToJSONString;
+    Procedure TestChildren;
+    Procedure TestChildren2;
+  end;
+
+  { TCJSONDeStreamer }
+
+  TCJSONDeStreamer = class(TTestJSON)
+  private
+    FDS : TJSONDeStreamer;
+    FJD : TJSONData;
+    FToFree : TObject;
+    FCalled : Boolean;
+    procedure DeStream(JSON: TJSONStringType; AObject: TObject);
+    procedure DeStream(JSON: TJSONObject; AObject: TObject);
+  protected
+    procedure SetUp; override;
+    procedure TearDown; override;
+    Procedure AssertVarType(Msg : String; AVarType : TVarType; Const Variant : Variant);
+    Property DS : TJSONDeStreamer Read FDS;
+    Property JD : TJSONData Read FJD Write FJD;
+    Property Tofree : TObject Read FToFree Write FToFree;
+  published
+    Procedure TestVariantInteger;
+    Procedure TestVariantFloat;
+    Procedure TestVariantInt64;
+    Procedure TestVariantBoolean;
+    Procedure TestVariantNull;
+    Procedure TestVariantString;
+    Procedure TestVariantArray;
+    procedure TestEmpty;
+    procedure TestBoolean;
+    procedure TestInteger;
+    procedure TestString;
+    procedure TestFloat;
+    procedure TestFloat2;
+    procedure TestFloat3;
+    procedure TestFloat4;
+    procedure TestFloat5;
+    procedure TestEnum1;
+    procedure TestEnum2;
+    Procedure TestSet1;
+    Procedure TestSet2;
+    Procedure TestSet3;
+    Procedure TestSet4;
+    Procedure TestVariantProp;
+    procedure TestCollection;
+    procedure TestCollection2;
+    procedure TestCollection3;
+    procedure TestCollection4;
+    procedure TestCollection5;
+    procedure TestCollection6;
+    procedure TestCollectionProp;
+    procedure TestCollectionProp2;
+    procedure TestStrings;
+    procedure TestStrings2;
+    procedure TestStrings3;
+  end;
+
+implementation
+
+uses variants;
+
+{ TCJSONDeStreamer }
+
+procedure TCJSONDeStreamer.SetUp;
+begin
+  inherited SetUp;
+  FDS:=TJSONDeStreamer.Create(Nil)
+end;
+
+procedure TCJSONDeStreamer.TearDown;
+begin
+  FreeAndNil(FDS);
+  FreeAndNil(FJD);
+  FreeAndNil(FToFree);
+  inherited TearDown;
+end;
+
+procedure TCJSONDeStreamer.AssertVarType(Msg: String; AVarType: TVarType;
+  const Variant: Variant);
+begin
+  AssertEquals(Msg,VarTypeAsText(AVarType),VarTypeAsText(VarType(Variant)));
+end;
+
+procedure TCJSONDeStreamer.TestVariantInteger;
+
+Var
+  V : Variant;
+
+begin
+  JD:=TJSOnIntegerNumber.Create(12);
+  V:=DS.JSONToVariant(JD);
+  AssertVarType('Integer data',varInteger,V);
+  AssertEquals('Integer value',12,V);
+end;
+
+procedure TCJSONDeStreamer.TestVariantFloat;
+Var
+  V : Variant;
+
+begin
+  JD:=TJSOnFloatNumber.Create(1.2);
+  V:=DS.JSONToVariant(JD);
+  AssertVarType('Double data',varDouble,V);
+  AssertEquals('Float value',1.2,V);
+end;
+
+procedure TCJSONDeStreamer.TestVariantInt64;
+Var
+  V : Variant;
+
+begin
+  JD:=TJSONInt64Number.Create(123);
+  V:=DS.JSONToVariant(JD);
+  AssertVarType('Int64 data',varInt64,V);
+  AssertEquals('Int64 value',123,V);
+end;
+
+procedure TCJSONDeStreamer.TestVariantBoolean;
+Var
+  V : Variant;
+
+begin
+  JD:=TJSONBoolean.Create(True);
+  V:=DS.JSONToVariant(JD);
+  AssertVarType('Boolean data',varBoolean,V);
+  AssertEquals('Boolean value',True,V);
+end;
+
+procedure TCJSONDeStreamer.TestVariantNull;
+Var
+  V : Variant;
+
+begin
+  JD:=TJSONNull.Create();
+  V:=DS.JSONToVariant(JD);
+  AssertVarType('Null data',varNull,V);
+end;
+
+procedure TCJSONDeStreamer.TestVariantString;
+Var
+  V : Variant;
+
+begin
+  JD:=TJSONString.Create('A string');
+  V:=DS.JSONToVariant(JD);
+  AssertVarType('String data',varString,V);
+  AssertEquals('String data','A string',V);
+end;
+
+procedure TCJSONDeStreamer.TestVariantArray;
+Var
+  V : Variant;
+begin
+  JD:=TJSONArray.Create([1,2,3]);
+  V:=DS.JSONToVariant(JD);
+  AssertEQuals('Variant is array',true,VarIsArray(V));
+  AssertEquals('Lower bound is zero ',0,VarArrayLowBound(V,1));
+  AssertEquals('Higher bound is count-1 ',2,VarArrayHighBound(V,1));
+  AssertEquals('Element 0 value correct ',1,V[0]);
+  AssertEquals('Element 1 value correct ',2,V[1]);
+  AssertEquals('Element 2 value correct ',3,V[2]);
+end;
+
+procedure TCJSONDeStreamer.TestEmpty;
+begin
+  FTofree:=TComponent.Create(Nil);
+  DS.JSONToObject('{}',FTofree);
+  AssertEquals('Empty name','',TComponent(FToFree).Name);
+  AssertEquals('Empty Tag',0,TComponent(FToFree).Tag);
+end;
+
+procedure TCJSONDeStreamer.DeStream(JSON : TJSONStringType; AObject : TObject);
+
+begin
+  FToFree:=AObject;
+  DS.JSONToObject(JSON,FTofree);
+end;
+
+procedure TCJSONDeStreamer.DeStream(JSON: TJSONObject; AObject: TObject);
+begin
+  FToFree:=AObject;
+  JD:=JSON;
+  DS.JSONToObject(JSON,FTofree);
+end;
+
+procedure TCJSONDeStreamer.TestBoolean;
+
+Var
+  B : TBooleanComponent;
+
+begin
+  B:=TBooleanComponent.Create(Nil);
+  DeStream('{ "BooleanProp" : true }',B);
+  AssertEquals('Correct boolean value',true,B.BooleanProp);
+end;
+
+procedure TCJSONDeStreamer.TestInteger;
+
+Var
+  B : TIntegerComponent;
+
+begin
+  B:=TIntegerComponent.Create(Nil);
+  DeStream('{ "IntProp" : 22 }',B);
+  AssertEquals('Correct integer value',22,B.IntProp);
+end;
+
+procedure TCJSONDeStreamer.TestString;
+
+Var
+  B : TStringComponent;
+
+begin
+  B:=TStringComponent.Create(Nil);
+  DeStream('{ "StringProp" : "A nice string"}',B);
+  AssertEquals('Correct string value','A nice string',B.StringProp);
+end;
+
+procedure TCJSONDeStreamer.TestFloat;
+
+Var
+  B : TSingleComponent;
+
+begin
+  B:=TSingleComponent.Create(Nil);
+  DeStream('{ "SingleProp" : 2.34 }',B);
+  AssertEquals('Correct single value',2.34,B.SingleProp);
+end;
+
+procedure TCJSONDeStreamer.TestFloat2;
+
+Var
+  B : TDoubleComponent;
+
+begin
+  B:=TDoubleComponent.Create(Nil);
+  DeStream('{ "DoubleProp" : 3.45 }',B);
+  AssertEquals('Correct Double value',3.45,B.DoubleProp);
+end;
+
+procedure TCJSONDeStreamer.TestFloat3;
+Var
+  B : TExtendedComponent;
+
+begin
+  B:=TExtendedComponent.Create(Nil);
+  DeStream('{ "ExtendedProp" : 4.56 }',B);
+  AssertEquals('Correct extended value',4.56,B.ExtendedProp);
+end;
+
+procedure TCJSONDeStreamer.TestFloat4;
+
+Var
+  B : TCompComponent;
+
+begin
+  B:=TCompComponent.Create(Nil);
+  DeStream('{ "ExtendedProp" : 5.67 }',B);
+{$ifdef CPUX86_64}
+  AssertEquals('Correct comp value',round(5.67),B.ExtendedProp);
+{$else}
+  AssertEquals('Correct extended value',5.67,B.ExtendedProp);
+{$endif}
+end;
+
+procedure TCJSONDeStreamer.TestFloat5;
+Var
+  B : TCurrencyComponent;
+
+begin
+  B:=TCurrencyComponent.Create(Nil);
+  DeStream('{ "CurrencyProp" : 5.67 }',B);
+  AssertEquals('Correct string value',5.67,B.CurrencyProp);
+end;
+
+procedure TCJSONDeStreamer.TestEnum1;
+
+Var
+  E : TEnumcomponent;
+
+begin
+  E:=TEnumComponent.Create(Nil);
+  DeStream('{ "Dice" : 2 }',E);
+  AssertEquals('Correct value',2,Ord(E.Dice));
+end;
+
+procedure TCJSONDeStreamer.TestEnum2;
+
+Var
+  E : TEnumcomponent;
+
+begin
+  E:=TEnumComponent.Create(Nil);
+  DeStream('{ "Dice" : "three" }',E);
+  AssertEquals('Correct value',GetEnumName(TypeInfo(TDice),Ord(Three)),GetEnumName(TypeInfo(TDice),Ord(E.Dice)));
+end;
+
+procedure TCJSONDeStreamer.TestSet1;
+
+Var
+  T : TSetComponent;
+
+begin
+  T:=TSetComponent.Create(Nil);
+  DeStream('{ "Throw" : "one,two" }',T);
+  If not (T.Throw=[one,two]) then
+    Fail('Correct value for throw');
+end;
+
+procedure TCJSONDeStreamer.TestSet2;
+
+Var
+  T : TSetComponent;
+
+begin
+  T:=TSetComponent.Create(Nil);
+  DeStream('{ "Throw" : "[one,two]" }',T);
+  If not (T.Throw=[one,two]) then
+    Fail('Correct value for throw');
+end;
+
+procedure TCJSONDeStreamer.TestSet3;
+
+Var
+  T : TSetComponent;
+
+begin
+  T:=TSetComponent.Create(Nil);
+  DeStream('{ "Throw" : [ "one", "two"] }',T);
+  If not (T.Throw=[one,two]) then
+    Fail('Correct value for throw');
+end;
+
+procedure TCJSONDeStreamer.TestSet4;
+
+Var
+  T : TSetComponent;
+
+begin
+  T:=TSetComponent.Create(Nil);
+  DeStream('{ "Throw" : [ 0 , 1 ] }',T);
+  If not (T.Throw=[one,two]) then
+    Fail('Correct value for throw');
+end;
+
+procedure TCJSONDeStreamer.TestVariantProp;
+Var
+  V : TVariantComponent;
+
+begin
+  V:=TVariantComponent.Create(Nil);
+  DeStream('{ "VariantProp" : "A string" }',V);
+  AssertEquals('Variant property value','A string',V.VariantProp);
+end;
+
+procedure TCJSONDeStreamer.TestCollection;
+
+Var
+  C : TTestCollection;
+
+begin
+  C:=TTestCollection.Create;
+  DeStream('[ { "StrProp" : "one" }, { "StrProp" : "two" } ]',C);
+  AssertEquals('Item count',2,C.Count);
+  AssertEquals('Class item 0',TTestItem,C.Items[0].ClassType);
+  AssertEquals('Class item 1',TTestItem,C.Items[1].ClassType);
+  AssertEquals('Class item 0','one',TTestItem(C.Items[0]).StrProp);
+  AssertEquals('Class item 1','two',TTestItem(C.Items[1]).StrProp);
+end;
+
+procedure TCJSONDeStreamer.TestCollection2;
+
+Var
+  C : TTestCollection;
+
+begin
+  C:=TTestCollection.Create;
+  DeStream('{ "Items" : [ { "StrProp" : "one" }, { "StrProp" : "two" } ] }',C);
+  AssertEquals('Item count',2,C.Count);
+  AssertEquals('Class item 0',TTestItem,C.Items[0].ClassType);
+  AssertEquals('Class item 1',TTestItem,C.Items[1].ClassType);
+  AssertEquals('Class item 0','one',TTestItem(C.Items[0]).StrProp);
+  AssertEquals('Class item 1','two',TTestItem(C.Items[1]).StrProp);
+end;
+
+procedure TCJSONDeStreamer.TestCollection3;
+
+Var
+  C : TTestCollection;
+
+begin
+  C:=TTestCollection.Create;
+  FTofree:=C;
+  DS.JSONToCollection('{ "Items" : [ { "StrProp" : "one" }, { "StrProp" : "two" } ] }',C);
+  AssertEquals('Item count',2,C.Count);
+  AssertEquals('Class item 0',TTestItem,C.Items[0].ClassType);
+  AssertEquals('Class item 1',TTestItem,C.Items[1].ClassType);
+  AssertEquals('Class item 0','one',TTestItem(C.Items[0]).StrProp);
+  AssertEquals('Class item 1','two',TTestItem(C.Items[1]).StrProp);
+end;
+
+procedure TCJSONDeStreamer.TestCollection4;
+
+Var
+  C : TTestCollection;
+
+begin
+  C:=TTestCollection.Create;
+  FTofree:=C;
+  DS.JSONToCollection('[ { "StrProp" : "one" }, { "StrProp" : "two" } ]',C);
+  AssertEquals('Item count',2,C.Count);
+  AssertEquals('Class item 0',TTestItem,C.Items[0].ClassType);
+  AssertEquals('Class item 1',TTestItem,C.Items[1].ClassType);
+  AssertEquals('Class item 0','one',TTestItem(C.Items[0]).StrProp);
+  AssertEquals('Class item 1','two',TTestItem(C.Items[1]).StrProp);
+end;
+
+procedure TCJSONDeStreamer.TestCollection5;
+
+Var
+  C : TTestCollection;
+
+begin
+  C:=TTestCollection.Create;
+  FTofree:=C;
+  JD:=TJSONArray.Create([TJSONObject.Create(['StrProp','one']),TJSONObject.Create(['StrProp','two'])]);
+  DS.JSONToCollection(JD,C);
+  AssertEquals('Item count',2,C.Count);
+  AssertEquals('Class item 0',TTestItem,C.Items[0].ClassType);
+  AssertEquals('Class item 1',TTestItem,C.Items[1].ClassType);
+  AssertEquals('Class item 0','one',TTestItem(C.Items[0]).StrProp);
+  AssertEquals('Class item 1','two',TTestItem(C.Items[1]).StrProp);
+end;
+
+procedure TCJSONDeStreamer.TestCollection6;
+Var
+  C : TTestCollection;
+
+begin
+  C:=TTestCollection.Create;
+  FTofree:=C;
+  JD:=TJSONObject.Create(['Items',TJSONArray.Create([TJSONObject.Create(['StrProp','one']),TJSONObject.Create(['StrProp','two'])])]);
+  DS.JSONToCollection(JD,C);
+  AssertEquals('Item count',2,C.Count);
+  AssertEquals('Class item 0',TTestItem,C.Items[0].ClassType);
+  AssertEquals('Class item 1',TTestItem,C.Items[1].ClassType);
+  AssertEquals('Class item 0','one',TTestItem(C.Items[0]).StrProp);
+  AssertEquals('Class item 1','two',TTestItem(C.Items[1]).StrProp);
+end;
+
+procedure TCJSONDeStreamer.TestCollectionProp;
+
+Var
+  C : TCollection;
+
+begin
+  JD:=TJSONObject.Create(['Coll',TJSONArray.Create([TJSONObject.Create(['StrProp','one']),TJSONObject.Create(['StrProp','two'])])]);
+  DeStream(JD as TJSONObject,TCollectionComponent.Create(Nil));
+  C:=TCollectionComponent(ToFree).Coll;
+  AssertEquals('Item count',2,C.Count);
+  AssertEquals('Class item 0',TTestItem,C.Items[0].ClassType);
+  AssertEquals('Class item 1',TTestItem,C.Items[1].ClassType);
+  AssertEquals('Class item 0','one',TTestItem(C.Items[0]).StrProp);
+  AssertEquals('Class item 1','two',TTestItem(C.Items[1]).StrProp);
+end;
+
+procedure TCJSONDeStreamer.TestCollectionProp2;
+
+Var
+  C : TCollection;
+
+begin
+
+  DeStream('{ "Coll" : [ { "StrProp" : "one" }, { "StrProp" : "two" } ]}',TCollectionComponent.Create(Nil));
+  C:=TCollectionComponent(ToFree).Coll;
+  AssertEquals('Item count',2,C.Count);
+  AssertEquals('Class item 0',TTestItem,C.Items[0].ClassType);
+  AssertEquals('Class item 1',TTestItem,C.Items[1].ClassType);
+  AssertEquals('Class item 0','one',TTestItem(C.Items[0]).StrProp);
+  AssertEquals('Class item 1','two',TTestItem(C.Items[1]).StrProp);
+end;
+
+procedure TCJSONDeStreamer.TestStrings;
+
+Var
+  S : TStrings;
+
+begin
+  S:=TStringList.Create;
+  FTofree:=S;
+  DS.JSONToStrings('[ "one" , "two" ]',S);
+  AssertEquals('Item count',2,S.Count);
+  AssertEquals('First item','one',S[0]);
+  AssertEquals('First item','two',S[1]);
+end;
+
+procedure TCJSONDeStreamer.TestStrings2;
+
+Var
+  S : TStrings;
+
+begin
+  S:=TStringList.Create;
+  FTofree:=S;
+  DS.JSONToStrings('{ "Strings" : [ "one" , "two" ] }',S);
+  AssertEquals('Item count',2,S.Count);
+  AssertEquals('First item','one',S[0]);
+  AssertEquals('First item','two',S[1]);
+end;
+
+procedure TCJSONDeStreamer.TestStrings3;
+Var
+  S : TStrings;
+
+begin
+  S:=TStringList.Create;
+  FTofree:=S;
+  DS.JSONToStrings('{ "Strings" : [ "one" , "two" ] }',S);
+  AssertEquals('Item count',2,S.Count);
+  AssertEquals('First item','one',S[0]);
+  AssertEquals('First item','two',S[1]);
+end;
+
+{ TCJSONStreamer }
+
+function TCJSONStreamer.StreamObject(AObject: TObject): TJSONObject;
+begin
+  FToFree:=AObject;
+  FSR:=FRJ.ObjectToJSON(AObject);
+  Result:=FSR;
+end;
+
+procedure TCJSONStreamer.DoStreamProperty1(Sender: TObject; AObject: TObject;
+  Info: PPropInfo; var Res: TJSONData);
+begin
+  If (info^.name<>'IntProp') and (info^.name<>'Name') and (info^.name<>'Tag') then
+    Fail('Wrong property');
+  If (info^.name='IntProp') then
+    FreeAndNil(Res);
+  FCalled:=true;
+end;
+
+procedure TCJSONStreamer.SetUp;
+begin
+  Inherited;
+  FRJ:=TJSONStreamer.Create(Nil);
+end;
+
+procedure TCJSONStreamer.TearDown;
+begin
+  FreeAndNil(FSR);
+  FreeAndNil(FRJ);
+  FreeAndNil(FToFree);
+  Inherited;
+end;
+
+procedure TCJSONStreamer.AssertEquals(AMessage: String; Expected, Actual: TJSONType);
+begin
+  AssertEquals(AMessage,GetEnumName(TypeInfo(TJSONType),Ord(Expected)),
+                        GetEnumName(TypeInfo(TJSONType),Ord(Actual)));
+end;
+
+procedure TCJSONStreamer.AssertPropCount(ACount: Integer);
+begin
+  AssertNotNull('Result of streaming available',FSR);
+  If FToFree is TComponent then
+    ACount:=ACount+2; // Tag + Name
+  Writeln(FSR.ASJSON);
+  AssertEquals('Property count correct',ACount,FSR.Count);
+end;
+
+function TCJSONStreamer.AssertProperty(APropName: String; AType: TJSONType
+  ): TJSONData;
+
+Var
+  i : Integer;
+
+begin
+  I:=FSR.IndexOfName(APropName);
+  If (I=-1) then
+    Fail('No property "'+APropName+'" available');
+  Result:=FSR.Items[i];
+  AssertEquals('Property "'+APropName+'" has correct type',GetEnumName(TypeInfo(TJSONType),Ord(AType)),
+                                                           GetEnumName(TypeInfo(TJSONType),Ord(Result.JSONType)));
+end;
+
+procedure TCJSONStreamer.AssertProp(APropName: String; AValue: Boolean);
+begin
+  AssertNotNull('Result of streaming available',FSR);
+  AssertEquals('Result of streaming is TJSONObject',TJSONObject,FSR.ClassType);
+  AssertEquals('Correct value',AValue,AssertProperty(APropName,jtBoolean).AsBoolean);
+end;
+
+procedure TCJSONStreamer.AssertProp(APropName: String; AValue: Integer);
+begin
+  AssertNotNull('Result of streaming available',FSR);
+  AssertEquals('Result of streaming is TJSONObject',TJSONObject,FSR.ClassType);
+  AssertEquals('Correct value',AValue,AssertProperty(APropName,jtNumber).AsInteger);
+end;
+
+procedure TCJSONStreamer.AssertProp(APropName: String; AValue: String);
+begin
+  AssertNotNull('Result of streaming available',FSR);
+  AssertEquals('Result of streaming is TJSONObject',TJSONObject,FSR.ClassType);
+  AssertEquals('Correct value',AValue,AssertProperty(APropName,jtString).AsString);
+end;
+
+procedure TCJSONStreamer.AssertProp(APropName: String; AValue: TJSONFloat);
+begin
+  AssertNotNull('Result of streaming available',FSR);
+  AssertEquals('Result of streaming is TJSONObject',TJSONObject,FSR.ClassType);
+  AssertEquals('Correct value',AValue,AssertProperty(APropName,jtNumber).AsFloat);
+end;
+
+procedure TCJSONStreamer.AssertProp(APropName: String; AValue: array of String
+  );
+Var
+  a : TJSONArray;
+  i : integer;
+
+begin
+  a:=AssertArrayProp(APropName);
+  For I:=Low(AValue) to High(Avalue) do
+    begin
+    AssertEquals('Array element type',jtString,A.Types[i]);
+    AssertEquals('Array value',AValue[i],A.strings[i]);
+    end;
+end;
+
+procedure TCJSONStreamer.AssertProp(APropName: String; AValue: array of Integer
+  );
+Var
+  a : TJSONArray;
+  i : integer;
+
+begin
+  a:=AssertArrayProp(APropName);
+  For I:=Low(AValue) to High(Avalue) do
+    begin
+    AssertEquals('Array element type',jtNumber,A.Types[i]);
+    AssertEquals('Array value',AValue[i],A.Integers[i]);
+    end;
+end;
+
+function TCJSONStreamer.CreateVariantComp: TVariantComponent;
+begin
+  Result:=TVariantComponent.Create(Nil);
+  FTofree:=Result;
+end;
+
+procedure TCJSONStreamer.AssertNullProp(APropName: String);
+begin
+  AssertProperty(APropName,jtNull);
+end;
+
+function TCJSONStreamer.AssertObjectProp(APropName: String): TJSONObject;
+begin
+  Result:=AssertProperty(APropName,jtObject) as TJSONObject;
+end;
+
+function TCJSONStreamer.AssertArrayProp(APropName: String): TJSONArray;
+begin
+  Result:=AssertProperty(APropName,jtArray) as TJSONArray;
+end;
+
+procedure TCJSONStreamer.TestNil;
+begin
+  AssertNull('Nil returns nil',StreamObject(Nil));
+end;
+
+procedure TCJSONStreamer.TestEmpty;
+begin
+  StreamObject(TemptyPersistent.Create);
+  AssertPropCount(0);
+end;
+
+procedure TCJSONStreamer.TestEmptyComponent;
+begin
+  StreamObject(TComponent.Create(nil));
+  AssertPropCount(0);
+end;
+
+procedure TCJSONStreamer.TestWriteBoolean;
+
+begin
+  StreamObject(TBooleanComponent.Create(nil));
+  AssertPropCount(1);
+  AssertProp('BooleanProp',False);
+end;
+
+procedure TCJSONStreamer.TestWriteInteger;
+begin
+  StreamObject(TIntegerComponent.Create(Nil));
+  AssertPropCount(1);
+  AssertProp('IntProp',3);
+end;
+
+procedure TCJSONStreamer.TestWriteString;
+begin
+  StreamObject(TStringComponent.Create(Nil));
+  AssertPropCount(1);
+  AssertProp('StringProp','A string');
+end;
+
+procedure TCJSONStreamer.TestWriteFloat;
+begin
+  StreamObject(TSingleComponent.Create(Nil));
+  AssertPropCount(1);
+  AssertProp('SingleProp',1.23);
+end;
+
+procedure TCJSONStreamer.TestWriteFloat2;
+begin
+  StreamObject(TDoubleComponent.Create(Nil));
+  AssertPropCount(1);
+  AssertProp('DoubleProp',2.34);
+end;
+
+procedure TCJSONStreamer.TestWriteFloat3;
+begin
+  StreamObject(TExtendedComponent.Create(Nil));
+  AssertPropCount(1);
+  AssertProp('ExtendedProp',3.45);
+end;
+
+procedure TCJSONStreamer.TestWriteFloat4;
+begin
+  StreamObject(TCompComponent.Create(Nil));
+  AssertPropCount(1);
+  // Extended is correct, propname is wrong
+  {$ifdef CPUX86_64}
+    AssertProp('ExtendedProp',TJSONFloat(5));
+  {$else}
+    AssertProp('ExtendedProp',4.56);
+  {$endif}
+end;
+
+procedure TCJSONStreamer.TestWriteFloat5;
+begin
+  StreamObject(TCurrencyComponent.Create(Nil));
+  AssertPropCount(1);
+  AssertProp('CurrencyProp',5.67);
+end;
+
+procedure TCJSONStreamer.TestEnum1;
+begin
+  StreamObject(TEnumComponent3.Create(Nil));
+  AssertPropCount(1);
+  AssertProp('Dice',GetEnumName(TypeInfo(TDice),Ord(three)));
+end;
+
+procedure TCJSONStreamer.TestEnum2;
+begin
+  RJ.Options:=[jsoEnumeratedAsInteger];
+  StreamObject(TEnumComponent3.Create(Nil));
+  AssertProp('Dice',Ord(three));
+end;
+
+procedure TCJSONStreamer.TestSet1;
+begin
+  StreamObject(TSetComponent.Create(Nil));
+  AssertPropCount(1);
+  AssertProp('Throw',['two','five']);
+end;
+
+procedure TCJSONStreamer.TestSet2;
+begin
+  RJ.Options:=[jsoSetAsString];
+  StreamObject(TSetComponent.Create(Nil));
+  AssertPropCount(1);
+  AssertProp('Throw','two,five');
+end;
+
+procedure TCJSONStreamer.TestSet3;
+begin
+  RJ.Options:=[jsoSetAsString,jsoSetBrackets];
+  StreamObject(TSetComponent.Create(Nil));
+  AssertPropCount(1);
+  AssertProp('Throw','[two,five]');
+end;
+
+procedure TCJSONStreamer.TestSet4;
+begin
+  RJ.Options:=[jsoSetEnumeratedAsInteger];
+  StreamObject(TSetComponent.Create(Nil));
+  AssertPropCount(1);
+  AssertProp('Throw',[Ord(two),Ord(five)]);
+end;
+
+procedure TCJSONStreamer.TestObjectNil;
+
+Var
+  P : TOwnedComponent;
+
+begin
+  P:=TOwnedComponent.Create(Nil);
+  P.CompProp.Free;
+  P.CompProp:=Nil;
+  StreamObject(P);
+  AssertPropCount(1);
+  AssertNullProp('CompProp');
+end;
+
+procedure TCJSONStreamer.TestComponentProp1;
+begin
+  StreamObject(TOwnedComponent.Create(Nil));
+  AssertPropCount(1);
+  AssertProp('CompProp','SubComponent');
+end;
+
+procedure TCJSONStreamer.TestComponentProp2;
+
+Var
+  C : TOwnedComponent;
+  F : TJSONObject;
+
+begin
+  RJ.Options:=[jsoComponentsInline];
+  C:=TOwnedComponent.Create(Nil);
+  StreamObject(C);
+  AssertPropCount(1);
+  F:=SR;
+  try
+    SR:=AssertObjectProp('CompProp');
+    AssertPropCount(1);
+    AssertProp('Name','SubComponent');
+    Assertprop('Tag',0);
+    AssertProp('IntProp',3);
+  finally
+    SR:=F;
+  end;
+end;
+
+procedure TCJSONStreamer.TestCollectionProp1;
+
+Var
+  C : TCollectionComponent;
+  F : TJSONObject;
+  A : TJSONArray;
+
+begin
+  C:=TCollectionComponent2.Create(Nil);
+  StreamObject(C);
+  AssertPropCount(1);
+  F:=SR;
+  try
+    A:=AssertArrayProp('Coll');
+    AssertEquals('Collection item cound',3,A.Count);
+    AssertEquals('Item 0 is object',jtObject,A.Types[0]);
+    SR:=A.Objects[0];
+    FToFree:=SR;
+    AssertPropCount(1);
+    AssertProp('StrProp','First');
+    AssertEquals('Item 1 is object',jtObject,A.Types[1]);
+    SR:=A.Objects[1];
+    FToFree:=SR;
+    AssertPropCount(1);
+    AssertProp('StrProp','Second');
+    AssertEquals('Item 2 is object',jtObject,A.Types[2]);
+    SR:=A.Objects[2];
+    FToFree:=SR;
+    AssertPropCount(1);
+    AssertProp('StrProp','Third');
+  finally
+    SR:=F;
+    FToFree:=C;
+  end;
+end;
+
+procedure TCJSONStreamer.TestCollectionProp2;
+
+Var
+  C : TCollectionComponent;
+  F : TJSONObject;
+  A : TJSONArray;
+
+begin
+  C:=TCollectionComponent.Create(Nil);
+  StreamObject(C);
+  AssertPropCount (1);
+  A:=AssertArrayProp('Coll');
+  AssertEquals('Collection item count',0,A.Count);
+end;
+
+procedure TCJSONStreamer.TestPersistentProp1;
+
+var
+  P : TPersistentComponent;
+  F : TJSONObject;
+
+begin
+  P:=TPersistentComponent.Create(Nil);
+  StreamObject(P);
+  AssertPropCount(1);
+  F:=SR;
+  try
+    SR:=AssertObjectProp('Persist');
+    FToFree:=P.Persist;
+    AssertPropCount(2);
+    AssertProp('AString','A persistent string');
+    AssertProp('AInteger',3);
+  finally
+    FToFree:=P;
+    SR:=F;
+  end;
+end;
+
+procedure TCJSONStreamer.TestStringsProp1;
+
+Var
+  A : TJSONArray;
+begin
+  RJ.Options:=[jsoTstringsAsArray];
+  StreamObject(TStringsCOmponent.Create(Nil));
+  AssertPropCount(1);
+  AssertProp('StringsProp',['One','Two','Three']);
+end;
+
+procedure TCJSONStreamer.TestStringsProp2;
+
+Var
+  A : TJSONArray;
+begin
+  StreamObject(TStringsCOmponent.Create(Nil));
+  AssertPropCount(1);
+  AssertProp('StringsProp','One'+sLineBreak+'Two'+sLineBreak+'Three'+sLineBreak);
+end;
+
+procedure TCJSONStreamer.TestStringsProp3;
+
+Var
+  O : TJSONObject;
+  S : TStringsComponent;
+
+begin
+  S:=TStringsCOmponent.Create(Nil);
+  RJ.Options:=[jsoTstringsAsObject];
+  StreamObject(S);
+  AssertPropCount(1);
+  O:=SR;
+  SR:=AssertObjectprop('StringsProp');
+  FTofree:=Nil;
+  try
+    AssertNullProp('One');
+    AssertNullProp('Two');
+    AssertNullProp('Three');
+  finally
+    SR:=o;
+    FToFree:=S;
+  end;
+end;
+
+procedure TCJSONStreamer.TestStringsProp4;
+
+Var
+  O,SP : TJSONObject;
+  S : TStringsComponent;
+
+begin
+  S:=TStringsCOmponent.Create(Nil);
+  S.StringsProp.Objects[0]:=TEmptyPersistent.Create;
+  S.StringsProp.Objects[1]:=TEmptyPersistent.Create;
+  S.StringsProp.Objects[2]:=TEmptyPersistent.Create;
+  try
+    RJ.Options:=[jsoTstringsAsObject];
+    StreamObject(S);
+    AssertPropCount(1);
+    O:=SR;
+    SP:=AssertObjectprop('StringsProp');
+    SR:=SP;
+    FTofree:=Nil;
+    try
+      SR:=AssertObjectProp('One');
+      AssertPropCount(0);
+      SR:=SP;
+      SR:=AssertObjectProp('Two');
+      AssertPropCount(0);
+      SR:=SP;
+      SR:=AssertObjectProp('Three');
+      AssertPropCount(0);
+    finally
+      SR:=o;
+      FToFree:=S;
+    end;
+  finally
+    S.StringsProp.Objects[0].Free;
+    S.StringsProp.Objects[1].Free;
+    S.StringsProp.Objects[2].Free;
+  end;
+end;
+
+procedure TCJSONStreamer.TestStringsArray;
+
+Var
+  O : TJSONArray;
+  S : TStringList;
+
+begin
+  S:=TStringList.create;
+  try
+    S.Add('one');
+    O:=RJ.StreamTStringsArray(S);
+    try
+      AssertEquals('one element',1,O.Count);
+      AssertEquals('string type',jtString,O.Types[0]);
+      AssertEquals('string value','one',O.Strings[0]);
+    finally
+      FreeAndNil(O);
+    end;
+  finally
+    S.Free;
+  end;
+end;
+
+procedure TCJSONStreamer.TestStringsObject;
+
+Var
+  O : TJSONObject;
+  S : TStringList;
+
+begin
+  S:=TStringList.create;
+  try
+    S.AddObject('one',TEmptyPersistent.Create);
+    O:=RJ.StreamTStringsObject(S);
+    try
+      AssertEquals('one element',1,O.Count);
+      AssertEquals('Have property',0,O.IndexOfName('one'));
+      AssertEquals('string type',jtObject,O.Types['one']);
+      AssertEquals('string value','one',O.Names[0]);
+    finally
+      FreeAndNil(O);
+    end;
+  finally
+    S.Objects[0].FRee;
+    S.Free;
+  end;
+end;
+
+procedure TCJSONStreamer.TestStringsStream1;
+
+Var
+  D: TJSONData;
+  O : TJSONArray;
+  S : TStringList;
+
+begin
+  S:=TStringList.create;
+  try
+    S.Add('one');
+    RJ.Options:=[jsoTstringsAsArray];
+    D:=RJ.StreamTStrings(S);
+    try
+      AssertEquals('Correct type',jtArray,D.JSONType);
+      O:=D as TJSONArray;
+      AssertEquals('one element',1,O.Count);
+      AssertEquals('string type',jtString,O.Types[0]);
+      AssertEquals('string value','one',O.Strings[0]);
+    finally
+      FreeAndNil(O);
+    end;
+  finally
+    S.Free;
+  end;
+end;
+
+procedure TCJSONStreamer.TestStringsStream2;
+
+Var
+  D : TJSONData;
+  O : TJSONObject;
+  S : TStringList;
+
+begin
+  S:=TStringList.create;
+  try
+    S.AddObject('one',TEmptyPersistent.Create);
+    RJ.Options:=[jsoTstringsAsObject];
+    D:=RJ.StreamTstrings(S);
+    try
+      AssertEquals('Correct type',jtObject,D.JSONType);
+      O:=D as TJSONObject;
+      AssertEquals('one element',1,O.Count);
+      AssertEquals('Have property',0,O.IndexOfName('one'));
+      AssertEquals('string type',jtObject,O.Types['one']);
+      AssertEquals('string value','one',O.Names[0]);
+    finally
+      SR:=O;
+    end;
+  finally
+    S.Objects[0].FRee;
+    S.Free;
+  end;
+end;
+
+procedure TCJSONStreamer.TestStringsStream3;
+Var
+  O : TJSONObject;
+  S : TStringList;
+
+begin
+  S:=TStringList.create;
+  try
+    S.AddObject('one',TEmptyPersistent.Create);
+    RJ.Options:=[jsoTstringsAsObject];
+    SR:=RJ.ObjectToJSON(S);
+    O:=AssertObjectProp('Strings');
+    AssertEquals('one element',1,O.Count);
+    AssertEquals('Have property',0,O.IndexOfName('one'));
+    AssertEquals('string type',jtObject,O.Types['one']);
+    AssertEquals('string value','one',O.Names[0]);
+  finally
+    S.Objects[0].FRee;
+    S.Free;
+  end;
+end;
+
+procedure TCJSONStreamer.TestStringsStream4;
+Var
+  O : TJSONObject;
+  S : TStringList;
+
+begin
+  S:=TStringList.create;
+  try
+    S.AddObject('one',TEmptyPersistent.Create);
+    SR:=RJ.ObjectToJSON(S);
+    AssertProp('Strings','one'+sLinebreak);
+  finally
+    S.Objects[0].FRee;
+    S.Free;
+  end;
+end;
+
+procedure TCJSONStreamer.TestStringsStream5;
+Var
+  D : TJSONData;
+  S : TStringList;
+
+begin
+  S:=TStringList.create;
+  try
+    S.AddObject('one',TEmptyPersistent.Create);
+    D:=RJ.StreamTstrings(S);
+    try
+      AssertEquals('String data',jtString,D.JSONType);
+      AssertEquals('String value','one'+sLineBreak,D.AsString);
+    finally
+      D.free;
+    end;
+  finally
+    S.Objects[0].FRee;
+    S.Free;
+  end;
+end;
+
+procedure TCJSONStreamer.TestCollectionStream;
+
+Var
+  C : TTestCollection;
+  A : TJSONArray;
+
+begin
+  C:=TTestCollection.Create;
+  FToFree:=C;
+  TTestItem(C.Add).StrProp:='One';
+  TTestItem(C.Add).StrProp:='Two';
+  A:=RJ.StreamCollection(C);
+  try
+    AssertNotNull('Have result',A);
+    AssertEquals('2 items',2,A.Count);
+    AssertEquals('Type item 0,',jtObject,A.Types[0]);
+    AssertEquals('Type item 1,',jtObject,A.Types[1]);
+    SR:=A.Objects[0];
+    AssertPropCount(1);
+    AssertProp('StrProp','One');
+    SR:=A.Objects[1];
+    AssertPropCount(1);
+    AssertProp('StrProp','Two');
+    SR:=Nil;
+  finally
+    FreeAndNil(A);
+  end;
+end;
+
+procedure TCJSONStreamer.TestCollectionStream2;
+
+Var
+  C : TTestCollection;
+  A : TJSONArray;
+  o : TJSONObject;
+
+begin
+  C:=TTestCollection.Create;
+  TTestItem(C.Add).StrProp:='One';
+  TTestItem(C.Add).StrProp:='Two';
+  FToFree:=C;
+  StreamObject(C);
+  O:=SR;
+  try
+    A:=AssertProperty('Items',jtArray) as TJSONArray;
+    AssertNotNull('Have result',A);
+    AssertEquals('2 items',2,A.Count);
+    AssertEquals('Type item 0,',jtObject,A.Types[0]);
+    AssertEquals('Type item 1,',jtObject,A.Types[1]);
+    SR:=A.Objects[0];
+    AssertPropCount(1);
+    AssertProp('StrProp','One');
+    SR:=A.Objects[1];
+    AssertPropCount(1);
+    AssertProp('StrProp','Two');
+    SR:=Nil;
+  finally
+    SR:=O;
+  end;
+end;
+
+procedure TCJSONStreamer.TestOnStreamProperty;
+begin
+  RJ.OnStreamProperty:=@DoStreamProperty1;
+  StreamObject(TIntegerComponent.Create(Nil));
+  AssertPropCount(0);
+end;
+
+procedure TCJSONStreamer.TestDateTimeProp;
+
+Var
+  D : Double;
+begin
+  StreamObject(TDateTimeComponent.Create(Nil));
+  D:=EncodeDate(1996,8,1);
+  AssertPropCount(1);
+  AssertProp('DateTimeProp',D);
+end;
+
+procedure TCJSONStreamer.TestDateTimeProp2;
+Var
+  D : Double;
+begin
+  StreamObject(TDateTimeComponent2.Create(Nil));
+  D:=EncodeTime(23,20,0,0);
+  AssertPropCount(1);
+  AssertProp('DateTimeProp',D);
+end;
+
+procedure TCJSONStreamer.TestDateTimeProp3;
+Var
+  D : Double;
+begin
+  StreamObject(TDateTimeComponent3.Create(Nil));
+  D:=EncodeDate(1996,8,1)+EncodeTime(23,20,0,0);
+  AssertPropCount(1);
+  AssertProp('DateTimeProp',D);
+end;
+
+procedure TCJSONStreamer.TestDateTimeProp4;
+
+begin
+  RJ.Options:=[jsoDateTimeAsString];
+  StreamObject(TDateTimeComponent.Create(Nil));
+  AssertPropCount(1);
+  AssertProp('DateTimeProp',DateToStr(EncodeDate(1996,8,1)));
+end;
+
+procedure TCJSONStreamer.TestDateTimeProp5;
+
+begin
+  RJ.Options:=[jsoDateTimeAsString];
+  StreamObject(TDateTimeComponent2.Create(Nil));
+  AssertPropCount(1);
+  AssertProp('DateTimeProp',TimeToStr(EncodeTime(23,20,0,0)));
+end;
+
+procedure TCJSONStreamer.TestDateTimeProp6;
+
+begin
+  RJ.Options:=[jsoDateTimeAsString];
+  StreamObject(TDateTimeComponent3.Create(Nil));
+  AssertPropCount(1);
+  AssertProp('DateTimeProp',DateTimeToStr(EncodeDate(1996,8,1)+EncodeTime(23,20,0,0)));
+end;
+
+procedure TCJSONStreamer.TestDateTimeProp7;
+begin
+  RJ.Options:=[jsoDateTimeAsString];
+  RJ.DateTimeFormat:='hh:nn';
+  StreamObject(TDateTimeComponent3.Create(Nil));
+  AssertPropCount(1);
+  AssertProp('DateTimeProp',FormatDateTime('hh:nn',EncodeDate(1996,8,1)+EncodeTime(23,20,0,0)));
+end;
+
+procedure TCJSONStreamer.TestVariantShortint;
+
+Var
+  i : ShortInt;
+  C : TVariantComponent;
+
+begin
+  i:=3;
+  C:=CreateVariantComp;
+  C.VariantProp:=i;
+  AssertEquals('Variant type',VarTypeAsText(varshortint),VarTypeAsText(VarType(C.VariantProp)));
+  StreamObject(FTofree);
+  AssertPropCount(1);
+  AssertProp('VariantProp',3);
+end;
+
+procedure TCJSONStreamer.TestVariantbyte;
+Var
+  i : Byte;
+  C : TVariantComponent;
+
+begin
+  i:=3;
+  C:=CreateVariantComp;
+  C.VariantProp:=i;
+  AssertEquals('Variant type',VarTypeAsText(varByte),VarTypeAsText(VarType(C.VariantProp)));
+  StreamObject(FTofree);
+  AssertPropCount(1);
+  AssertProp('VariantProp',3);
+end;
+
+procedure TCJSONStreamer.TestVariantword;
+
+Var
+  i : Word;
+  C : TVariantComponent;
+
+begin
+  i:=3;
+  C:=CreateVariantComp;
+  C.VariantProp:=i;
+  AssertEquals('Variant type',VarTypeAsText(varWord),VarTypeAsText(VarType(C.VariantProp)));
+  StreamObject(FTofree);
+  AssertPropCount(1);
+  AssertProp('VariantProp',3);
+end;
+
+procedure TCJSONStreamer.TestVariantsmallint;
+
+Var
+  i : Smallint;
+  C : TVariantComponent;
+
+begin
+  i:=3;
+  C:=CreateVariantComp;
+  C.VariantProp:=i;
+  AssertEquals('Variant type',VarTypeAsText(varSmallint),VarTypeAsText(VarType(C.VariantProp)));
+  StreamObject(FTofree);
+  AssertPropCount(1);
+  AssertProp('VariantProp',3);
+end;
+
+procedure TCJSONStreamer.TestVariantinteger;
+Var
+  i : Integer;
+  C : TVariantComponent;
+
+begin
+  i:=3;
+  C:=CreateVariantComp;
+  C.VariantProp:=i;
+  AssertEquals('Variant type',VarTypeAsText(varInteger),VarTypeAsText(VarType(C.VariantProp)));
+  StreamObject(FTofree);
+  AssertPropCount(1);
+  AssertProp('VariantProp',3);
+end;
+
+procedure TCJSONStreamer.TestVariantlongword;
+
+Var
+  i : Cardinal;
+  C : TVariantComponent;
+
+begin
+  i:=3;
+  C:=CreateVariantComp;
+  C.VariantProp:=i;
+  AssertEquals('Variant type',VarTypeAsText(varLongword),VarTypeAsText(VarType(C.VariantProp)));
+  StreamObject(FTofree);
+  AssertPropCount(1);
+  AssertProp('VariantProp',3);
+end;
+
+procedure TCJSONStreamer.TestVariantint64;
+Var
+  i : Int64;
+  C : TVariantComponent;
+
+begin
+  i:=3;
+  C:=CreateVariantComp;
+  C.VariantProp:=i;
+  AssertEquals('Variant type',VarTypeAsText(varInt64),VarTypeAsText(VarType(C.VariantProp)));
+  StreamObject(FTofree);
+  AssertPropCount(1);
+  AssertProp('VariantProp',3);
+end;
+
+procedure TCJSONStreamer.TestVariantqword;
+Var
+  i : QWord;
+  C : TVariantComponent;
+
+begin
+  i:=3;
+  C:=CreateVariantComp;
+  C.VariantProp:=i;
+  AssertEquals('Variant type',VarTypeAsText(varQWord),VarTypeAsText(VarType(C.VariantProp)));
+  StreamObject(FTofree);
+  AssertPropCount(1);
+  AssertProp('VariantProp',3);
+end;
+
+procedure TCJSONStreamer.TestVariantsingle;
+Var
+  i : Single;
+  C : TVariantComponent;
+
+begin
+  i:=3.14;
+  C:=CreateVariantComp;
+  C.VariantProp:=VarAsType(3.14,varSingle);
+  AssertEquals('Variant type',VarTypeAsText(varSingle),VarTypeAsText(VarType(C.VariantProp)));
+  StreamObject(FTofree);
+  AssertPropCount(1);
+  AssertProp('VariantProp',3.14);
+end;
+
+procedure TCJSONStreamer.TestVariantdouble;
+
+Var
+  i : Double;
+  C : TVariantComponent;
+
+begin
+  i:=3.14;
+  C:=CreateVariantComp;
+  C.VariantProp:=i;
+  AssertEquals('Variant type',VarTypeAsText(varDouble),VarTypeAsText(VarType(C.VariantProp)));
+  StreamObject(FTofree);
+  AssertPropCount(1);
+  AssertProp('VariantProp',3.14);
+end;
+
+procedure TCJSONStreamer.TestVariantCurrency;
+Var
+  i : Currency;
+  C : TVariantComponent;
+
+begin
+  i:=3.14;
+  C:=CreateVariantComp;
+  C.VariantProp:=i;
+  AssertEquals('Variant type',VarTypeAsText(varCurrency),VarTypeAsText(VarType(C.VariantProp)));
+  StreamObject(FTofree);
+  AssertPropCount(1);
+  AssertProp('VariantProp',3.14);
+end;
+
+procedure TCJSONStreamer.TestVariantString;
+
+Var
+  i : String;
+  C : TVariantComponent;
+
+begin
+  i:='3.14';
+  C:=CreateVariantComp;
+  C.VariantProp:=i;
+  AssertEquals('Variant type',VarTypeAsText(varString),VarTypeAsText(VarType(C.VariantProp)));
+  StreamObject(FTofree);
+  AssertPropCount(1);
+  AssertProp('VariantProp','3.14');
+end;
+
+procedure TCJSONStreamer.TestVariantolestr;
+
+Var
+  i : String;
+  C : TVariantComponent;
+
+begin
+  i:='3.14';
+  C:=CreateVariantComp;
+  C.VariantProp:=VarAsType(i,varOleStr);
+  AssertEquals('Variant type',VarTypeAsText(varOleStr),VarTypeAsText(VarType(C.VariantProp)));
+  StreamObject(FTofree);
+  AssertPropCount(1);
+  AssertProp('VariantProp','3.14');
+end;
+
+procedure TCJSONStreamer.TestVariantboolean;
+Var
+  i : Boolean;
+  C : TVariantComponent;
+
+begin
+  i:=True;
+  C:=CreateVariantComp;
+  C.VariantProp:=i;
+  AssertEquals('Variant type',VarTypeAsText(varBoolean),VarTypeAsText(VarType(C.VariantProp)));
+  StreamObject(FTofree);
+  AssertPropCount(1);
+  AssertProp('VariantProp',True);
+end;
+
+procedure TCJSONStreamer.TestVariantDate;
+
+Var
+  i : TDateTime;
+  C : TVariantComponent;
+
+begin
+  i:=EncodeDate(2010,12,23);
+  C:=CreateVariantComp;
+  C.VariantProp:=i;
+  AssertEquals('Variant type',VarTypeAsText(varDate),VarTypeAsText(VarType(C.VariantProp)));
+  StreamObject(FTofree);
+  AssertPropCount(1);
+  AssertProp('VariantProp',EncodeDate(2010,12,23));
+end;
+
+procedure TCJSONStreamer.TestVariantDate2;
+
+Var
+  i : TDateTime;
+  C : TVariantComponent;
+
+begin
+  RJ.Options:=[jsoDateTimeAsString];
+  i:=EncodeDate(2010,12,23);
+  C:=CreateVariantComp;
+  C.VariantProp:=i;
+  AssertEquals('Variant type',VarTypeAsText(varDate),VarTypeAsText(VarType(C.VariantProp)));
+  StreamObject(FTofree);
+  AssertPropCount(1);
+  AssertProp('VariantProp',DateToStr(EncodeDate(2010,12,23)));
+end;
+
+procedure TCJSONStreamer.TestVariantArray;
+Var
+  i : Integer;
+  V : Variant;
+  C : TVariantComponent;
+  A : TJSONArray;
+
+begin
+  V:=VarArrayCreate([1,10],varInteger);
+  For I:=1 to 10 do
+    V[i]:=11-I;
+  C:=CreateVariantComp;
+  C.VariantProp:=V;
+  StreamObject(FTofree);
+  AssertPropCount(1);
+  A:=AssertProperty('VariantProp',jtArray) as TJSONArray;
+  AssertEquals('10 elements in array',10,A.Count);
+  For I:=1 to 10 do
+    begin
+    assertEquals('Type of element',jtNumber,A.Types[i-1]);
+    AssertEquals('Value of element',11-i,A.Integers[i-1]);
+    end;
+end;
+
+procedure TCJSONStreamer.TestMultipleProps;
+begin
+  StreamObject(TMultipleComponent.Create(Nil));
+  AssertPropCount(5);
+  AssertProp('IntProp',1);
+  Assertprop('StringProp','A String');
+  AssertProp('CurrencyProp',2.3);
+  AssertProp('Throw',['three','four']);
+  AssertProp('Dice','two');
+end;
+
+procedure TCJSONStreamer.TestObjectToJSONString;
+begin
+  StreamObject(TIntegerComponent.Create(Nil));
+  AssertEquals('Correct stream',SR.AsJSON,RJ.ObjectToJSONString(FToFree));
+end;
+
+procedure TCJSONStreamer.TestStringsToJSONString;
+Var
+  S : TStrings;
+begin
+  S:=TStringList.Create;
+  try
+    S.Add('one');
+    S.Add('two');
+    S.Add('three');
+    AssertEquals('StringsToJSONString','["one", "two", "three"]',RJ.StringsToJSON(S));
+    AssertEquals('StringsToJSONString','{ "one" : null, "two" : null, "three" : null }',RJ.StringsToJSON(S,True));
+  finally
+    FreeAndNil(S);
+  end;
+end;
+
+procedure TCJSONStreamer.TestCollectionToJSONString;
+
+Var
+  C : TTestCollection;
+
+begin
+  C:=TTestCollection.Create;
+  try
+    (C.Add as TTestItem).StrProp:='one';
+    (C.Add as TTestItem).StrProp:='two';
+    (C.Add as TTestItem).StrProp:='three';
+    AssertEquals('CollectionToJSON','[{ "StrProp" : "one" }, { "StrProp" : "two" }, { "StrProp" : "three" }]',RJ.CollectionToJSON(C));
+  finally
+    FreeAndNil(C);
+  end;
+end;
+
+procedure TCJSONStreamer.TestChildren;
+
+Var
+  C : TChildrenComponent;
+
+begin
+  C:=TChildrenComponent.Create(Nil);
+  TComponent.Create(C).Name:='Child1';
+  TComponent.Create(C).Name:='Child2';
+  StreamObject(C);
+  If SR.IndexOfName('Children')<>-1 then
+    Fail('Children streamed with default options');
+
+end;
+
+procedure TCJSONStreamer.TestChildren2;
+Var
+  C : TChildrenComponent;
+  A : TJSONArray;
+  O : TJSONObject;
+
+begin
+  C:=TChildrenComponent.Create(Nil);
+  TComponent.Create(C).Name:='Child1';
+  TComponent.Create(C).Name:='Child2';
+  RJ.Options:=[jsoStreamChildren];
+  StreamObject(C);
+  AssertPropCount(1);
+  A:=AssertProperty('Children',jtArray) as TJSONArray;
+  O:=SR;
+  try
+    AssertEquals('2 Elements in array',2,A.Count);
+    AssertEquals('First in array is object',jtObject,A.Types[0]);
+    AssertEquals('Second in array is object',jtObject,A.Types[1]);
+    SR:=A.Objects[0];
+    AssertProp('Name','Child1');
+    SR:=A.Objects[1];
+    AssertProp('Name','Child2');
+  finally
+    SR:=O;
+  end;
+end;
+
+initialization
+
+  RegisterTests([TCJSONStreamer,TCJSONDeStreamer]);
+end.
+

+ 5 - 0
packages/fcl-web/src/base/fphtml.pp

@@ -170,6 +170,8 @@ type
 
   TForeachContentProducerProc = procedure(const AContentProducer: THTMLContentProducer) of object;
 
+  { IHTMLContentProducerContainer }
+
   IHTMLContentProducerContainer = interface
    ['{8B4D8AE0-4873-49BF-B677-D03C8A02CDA5}']
     procedure AddContentProducer(AContentProducer: THTMLContentProducer);
@@ -177,6 +179,8 @@ type
     function ExchangeContentProducers(Child1, Child2: THTMLContentProducer) : boolean;
     function MoveContentProducer(MoveElement, MoveBeforeElement: THTMLContentProducer) : boolean;
     procedure ForeachContentProducer(AForeachChildsProc: TForeachContentProducerProc; Recursive: boolean);
+
+    function ProduceContent : string;
   end;
 
   { THTMLContentProducer }
@@ -782,6 +786,7 @@ begin
   ChildIndex2:=GetContentProducerList.IndexOf(MoveBeforeElement);
   if (ChildIndex2=-1) then
     Exit;
+  if ChildIndex2>ChildIndex1 then dec(ChildIndex2);
   GetContentProducerList.Move(ChildIndex1,ChildIndex2);
   result := true;
 end;

+ 27 - 2
packages/fcl-web/src/base/webpage.pp

@@ -14,10 +14,23 @@ type
   TAjaxRequestResponseEvent = procedure(Sender: TObject; ARequest: TRequest; AResponse: TAjaxResponse) of object;
 
 type
+
+  { IWebPageDesigner }
+
   IWebPageDesigner = interface(IUnknown)
+  ['{25629DEA-79D5-4165-A0A3-BE6E2BA74442}']
     procedure Invalidate;
   end;
 
+  { IHTMLDesignable }
+
+  IHTMLDesignable = interface(IUnknown)
+  ['{C75546D6-9C93-49F0-809F-D29C52CD306D}']
+    function GetDesigner: IWebPageDesigner;
+    procedure SetDesigner(const AValue: IWebPageDesigner);
+    property Designer: IWebPageDesigner read GetDesigner write SetDesigner;
+  end;
+
   { TStandardWebController }
 
   TStandardWebController = class(TWebController)
@@ -44,7 +57,7 @@ type
 
   { TWebPage }
 
-  TWebPage = class(TDataModule, IHTMLContentProducerContainer)
+  TWebPage = class(TDataModule, IHTMLContentProducerContainer, IHTMLDesignable)
   private
     FAfterAjaxRequest: TAjaxRequestResponseEvent;
     FBaseURL: string;
@@ -59,8 +72,10 @@ type
     function GetContentProducer(Index: integer): THTMLContentProducer;
     function GetContentProducerList: TFPList;
     function GetContentProducers(Index: integer): THTMLContentProducer;
+    function GetDesigner: IWebPageDesigner;
     function GetHasWebController: boolean;
     function GetWebController: TWebController;
+    procedure SetDesigner(const AValue: IWebPageDesigner);
   protected
     procedure DoAfterAjaxRequest(ARequest: TRequest; AnAjaxResponse: TAjaxResponse); virtual;
     procedure DoHandleAjaxRequest(ARequest: TRequest; AnAjaxResponse: TAjaxResponse; var Handled: boolean); virtual;
@@ -86,7 +101,7 @@ type
     procedure HandlePage(ARequest: TRequest; AResponse: TResponse; AWriter: THTMLwriter; AWebModule: TFPWebModule = nil); virtual;
     procedure DoBeforeGenerateXML; virtual;
     procedure CleanupAfterRequest; virtual;
-    property Designer: IWebPageDesigner read FDesigner write FDesigner;
+    property Designer: IWebPageDesigner read GetDesigner write SetDesigner;
     property Request: TRequest read FRequest;
     property ContentProducers[Index: integer]: THTMLContentProducer read GetContentProducer;
     property HasWebController: boolean read GetHasWebController;
@@ -270,6 +285,11 @@ begin
   Result:=THTMLContentProducer(ContentProducerList[Index]);
 end;
 
+function TWebPage.GetDesigner: IWebPageDesigner;
+begin
+  result := FDesigner;
+end;
+
 function TWebPage.GetHasWebController: boolean;
 begin
   result := assigned(FWebController);
@@ -282,6 +302,11 @@ begin
   result := FWebController;
 end;
 
+procedure TWebPage.SetDesigner(const AValue: IWebPageDesigner);
+begin
+  FDesigner := AValue;
+end;
+
 function TWebPage.GetContentProducerList: TFPList;
 begin
   if not assigned(FContentProducers) then