Browse Source

新建linux门口机工程

vothin 2 years ago
commit
bd0ece59e9
100 changed files with 26772 additions and 0 deletions
  1. 150 0
      .cproject
  2. 28 0
      .project
  3. 5 0
      .settings/com.zksw.flythings.easyui.prefs
  4. 25 0
      .settings/language.settings.xml
  5. 29 0
      .settings/org.eclipse.cdt.core.prefs
  6. 2 0
      .settings/org.eclipse.core.resources.prefs
  7. 4 0
      i18n/en_US.tr
  8. 104 0
      i18n/zh_CN.tr
  9. 28 0
      jni/Main.cpp
  10. 133 0
      jni/Makefile
  11. 99 0
      jni/Makefile.bak
  12. 470 0
      jni/activity/DeviceUpdateActivity.cpp
  13. 120 0
      jni/activity/DeviceUpdateActivity.h
  14. 426 0
      jni/activity/callActivity.cpp
  15. 105 0
      jni/activity/callActivity.h
  16. 440 0
      jni/activity/mainActivity.cpp
  17. 132 0
      jni/activity/mainActivity.h
  18. 394 0
      jni/activity/navibar.cpp
  19. 92 0
      jni/activity/navibar.h
  20. 397 0
      jni/activity/startActivity.cpp
  21. 97 0
      jni/activity/startActivity.h
  22. 386 0
      jni/activity/statusbar.cpp
  23. 92 0
      jni/activity/statusbar.h
  24. 422 0
      jni/activity/testActivity.cpp
  25. 103 0
      jni/activity/testActivity.h
  26. 511 0
      jni/activity/ui3Activity.cpp
  27. 132 0
      jni/activity/ui3Activity.h
  28. 58 0
      jni/base/asio.hpp
  29. 52 0
      jni/base/base.hpp
  30. 89 0
      jni/base/crypto.hpp
  31. 31 0
      jni/base/errors.hpp
  32. 173 0
      jni/base/files.hpp
  33. 296 0
      jni/base/handler.hpp
  34. 638 0
      jni/base/http_client.cpp
  35. 92 0
      jni/base/http_client.h
  36. 41 0
      jni/base/http_request.cpp
  37. 96 0
      jni/base/http_request.h
  38. 63 0
      jni/base/http_response.cpp
  39. 55 0
      jni/base/http_response.h
  40. 134 0
      jni/base/input_event_reader.hpp
  41. 158 0
      jni/base/json_array.cpp
  42. 67 0
      jni/base/json_array.h
  43. 236 0
      jni/base/json_object.cpp
  44. 86 0
      jni/base/json_object.h
  45. 75 0
      jni/base/key_tone.hpp
  46. 68 0
      jni/base/log.hpp
  47. 87 0
      jni/base/log/redirectcoutstreambuf.h
  48. 37 0
      jni/base/macros.h
  49. 42 0
      jni/base/mutex.hpp
  50. 539 0
      jni/base/network.cpp
  51. 116 0
      jni/base/network.h
  52. 105 0
      jni/base/numbers.hpp
  53. 290 0
      jni/base/os.hpp
  54. 150 0
      jni/base/preference.hpp
  55. 154 0
      jni/base/prefs.hpp
  56. 284 0
      jni/base/rapidjson/allocators.h
  57. 78 0
      jni/base/rapidjson/cursorstreamwrapper.h
  58. 2682 0
      jni/base/rapidjson/document.h
  59. 299 0
      jni/base/rapidjson/encodedstream.h
  60. 716 0
      jni/base/rapidjson/encodings.h
  61. 74 0
      jni/base/rapidjson/error/en.h
  62. 161 0
      jni/base/rapidjson/error/error.h
  63. 99 0
      jni/base/rapidjson/filereadstream.h
  64. 104 0
      jni/base/rapidjson/filewritestream.h
  65. 151 0
      jni/base/rapidjson/fwd.h
  66. 290 0
      jni/base/rapidjson/internal/biginteger.h
  67. 271 0
      jni/base/rapidjson/internal/diyfp.h
  68. 245 0
      jni/base/rapidjson/internal/dtoa.h
  69. 78 0
      jni/base/rapidjson/internal/ieee754.h
  70. 308 0
      jni/base/rapidjson/internal/itoa.h
  71. 186 0
      jni/base/rapidjson/internal/meta.h
  72. 55 0
      jni/base/rapidjson/internal/pow10.h
  73. 740 0
      jni/base/rapidjson/internal/regex.h
  74. 232 0
      jni/base/rapidjson/internal/stack.h
  75. 69 0
      jni/base/rapidjson/internal/strfunc.h
  76. 290 0
      jni/base/rapidjson/internal/strtod.h
  77. 46 0
      jni/base/rapidjson/internal/swap.h
  78. 128 0
      jni/base/rapidjson/istreamwrapper.h
  79. 70 0
      jni/base/rapidjson/memorybuffer.h
  80. 71 0
      jni/base/rapidjson/memorystream.h
  81. 316 0
      jni/base/rapidjson/msinttypes/inttypes.h
  82. 300 0
      jni/base/rapidjson/msinttypes/stdint.h
  83. 81 0
      jni/base/rapidjson/ostreamwrapper.h
  84. 1415 0
      jni/base/rapidjson/pointer.h
  85. 277 0
      jni/base/rapidjson/prettywriter.h
  86. 658 0
      jni/base/rapidjson/rapidjson.h
  87. 2230 0
      jni/base/rapidjson/reader.h
  88. 2497 0
      jni/base/rapidjson/schema.h
  89. 223 0
      jni/base/rapidjson/stream.h
  90. 121 0
      jni/base/rapidjson/stringbuffer.h
  91. 709 0
      jni/base/rapidjson/writer.h
  92. 80 0
      jni/base/simple_form.hpp
  93. 258 0
      jni/base/strings.hpp
  94. 104 0
      jni/base/thread.hpp
  95. 124 0
      jni/base/time.hpp
  96. 219 0
      jni/base/timer.hpp
  97. 374 0
      jni/core/CPullWindow/CPullWindow.cpp
  98. 76 0
      jni/core/CPullWindow/CPullWindow.h
  99. 29 0
      jni/core/CPullWindow/w_DefPullWidnow.h
  100. 0 0
      jni/core/VelocityTracker.h

+ 150 - 0
.cproject

@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
+	<storageModule moduleId="org.eclipse.cdt.core.settings">
+		<cconfiguration id="cdt.managedbuild.config.gnu.exe.debug.566211490">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.exe.debug.566211490" moduleId="org.eclipse.cdt.core.settings" name="Debug">
+				<externalSettings/>
+				<extensions>
+					<extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.debug.566211490" name="Debug" parent="cdt.managedbuild.config.gnu.exe.debug">
+					<folderInfo id="cdt.managedbuild.config.gnu.exe.debug.566211490." name="/" resourcePath="">
+						<toolChain id="cdt.managedbuild.toolchain.gnu.exe.debug.1424090603" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.debug">
+							<targetPlatform id="cdt.managedbuild.target.gnu.platform.exe.debug.1275454578" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.exe.debug"/>
+							<builder arguments="-j2" buildPath="${ProjDirPath}/jni" command="make" id="cdt.managedbuild.target.gnu.builder.exe.debug.2033377817" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.exe.debug"/>
+							<tool id="cdt.managedbuild.tool.gnu.archiver.base.1728273503" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.1305165402" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug">
+								<option id="gnu.cpp.compiler.exe.debug.option.optimization.level.696779789" name="Optimization Level" superClass="gnu.cpp.compiler.exe.debug.option.optimization.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/>
+								<option id="gnu.cpp.compiler.exe.debug.option.debugging.level.2070456324" name="Debug Level" superClass="gnu.cpp.compiler.exe.debug.option.debugging.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.debugging.level.max" valueType="enumerated"/>
+								<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="gnu.cpp.compiler.option.include.paths.1154080955" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath">
+									<listOptionValue builtIn="false" value="&quot;${ZKSW_REAL_TOOLCHAIN}/arm-pc-linux-gnueabihf/include&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${ZKSW_REAL_TOOLCHAIN}/arm-pc-linux-gnueabihf/include/c++/8.3.0&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${ZKSW_REAL_TOOLCHAIN}/arm-pc-linux-gnueabihf/include/c++/8.3.0/arm-pc-linux-gnueabihf&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${ZKSW_REAL_TOOLCHAIN}/arm-pc-linux-gnueabihf/include/c++/8.3.0/backward&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${ZKSW_REAL_TOOLCHAIN}/arm-pc-linux-gnueabihf/sysroot/usr/include&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${ZKSW_REAL_TOOLCHAIN}/lib/gcc/arm-pc-linux-gnueabihf/8.3.0/include&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${ZKSW_REAL_TOOLCHAIN}/lib/gcc/arm-pc-linux-gnueabihf/8.3.0/include-fixed&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${ZKSW_REAL_PREBUILT}/include&quot;"/>
+								</option>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1947386254" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.compiler.exe.debug.1376883262" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.exe.debug">
+								<option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.exe.debug.option.optimization.level.1226597662" name="Optimization Level" superClass="gnu.c.compiler.exe.debug.option.optimization.level" useByScannerDiscovery="false" valueType="enumerated"/>
+								<option id="gnu.c.compiler.exe.debug.option.debugging.level.1368223028" name="Debug Level" superClass="gnu.c.compiler.exe.debug.option.debugging.level" useByScannerDiscovery="false" value="gnu.c.debugging.level.max" valueType="enumerated"/>
+								<option id="gnu.c.compiler.option.dialect.std.1052180836" name="Language standard" superClass="gnu.c.compiler.option.dialect.std" useByScannerDiscovery="true" value="gnu.c.compiler.dialect.default" valueType="enumerated"/>
+								<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="gnu.c.compiler.option.include.paths.465865736" superClass="gnu.c.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath">
+									<listOptionValue builtIn="false" value="&quot;${ZKSW_REAL_TOOLCHAIN}/arm-pc-linux-gnueabihf/include&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${ZKSW_REAL_TOOLCHAIN}/arm-pc-linux-gnueabihf/sysroot/usr/include&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${ZKSW_REAL_TOOLCHAIN}/lib/gcc/arm-pc-linux-gnueabihf/8.3.0/include&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${ZKSW_REAL_TOOLCHAIN}/lib/gcc/arm-pc-linux-gnueabihf/8.3.0/include-fixed&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${ZKSW_REAL_PREBUILT}/include&quot;"/>
+								</option>
+								<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.581748641" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.linker.exe.debug.1282953705" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.exe.debug">
+								<inputType id="cdt.managedbuild.tool.gnu.c.linker.input.1576143700" superClass="cdt.managedbuild.tool.gnu.c.linker.input">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+								</inputType>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.linker.exe.debug.720815330" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.exe.debug">
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.516232134" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+								</inputType>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.assembler.exe.debug.2062949718" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.exe.debug">
+								<inputType id="cdt.managedbuild.tool.gnu.assembler.input.418397562" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+							</tool>
+						</toolChain>
+					</folderInfo>
+				</configuration>
+			</storageModule>
+			<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+		</cconfiguration>
+		<cconfiguration id="cdt.managedbuild.config.gnu.exe.release.1001661297">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.exe.release.1001661297" moduleId="org.eclipse.cdt.core.settings" name="Release">
+				<externalSettings/>
+				<extensions>
+					<extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.release.1001661297" name="Release" parent="cdt.managedbuild.config.gnu.exe.release">
+					<folderInfo id="cdt.managedbuild.config.gnu.exe.release.1001661297." name="/" resourcePath="">
+						<toolChain id="cdt.managedbuild.toolchain.gnu.exe.release.1656558982" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.release">
+							<targetPlatform id="cdt.managedbuild.target.gnu.platform.exe.release.2006651292" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.exe.release"/>
+							<builder buildPath="${workspace_loc:/linux_door}/Release" id="cdt.managedbuild.target.gnu.builder.exe.release.1408509441" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.exe.release"/>
+							<tool id="cdt.managedbuild.tool.gnu.archiver.base.820667868" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.745370985" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release">
+								<option id="gnu.cpp.compiler.exe.release.option.optimization.level.1989544089" name="Optimization Level" superClass="gnu.cpp.compiler.exe.release.option.optimization.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/>
+								<option id="gnu.cpp.compiler.exe.release.option.debugging.level.1603679444" name="Debug Level" superClass="gnu.cpp.compiler.exe.release.option.debugging.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1060602816" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.compiler.exe.release.17032854" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.exe.release">
+								<option defaultValue="gnu.c.optimization.level.most" id="gnu.c.compiler.exe.release.option.optimization.level.1098801577" name="Optimization Level" superClass="gnu.c.compiler.exe.release.option.optimization.level" useByScannerDiscovery="false" valueType="enumerated"/>
+								<option id="gnu.c.compiler.exe.release.option.debugging.level.230670025" name="Debug Level" superClass="gnu.c.compiler.exe.release.option.debugging.level" useByScannerDiscovery="false" value="gnu.c.debugging.level.none" valueType="enumerated"/>
+								<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1929257441" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.linker.exe.release.242574966" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.exe.release">
+								<inputType id="cdt.managedbuild.tool.gnu.c.linker.input.1599777645" superClass="cdt.managedbuild.tool.gnu.c.linker.input">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+								</inputType>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.linker.exe.release.1416720549" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.exe.release">
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1473932384" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+								</inputType>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.assembler.exe.release.439048287" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.exe.release">
+								<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1642106201" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+							</tool>
+						</toolChain>
+					</folderInfo>
+				</configuration>
+			</storageModule>
+			<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+		</cconfiguration>
+	</storageModule>
+	<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+		<project id="linux_door.cdt.managedbuild.target.gnu.exe.983633874" name="Executable" projectType="cdt.managedbuild.target.gnu.exe"/>
+	</storageModule>
+	<storageModule moduleId="scannerConfiguration">
+		<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.566211490;cdt.managedbuild.config.gnu.exe.debug.566211490.;cdt.managedbuild.tool.gnu.c.compiler.exe.debug.1376883262;cdt.managedbuild.tool.gnu.c.compiler.input.581748641">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.1001661297;cdt.managedbuild.config.gnu.exe.release.1001661297.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.745370985;cdt.managedbuild.tool.gnu.cpp.compiler.input.1060602816">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.566211490;cdt.managedbuild.config.gnu.exe.debug.566211490.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.1305165402;cdt.managedbuild.tool.gnu.cpp.compiler.input.1947386254">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.1001661297;cdt.managedbuild.config.gnu.exe.release.1001661297.;cdt.managedbuild.tool.gnu.c.compiler.exe.release.17032854;cdt.managedbuild.tool.gnu.c.compiler.input.1929257441">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		</scannerConfigBuildInfo>
+	</storageModule>
+	<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
+	<storageModule moduleId="refreshScope" versionNumber="2">
+		<configuration configurationName="Release">
+			<resource resourceType="PROJECT" workspacePath="/linux_door"/>
+		</configuration>
+		<configuration configurationName="Debug"/>
+	</storageModule>
+	<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
+	<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
+</cproject>

+ 28 - 0
.project

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>linux_door</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
+			<triggers>full,incremental,</triggers>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
+			<triggers>clean,full,incremental,</triggers>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.cdt.core.cnature</nature>
+		<nature>org.eclipse.cdt.core.ccnature</nature>
+		<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
+		<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
+		<nature>com.zksw.ui.editor.core.nature</nature>
+	</natures>
+</projectDescription>

+ 5 - 0
.settings/com.zksw.flythings.easyui.prefs

@@ -0,0 +1,5 @@
+easyui.cfg.debug={"baud"\:"115200","defBrightness"\:-1,"languageCode"\:"zh_CN","languagePath"\:"/mnt/extsd/tr/","resPath"\:"/mnt/extsd/ui/","rotateScreen"\:0,"rotateTouch"\:0,"screensaverTimeOut"\:-1,"startupLibPath"\:"/mnt/extsd/lib/libzkgui.so","startupTouchCalib"\:false,"touchDev"\:"/dev/input/event1","uart"\:"ttyS1","zkdebug"\:false}
+easyui.cfg.release={"baud"\:"115200","defBrightness"\:-1,"languageCode"\:"zh_CN","languagePath"\:"/res/tr/","resPath"\:"/res/ui/","rotateScreen"\:0,"rotateTouch"\:0,"screensaverTimeOut"\:-1,"startupLibPath"\:"/res/lib/libzkgui.so","startupTouchCalib"\:false,"touchDev"\:"/dev/input/event1","uart"\:"ttyS1","zkdebug"\:false}
+eclipse.preferences.version=1
+platform={"name"\:"Z21","cprojectTemplateDir"\:"bundle/cproject/z21","internalCode"\:"z21"}
+resolution=800x480

+ 25 - 0
.settings/language.settings.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<project>
+	<configuration id="cdt.managedbuild.config.gnu.exe.debug.566211490" name="Debug">
+		<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
+			<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
+			<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
+			<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
+			<provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector" console="false" env-hash="908325126562" id="org.eclipse.cdt.managedbuilder.core.GCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
+				<language-scope id="org.eclipse.cdt.core.gcc"/>
+				<language-scope id="org.eclipse.cdt.core.g++"/>
+			</provider>
+		</extension>
+	</configuration>
+	<configuration id="cdt.managedbuild.config.gnu.exe.release.1001661297" name="Release">
+		<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
+			<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
+			<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
+			<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
+			<provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector" console="false" env-hash="1685337175238" id="org.eclipse.cdt.managedbuilder.core.GCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
+				<language-scope id="org.eclipse.cdt.core.gcc"/>
+				<language-scope id="org.eclipse.cdt.core.g++"/>
+			</provider>
+		</extension>
+	</configuration>
+</project>

+ 29 - 0
.settings/org.eclipse.cdt.core.prefs

@@ -0,0 +1,29 @@
+eclipse.preferences.version=1
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/CC/delimiter=;
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/CC/operation=append
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/CC/value=arm-pc-linux-gnueabihf-gcc
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/CROSS_COMPILE/delimiter=;
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/CROSS_COMPILE/operation=replace
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/CROSS_COMPILE/value=arm-pc-linux-gnueabihf-
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/PATH/delimiter=;
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/PATH/operation=append
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/PATH/value=${ZKSW_REAL_TOOLCHAIN}/bin
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/SDK_PATH/delimiter=;
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/SDK_PATH/operation=replace
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/SDK_PATH/value=${eclipse_home}/../sdk
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/ZKSW_REAL_PREBUILT/delimiter=;
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/ZKSW_REAL_PREBUILT/operation=replace
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/ZKSW_REAL_PREBUILT/value=${ZKSW_Z21_PREBUILT}
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/ZKSW_REAL_TOOLCHAIN/delimiter=;
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/ZKSW_REAL_TOOLCHAIN/operation=append
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/ZKSW_REAL_TOOLCHAIN/value=${ZKSW_Z21_TOOLCHAIN}
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/ZKSW_Z21_PREBUILT/delimiter=;
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/ZKSW_Z21_PREBUILT/operation=append
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/ZKSW_Z21_PREBUILT/value=${eclipse_home}/../sdk/platforms/z21/prebuilt
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/ZKSW_Z21_TOOLCHAIN/delimiter=;
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/ZKSW_Z21_TOOLCHAIN/operation=replace
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/ZKSW_Z21_TOOLCHAIN/value=${eclipse_home}/../sdk/platforms/z21/toolchain
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/append=true
+environment/project/cdt.managedbuild.config.gnu.exe.debug.566211490/appendContributed=true
+environment/project/cdt.managedbuild.config.gnu.exe.release.1001661297/append=true
+environment/project/cdt.managedbuild.config.gnu.exe.release.1001661297/appendContributed=true

+ 2 - 0
.settings/org.eclipse.core.resources.prefs

@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8

+ 4 - 0
i18n/en_US.tr

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="hello_world">Hello world!</string>
+</resources>

+ 104 - 0
i18n/zh_CN.tr

@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <!-- 时间相关 -->
+    <string name="Year">年</string>
+    <string name="Month">月</string>
+    <string name="Day">日</string>
+    <string name="Monday">周一</string>
+    <string name="Tuesday">周二</string>
+    <string name="Wednesday">周三</string>
+    <string name="Thursday">周四</string>
+    <string name="Friday">周五</string>
+    <string name="Saturday">周六</string>
+    <string name="Sunday">周日</string>
+    <!-- 按钮 -->
+    <string name="More">更多设置</string>
+    <string name="Fee">费用</string>
+    <string name="Help">请求增援</string>
+    <string name="HelpInfo">增援已发出</string>
+    <string name="HelpResponse">增援已响应</string>
+    <string name="Call">呼叫</string>
+    <string name="Reboot">重启</string>
+    <string name="SettingServerIP">服务器设置</string>
+    <string name="SettingNet">网络设置</string>
+    <string name="SoftVersion">软件版本</string>
+    <string name="SoftVersionCheck">检查更新</string>
+    <string name="SoftUpdateNow">立即升级</string>
+    <string name="Confirm">确定</string>
+    <string name="Cancel">取消</string>
+    <string name="Save">保存</string>
+    <string name="Back">返回</string>
+    <string name="CallBack">呼叫床位</string>
+    <string name="CallNurse">呼叫护士</string>
+    <string name="CallCencel">取消呼叫</string>
+    <!-- 首页 -->
+    <string name="Room">房间</string>
+    <string name="EmptyBed">空床</string>
+    <string name="None">暂无</string>
+    <string name="Oxygen">吸氧倒计时</string>
+    <string name="OxygenInhalation">吸氧</string>
+    <string name="SkinTest">皮试</string>
+    <string name="Infusion">输液</string>
+    <string name="10Minutes">10分钟</string>
+    <string name="15Minutes">15分钟</string>
+    <string name="20Minutes">20分钟时</string>
+    <string name="30Minutes">30分钟</string>
+    <string name="45Minutes">45分钟</string>
+    <string name="60Minutes">60分钟</string>
+    <string name="90Minutes">90分钟</string>
+    <string name="120Minutes">120分钟</string>
+    <string name="SettingTime">自定义时间</string>
+    <string name="CountdownProgress">正在倒计时</string>
+    <string name="CountdownCancel">是否取消倒计时</string>
+    <string name="CountdownEnded">倒计时已结束</string>
+	<string name="Nursing">进入护理</string>
+	<string name="InNursing">护理中...</string>
+	<string name="NursingEnd">护理结束</string>
+	<string name="Description">说明:</string>
+	<string name="Advice">医嘱</string>
+	<string name="AdviceType">医嘱类型</string>
+	<string name="LONG_TERM">长期</string>
+	<string name="TEMP">临时</string>
+	<string name="LoseEfficacy">失效</string>
+	<string name="TakeEffect">生效</string>
+	<string name="StartTime">开始时间:</string>
+	<string name="EndTime">结束时间:</string>
+	<string name="Content">内容</string>
+	<string name="Detail">参数</string>
+    <!-- 系统信息 -->
+    <string name="Null">无</string>
+    <string name="InDate">入院日期</string>
+    <string name="Advice">医嘱</string>
+    <string name="DeviceId">设备ID</string>
+    <string name="DeviceSign">设备内部ID</string>
+    <string name="MAC">设备MAC</string>
+    <string name="DeviceIp">设备IP</string>
+    <string name="NETMASK">子网掩码</string>
+    <string name="GATEWAY">网关</string>
+    <string name="VoiceId">语音ID</string>
+    <string name="VoiceDomain">语音网关</string>
+    <string name="VersionInfo">版本信息</string>
+    <string name="Version">版本名称</string>
+    <string name="VersionNo">版本号</string>
+    <string name="GetVersionFailed">获取版本失败,错误码</string>
+    <string name="ServerIP">服务器IP</string>
+    <string name="ServerIPWrong">服务器地址填写有误</string>
+    <string name="InputPassword">输入密码</string>
+    <string name="PasswordWrong">密码错误</string>
+    <string name="PasswordTag">4位密码</string>
+    <string name="Searching">查询中...</string>
+    <string name="IsTheLastVersion">已经是最新版本</string>
+    <string name="FindNewVersion">发现新版本</string>
+    <string name="Downloading">下载中</string>
+    <string name="EthernetDisconnect">未连接网络</string>
+    <string name="DownloadFailed">下载错误,错误码</string>
+    <!-- 通话界面 -->
+    <string name="RemoteRefuse">对方拒绝</string>
+    <string name="RemoteBusy">对方忙线</string>
+    <string name="CallFailed">呼出失败</string>
+    <string name="Calling">正在呼叫</string>
+    <string name="CallConfirmed">通话中</string>
+    <string name="CallConnecting">正在连接</string>
+    <string name="CallInComing">来电</string>
+    <string name="CallOutTitle">呼叫护士</string>
+</resources>

+ 28 - 0
jni/Main.cpp

@@ -0,0 +1,28 @@
+#include "entry/EasyUIContext.h"
+#include "uart/UartContext.h"
+#include "manager/ConfigManager.h"
+#ifdef __cplusplus
+extern "C" {
+#endif  /* __cplusplus */
+
+void onEasyUIInit(EasyUIContext *pContext) {
+	// 初始化时打开串口
+	//UARTCONTEXT->openUart(CONFIGMANAGER->getUartName().c_str(), CONFIGMANAGER->getUartBaudRate());
+	UartContext::init();
+}
+
+void onEasyUIDeinit(EasyUIContext *pContext) {
+	UartContext::destroy();
+}
+
+const char* onStartupApp(EasyUIContext *pContext) {
+	return "startActivity";
+}
+
+
+#ifdef __cplusplus
+
+}
+
+#endif  /* __cplusplus */
+

+ 133 - 0
jni/Makefile

@@ -0,0 +1,133 @@
+#一般情况无需修改该文件
+
+LOCAL_PATH=$(dir  $(abspath $(lastword $(MAKEFILE_LIST))))
+ZKSW_PREBUILT_LIB_PATH := $(ZKSW_REAL_PREBUILT)/lib
+ZKSW_PREBUILT_INCLUDE_PATH := $(ZKSW_REAL_PREBUILT)/include
+
+EASYUI_COMMON_INCLUDE := $(LOCAL_PATH)/include
+
+#配置源文件目录
+PROJ_ROOT_PATH  :=./
+#源文件后缀名
+PROJ_SRC_SUFFIX := %.cpp %.c
+PROJ_HEAD_SUFFIX := %.h
+# 递归遍历目录下的所有的文件 
+rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))  
+# 获取相应的源文件
+PROJ_ALL_FILES := $(foreach src_path,$(PROJ_ROOT_PATH), $(call rwildcard,$(src_path),*.*) )   
+PROJ_SRC_FILES := $(filter $(PROJ_SRC_SUFFIX),$(PROJ_ALL_FILES))   
+PROJ_HEAD_FILES := $(filter $(PROJ_HEAD_SUFFIX),$(PROJ_ALL_FILES))   
+
+# 获取相应的源文件
+LOCAL_SRC_FILES  := $(PROJ_SRC_FILES) 
+LOCAL_HEAD_FILES := $(PROJ_HEAD_FILES) 
+
+#源文件目录结构
+PROJ_DIR_TREE := $(dir $(foreach src_path, $(LOCAL_SRC_FILES), $(call rwildcard,$(src_path),*/) ) )  
+PROJ_DIR_TREE := $(sort $(PROJ_DIR_TREE))  
+
+
+OBJS_ROOT_DIR=../obj/
+OBJS_1 = $(patsubst %.cpp,%.o,$(LOCAL_SRC_FILES))
+OBJS_2 = $(patsubst %.c,%.o,$(OBJS_1))
+OBJS   = $(addprefix $(OBJS_ROOT_DIR),$(OBJS_2))
+OBJS_DIR_TREE=$(addprefix $(OBJS_ROOT_DIR),$(PROJ_DIR_TREE))
+
+CFLAGS=-Os -pipe  -fno-caller-saves -Wno-unused-result -mfloat-abi=hard -mfpu=vfp -Wformat -Werror=format-security -fstack-protector -D_FORTIFY_SOURCE=1 -Wl,-z,now -Wl,-z,relro -Wl,--warn-common -Wl,--warn-once -Wl,-z,combreloc -Wl,-z,defs -DUSE_ANDROID_LOG 
+CXXFLAGS=-Os -pipe  -fno-caller-saves -Wno-unused-result -mfloat-abi=hard -mfpu=vfp -Wformat -Werror=format-security -fstack-protector -D_FORTIFY_SOURCE=1 -Wl,-z,now -Wl,-z,relro -Wl,-z,defs -DUSE_ANDROID_LOG
+
+CXXFLAGS+= -fexceptions -Wall -lstdc++ -std=c++11 \
+          -DPJ_IS_LITTLE_ENDIAN=1 -DPJ_IS_BIG_ENDIAN=0	\
+          -D__PLAT_Z21__=1
+
+STATIC_LIB = curl/libcurl.a zlib/libz.a
+
+INCLUDE_DIR := -I$(EASYUI_COMMON_INCLUDE) \
+               -I$(ZKSW_PREBUILT_INCLUDE_PATH) \
+               -I. \
+               -Idep/include
+
+LDFLAGS += -lcurl -lcares -lssl -lcrypto
+
+LDFLAGS += -lvoip \
+           -lpjsua2-arm-unknown-linux-gnueabihf \
+           -lstdc++ -lpjsua-arm-unknown-linux-gnueabihf \
+           -lpjsip-ua-arm-unknown-linux-gnueabihf \
+           -lpjsip-simple-arm-unknown-linux-gnueabihf \
+           -lpjsip-arm-unknown-linux-gnueabihf \
+           -lpjmedia-codec-arm-unknown-linux-gnueabihf \
+           -lpjmedia-arm-unknown-linux-gnueabihf \
+           -lpjmedia-videodev-arm-unknown-linux-gnueabihf \
+           -lpjmedia-audiodev-arm-unknown-linux-gnueabihf \
+           -lpjmedia-arm-unknown-linux-gnueabihf \
+           -lpjnath-arm-unknown-linux-gnueabihf \
+           -lpjlib-util-arm-unknown-linux-gnueabihf  \
+           -lsrtp-arm-unknown-linux-gnueabihf \
+           -lresample-arm-unknown-linux-gnueabihf \
+           -lg7221codec-arm-unknown-linux-gnueabihf \
+           -lyuv-arm-unknown-linux-gnueabihf  \
+           -lpj-arm-unknown-linux-gnueabihf \
+           -lzkaudio \
+           -lpaho-mqtt3c
+           
+LDFLAGS += -lsqlite3
+
+LDFLAGS += -lswscale -lswresample -lavfilter -lavformat -lavcodec \
+           -lavdevice -lavutil
+           
+LDFLAGS += -lopenh264 
+LDFLAGS += -lz
+LDFLAGS += -lmi_panel -lmi_disp -lmi_ai -lmi_ao -lmi_sys -lmi_common -lcam_os_wrapper
+LDFLAGS += -lzkhardware -lzknet -leasyui -llog -pthread -lm -ldl
+LDFLAGS += -L$(ZKSW_PREBUILT_LIB_PATH) -L. -Ldep/lib
+
+TARGET=../libs/armeabi/libzkgui.so
+
+ifeq ($(TARGET), $(wildcard $(TARGET)))
+	DELETE_TARGET=$(TARGET)
+endif
+
+# alias commads if compile on windows
+RM =rm
+MKDIR=mkdir
+ECHO=echo
+ifeq ($(OS),Windows_NT)
+	RM=win32-rm
+	MKDIR=win32-mkdir
+	ECHO=win32-echo
+else
+	#keep default
+endif
+#alias end
+
+all: prepare $(TARGET)
+	@$(ECHO)
+	@$(ECHO) "[armeabi] Install        : libzkgui.so => libs/armeabi/libzkgui.so"
+	
+
+$(OBJS_ROOT_DIR)%.o: %.cpp $(LOCAL_HEAD_FILES)
+	@$(ECHO) "[armeabi] Compile++      : "$< 
+	@$(CC) -c $< -o $@ $(CXXFLAGS) $(INCLUDE_DIR) $(LDFLAGS) 
+	
+$(OBJS_ROOT_DIR)%.o: %.c $(LOCAL_HEAD_FILES)
+	@$(ECHO) "[armeabi] Compile++      : "$< 
+	@$(CC) -c $< -o $@ $(CFLAGS) $(INCLUDE_DIR) $(LDFLAGS) 
+
+$(TARGET):$(OBJS) 
+	@$(ECHO) "[armeabi] SharedLibrary  : "$@ 
+	@$(CC) -fPIC -shared $^ -o $@ $(LDFLAGS) $(CXXFLAGS)
+	@$(CROSS_COMPILE)strip $@ 
+	
+prepare: 
+	@$(ECHO) "[armeabi] GCC            : "$(CC) 
+	@-$(MKDIR) ../libs/armeabi -p 
+	@-$(MKDIR) $(OBJS_DIR_TREE) -p 
+	@-$(RM) $(TARGET) -rf 
+	
+clean:
+	@$(ECHO) "[armeabi] Clean          : "$(OBJS_ROOT_DIR) 
+	@-$(RM)  $(OBJS_ROOT_DIR) -rf 
+	@$(ECHO) "[armeabi] Clean          : "$(TARGET)
+	@-$(RM)  $(TARGET) -rf 
+
+.PHONY:all clean prepare $(TARGET)

+ 99 - 0
jni/Makefile.bak

@@ -0,0 +1,99 @@
+#一般情况无需修改该文件
+
+LOCAL_PATH=$(dir  $(abspath $(lastword $(MAKEFILE_LIST))))
+ZKSW_PREBUILT_LIB_PATH := $(ZKSW_REAL_PREBUILT)/lib
+ZKSW_PREBUILT_INCLUDE_PATH := $(ZKSW_REAL_PREBUILT)/include
+
+EASYUI_COMMON_INCLUDE := $(LOCAL_PATH)/include
+
+#配置源文件目录
+PROJ_ROOT_PATH  :=./
+#源文件后缀名
+PROJ_SRC_SUFFIX := %.cpp %.c
+PROJ_HEAD_SUFFIX := %.h
+# 递归遍历目录下的所有的文件 
+rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))  
+# 获取相应的源文件
+PROJ_ALL_FILES := $(foreach src_path,$(PROJ_ROOT_PATH), $(call rwildcard,$(src_path),*.*) )   
+PROJ_SRC_FILES := $(filter $(PROJ_SRC_SUFFIX),$(PROJ_ALL_FILES))   
+PROJ_HEAD_FILES := $(filter $(PROJ_HEAD_SUFFIX),$(PROJ_ALL_FILES))   
+
+# 获取相应的源文件
+LOCAL_SRC_FILES  := $(PROJ_SRC_FILES) 
+LOCAL_HEAD_FILES := $(PROJ_HEAD_FILES) 
+
+#源文件目录结构
+PROJ_DIR_TREE := $(dir $(foreach src_path, $(LOCAL_SRC_FILES), $(call rwildcard,$(src_path),*/) ) )  
+PROJ_DIR_TREE := $(sort $(PROJ_DIR_TREE))  
+
+
+OBJS_ROOT_DIR=../obj/
+OBJS_1 = $(patsubst %.cpp,%.o,$(LOCAL_SRC_FILES))
+OBJS_2 = $(patsubst %.c,%.o,$(OBJS_1))
+OBJS   = $(addprefix $(OBJS_ROOT_DIR),$(OBJS_2))
+OBJS_DIR_TREE=$(addprefix $(OBJS_ROOT_DIR),$(PROJ_DIR_TREE))
+
+CFLAGS=-Os -pipe  -fno-caller-saves -Wno-unused-result -mfloat-abi=hard -mfpu=vfp -Wformat -Werror=format-security -fstack-protector -D_FORTIFY_SOURCE=1 -Wl,-z,now -Wl,-z,relro -Wl,--warn-common -Wl,--warn-once -Wl,-z,combreloc -Wl,-z,defs -DUSE_ANDROID_LOG 
+CXXFLAGS=-Os -pipe  -fno-caller-saves -Wno-unused-result -mfloat-abi=hard -mfpu=vfp -Wformat -Werror=format-security -fstack-protector -D_FORTIFY_SOURCE=1 -Wl,-z,now -Wl,-z,relro -Wl,-z,defs -DUSE_ANDROID_LOG
+
+CXXFLAGS+= -fexceptions -Wall -lstdc++
+
+STATIC_LIB = curl/libcurl.a zlib/libz.a
+
+INCLUDE_DIR := -I$(EASYUI_COMMON_INCLUDE) \
+               -I$(ZKSW_PREBUILT_INCLUDE_PATH) \
+               -I. \
+               -Idep/include
+
+LDFLAGS = -lzkhardware -lzknet -leasyui -llog -pthread -lm -ldl
+LDFLAGS += -L$(ZKSW_PREBUILT_LIB_PATH) -L. -Ldep/lib
+
+TARGET=../libs/armeabi/libzkgui.so
+
+ifeq ($(TARGET), $(wildcard $(TARGET)))
+	DELETE_TARGET=$(TARGET)
+endif
+
+# alias commads if compile on windows
+RM =rm
+MKDIR=mkdir
+ECHO=echo
+ifeq ($(OS),Windows_NT)
+	RM=win32-rm
+	MKDIR=win32-mkdir
+	ECHO=win32-echo
+else
+	#keep default
+endif
+#alias end
+
+all: prepare $(TARGET)
+	@$(ECHO)
+	@$(ECHO) "[armeabi] Install        : libzkgui.so => libs/armeabi/libzkgui.so"
+	
+
+$(OBJS_ROOT_DIR)%.o: %.cpp $(LOCAL_HEAD_FILES)
+	@$(ECHO) "[armeabi] Compile++      : "$< 
+	@$(CC) -c $< -o $@ $(CXXFLAGS) $(INCLUDE_DIR) $(LDFLAGS) 
+	
+$(OBJS_ROOT_DIR)%.o: %.c $(LOCAL_HEAD_FILES)
+	@$(ECHO) "[armeabi] Compile++      : "$< 
+	@$(CC) -c $< -o $@ $(CFLAGS) $(INCLUDE_DIR) $(LDFLAGS) 
+
+$(TARGET):$(OBJS) 
+	@$(ECHO) "[armeabi] SharedLibrary  : "$@ 
+	@$(CC) -fPIC -shared $^ -o $@ $(STATIC_LIB) $(LDFLAGS) $(CXXFLAGS)
+	
+prepare: 
+	@$(ECHO) "[armeabi] GCC            : "$(CC) 
+	@-$(MKDIR) ../libs/armeabi -p 
+	@-$(MKDIR) $(OBJS_DIR_TREE) -p 
+	@-$(RM) $(TARGET) -rf 
+	
+clean:
+	@$(ECHO) "[armeabi] Clean          : "$(OBJS_ROOT_DIR) 
+	@-$(RM)  $(OBJS_ROOT_DIR) -rf 
+	@$(ECHO) "[armeabi] Clean          : "$(TARGET)
+	@-$(RM)  $(TARGET) -rf 
+
+.PHONY:all clean prepare $(TARGET)

+ 470 - 0
jni/activity/DeviceUpdateActivity.cpp

@@ -0,0 +1,470 @@
+/***********************************************
+/gen auto by zuitools
+***********************************************/
+#include "DeviceUpdateActivity.h"
+
+/*TAG:GlobalVariable全局变量*/
+static ZKButton* msys_backPtr;
+static ZKWindow* mWindow1Ptr;
+static ZKTextView* mVersionNoNewPtr;
+static ZKTextView* mTextView8Ptr;
+static ZKTextView* mVersionNewPtr;
+static ZKTextView* mVersionNoPtr;
+static ZKTextView* mTextView7Ptr;
+static ZKTextView* mVersionPtr;
+static ZKButton* mButtonDialog1Ptr;
+static ZKTextView* mTextViewDialog1Ptr;
+static ZKTextView* mTextView6Ptr;
+static ZKWindow* mWindowDialog1Ptr;
+static ZKTextView* mTextViewProgressMessagePtr;
+static ZKTextView* mTextViewProgressLoadingPtr;
+static ZKTextView* mTextView4Ptr;
+static ZKWindow* mWindowProgressPtr;
+static ZKButton* mButtonInstantlyPtr;
+static ZKTextView* mTextView3Ptr;
+static ZKTextView* mTextView5Ptr;
+static ZKWindow* mWindowFindPtr;
+static ZKTextView* mTextViewTitlePtr;
+static ZKTextView* mTextView1Ptr;
+static ZKButton* mButtonUpdatePtr;
+static ZKTextView* mTextView2Ptr;
+static DeviceUpdateActivity* mActivityPtr;
+
+/*register activity*/
+REGISTER_ACTIVITY(DeviceUpdateActivity);
+
+typedef struct {
+	int id; // 定时器ID , 不能重复
+	int time; // 定时器  时间间隔  单位 毫秒
+}S_ACTIVITY_TIMEER;
+
+#include "logic/DeviceUpdateLogic.cc"
+
+/***********/
+typedef struct {
+    int id;
+    const char *pApp;
+} SAppInfo;
+
+/**
+ *点击跳转window
+ */
+static SAppInfo sAppInfoTab[] = {
+//  { ID_MAIN_TEXT, "TextViewActivity" },
+};
+
+/***************/
+typedef bool (*ButtonCallback)(ZKButton *pButton);
+/**
+ * button onclick表
+ */
+typedef struct {
+    int id;
+    ButtonCallback callback;
+}S_ButtonCallback;
+
+/*TAG:ButtonCallbackTab按键映射表*/
+static S_ButtonCallback sButtonCallbackTab[] = {
+    ID_DEVICEUPDATE_sys_back, onButtonClick_sys_back,
+    ID_DEVICEUPDATE_ButtonDialog1, onButtonClick_ButtonDialog1,
+    ID_DEVICEUPDATE_ButtonInstantly, onButtonClick_ButtonInstantly,
+    ID_DEVICEUPDATE_ButtonUpdate, onButtonClick_ButtonUpdate,
+};
+/***************/
+
+
+typedef void (*SeekBarCallback)(ZKSeekBar *pSeekBar, int progress);
+typedef struct {
+    int id;
+    SeekBarCallback callback;
+}S_ZKSeekBarCallback;
+/*TAG:SeekBarCallbackTab*/
+static S_ZKSeekBarCallback SZKSeekBarCallbackTab[] = {
+};
+
+
+typedef int (*ListViewGetItemCountCallback)(const ZKListView *pListView);
+typedef void (*ListViewobtainListItemDataCallback)(ZKListView *pListView,ZKListView::ZKListItem *pListItem, int index);
+typedef void (*ListViewonItemClickCallback)(ZKListView *pListView, int index, int id);
+typedef struct {
+    int id;
+    ListViewGetItemCountCallback getListItemCountCallback;
+    ListViewobtainListItemDataCallback obtainListItemDataCallback;
+    ListViewonItemClickCallback onItemClickCallback;
+}S_ListViewFunctionsCallback;
+/*TAG:ListViewFunctionsCallback*/
+static S_ListViewFunctionsCallback SListViewFunctionsCallbackTab[] = {
+};
+
+
+typedef void (*SlideWindowItemClickCallback)(ZKSlideWindow *pSlideWindow, int index);
+typedef struct {
+    int id;
+    SlideWindowItemClickCallback onSlideItemClickCallback;
+}S_SlideWindowItemClickCallback;
+/*TAG:SlideWindowFunctionsCallbackTab*/
+static S_SlideWindowItemClickCallback SSlideWindowItemClickCallbackTab[] = {
+};
+
+
+typedef void (*EditTextInputCallback)(const std::string &text);
+typedef struct {
+    int id;
+    EditTextInputCallback onEditTextChangedCallback;
+}S_EditTextInputCallback;
+/*TAG:EditTextInputCallback*/
+static S_EditTextInputCallback SEditTextInputCallbackTab[] = {
+};
+
+typedef void (*VideoViewCallback)(ZKVideoView *pVideoView, int msg);
+typedef struct {
+    int id; //VideoView ID
+    bool loop; // 是否是轮播类型
+    int defaultvolume;//轮播类型时,默认视频音量
+    VideoViewCallback onVideoViewCallback;
+}S_VideoViewCallback;
+/*TAG:VideoViewCallback*/
+static S_VideoViewCallback SVideoViewCallbackTab[] = {
+};
+
+
+DeviceUpdateActivity::DeviceUpdateActivity() {
+	//todo add init code here
+	mVideoLoopIndex = -1;
+	mVideoLoopErrorCount = 0;
+}
+
+DeviceUpdateActivity::~DeviceUpdateActivity() {
+  //todo add init file here
+  // 退出应用时需要反注册
+    EASYUICONTEXT->unregisterGlobalTouchListener(this);
+    onUI_quit();
+    unregisterProtocolDataUpdateListener(onProtocolDataUpdate);
+    msys_backPtr = NULL;
+    mWindow1Ptr = NULL;
+    mVersionNoNewPtr = NULL;
+    mTextView8Ptr = NULL;
+    mVersionNewPtr = NULL;
+    mVersionNoPtr = NULL;
+    mTextView7Ptr = NULL;
+    mVersionPtr = NULL;
+    mButtonDialog1Ptr = NULL;
+    mTextViewDialog1Ptr = NULL;
+    mTextView6Ptr = NULL;
+    mWindowDialog1Ptr = NULL;
+    mTextViewProgressMessagePtr = NULL;
+    mTextViewProgressLoadingPtr = NULL;
+    mTextView4Ptr = NULL;
+    mWindowProgressPtr = NULL;
+    mButtonInstantlyPtr = NULL;
+    mTextView3Ptr = NULL;
+    mTextView5Ptr = NULL;
+    mWindowFindPtr = NULL;
+    mTextViewTitlePtr = NULL;
+    mTextView1Ptr = NULL;
+    mButtonUpdatePtr = NULL;
+    mTextView2Ptr = NULL;
+    mActivityPtr = NULL;
+}
+
+const char* DeviceUpdateActivity::getAppName() const{
+	return "DeviceUpdate.ftu";
+}
+
+//TAG:onCreate
+void DeviceUpdateActivity::onCreate() {
+	Activity::onCreate();
+    msys_backPtr = (ZKButton*)findControlByID(ID_DEVICEUPDATE_sys_back);
+    mWindow1Ptr = (ZKWindow*)findControlByID(ID_DEVICEUPDATE_Window1);
+    mVersionNoNewPtr = (ZKTextView*)findControlByID(ID_DEVICEUPDATE_VersionNoNew);
+    mTextView8Ptr = (ZKTextView*)findControlByID(ID_DEVICEUPDATE_TextView8);
+    mVersionNewPtr = (ZKTextView*)findControlByID(ID_DEVICEUPDATE_VersionNew);
+    mVersionNoPtr = (ZKTextView*)findControlByID(ID_DEVICEUPDATE_VersionNo);
+    mTextView7Ptr = (ZKTextView*)findControlByID(ID_DEVICEUPDATE_TextView7);
+    mVersionPtr = (ZKTextView*)findControlByID(ID_DEVICEUPDATE_Version);
+    mButtonDialog1Ptr = (ZKButton*)findControlByID(ID_DEVICEUPDATE_ButtonDialog1);
+    mTextViewDialog1Ptr = (ZKTextView*)findControlByID(ID_DEVICEUPDATE_TextViewDialog1);
+    mTextView6Ptr = (ZKTextView*)findControlByID(ID_DEVICEUPDATE_TextView6);
+    mWindowDialog1Ptr = (ZKWindow*)findControlByID(ID_DEVICEUPDATE_WindowDialog1);
+    mTextViewProgressMessagePtr = (ZKTextView*)findControlByID(ID_DEVICEUPDATE_TextViewProgressMessage);
+    mTextViewProgressLoadingPtr = (ZKTextView*)findControlByID(ID_DEVICEUPDATE_TextViewProgressLoading);
+    mTextView4Ptr = (ZKTextView*)findControlByID(ID_DEVICEUPDATE_TextView4);
+    mWindowProgressPtr = (ZKWindow*)findControlByID(ID_DEVICEUPDATE_WindowProgress);
+    mButtonInstantlyPtr = (ZKButton*)findControlByID(ID_DEVICEUPDATE_ButtonInstantly);
+    mTextView3Ptr = (ZKTextView*)findControlByID(ID_DEVICEUPDATE_TextView3);
+    mTextView5Ptr = (ZKTextView*)findControlByID(ID_DEVICEUPDATE_TextView5);
+    mWindowFindPtr = (ZKWindow*)findControlByID(ID_DEVICEUPDATE_WindowFind);
+    mTextViewTitlePtr = (ZKTextView*)findControlByID(ID_DEVICEUPDATE_TextViewTitle);
+    mTextView1Ptr = (ZKTextView*)findControlByID(ID_DEVICEUPDATE_TextView1);
+    mButtonUpdatePtr = (ZKButton*)findControlByID(ID_DEVICEUPDATE_ButtonUpdate);
+    mTextView2Ptr = (ZKTextView*)findControlByID(ID_DEVICEUPDATE_TextView2);
+	mActivityPtr = this;
+	onUI_init();
+    registerProtocolDataUpdateListener(onProtocolDataUpdate); 
+    rigesterActivityTimer();
+}
+
+void DeviceUpdateActivity::onClick(ZKBase *pBase) {
+	//TODO: add widget onClik code 
+    int buttonTablen = sizeof(sButtonCallbackTab) / sizeof(S_ButtonCallback);
+    for (int i = 0; i < buttonTablen; ++i) {
+        if (sButtonCallbackTab[i].id == pBase->getID()) {
+            if (sButtonCallbackTab[i].callback((ZKButton*)pBase)) {
+            	return;
+            }
+            break;
+        }
+    }
+
+
+    int len = sizeof(sAppInfoTab) / sizeof(sAppInfoTab[0]);
+    for (int i = 0; i < len; ++i) {
+        if (sAppInfoTab[i].id == pBase->getID()) {
+            EASYUICONTEXT->openActivity(sAppInfoTab[i].pApp);
+            return;
+        }
+    }
+
+	Activity::onClick(pBase);
+}
+
+void DeviceUpdateActivity::onResume() {
+	Activity::onResume();
+	EASYUICONTEXT->registerGlobalTouchListener(this);
+	startVideoLoopPlayback();
+	onUI_show();
+}
+
+void DeviceUpdateActivity::onPause() {
+	Activity::onPause();
+	EASYUICONTEXT->unregisterGlobalTouchListener(this);
+	stopVideoLoopPlayback();
+	onUI_hide();
+}
+
+void DeviceUpdateActivity::onIntent(const Intent *intentPtr) {
+	Activity::onIntent(intentPtr);
+	onUI_intent(intentPtr);
+}
+
+bool DeviceUpdateActivity::onTimer(int id) {
+	return onUI_Timer(id);
+}
+
+void DeviceUpdateActivity::onProgressChanged(ZKSeekBar *pSeekBar, int progress){
+
+    int seekBarTablen = sizeof(SZKSeekBarCallbackTab) / sizeof(S_ZKSeekBarCallback);
+    for (int i = 0; i < seekBarTablen; ++i) {
+        if (SZKSeekBarCallbackTab[i].id == pSeekBar->getID()) {
+            SZKSeekBarCallbackTab[i].callback(pSeekBar, progress);
+            break;
+        }
+    }
+}
+
+int DeviceUpdateActivity::getListItemCount(const ZKListView *pListView) const{
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            return SListViewFunctionsCallbackTab[i].getListItemCountCallback(pListView);
+            break;
+        }
+    }
+    return 0;
+}
+
+void DeviceUpdateActivity::obtainListItemData(ZKListView *pListView,ZKListView::ZKListItem *pListItem, int index){
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            SListViewFunctionsCallbackTab[i].obtainListItemDataCallback(pListView, pListItem, index);
+            break;
+        }
+    }
+}
+
+void DeviceUpdateActivity::onItemClick(ZKListView *pListView, int index, int id){
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            SListViewFunctionsCallbackTab[i].onItemClickCallback(pListView, index, id);
+            break;
+        }
+    }
+}
+
+void DeviceUpdateActivity::onSlideItemClick(ZKSlideWindow *pSlideWindow, int index) {
+    int tablen = sizeof(SSlideWindowItemClickCallbackTab) / sizeof(S_SlideWindowItemClickCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SSlideWindowItemClickCallbackTab[i].id == pSlideWindow->getID()) {
+            SSlideWindowItemClickCallbackTab[i].onSlideItemClickCallback(pSlideWindow, index);
+            break;
+        }
+    }
+}
+
+bool DeviceUpdateActivity::onTouchEvent(const MotionEvent &ev) {
+    return onDeviceUpdateActivityTouchEvent(ev);
+}
+
+void DeviceUpdateActivity::onTextChanged(ZKTextView *pTextView, const std::string &text) {
+    int tablen = sizeof(SEditTextInputCallbackTab) / sizeof(S_EditTextInputCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SEditTextInputCallbackTab[i].id == pTextView->getID()) {
+            SEditTextInputCallbackTab[i].onEditTextChangedCallback(text);
+            break;
+        }
+    }
+}
+
+void DeviceUpdateActivity::rigesterActivityTimer() {
+    int tablen = sizeof(REGISTER_ACTIVITY_TIMER_TAB) / sizeof(S_ACTIVITY_TIMEER);
+    for (int i = 0; i < tablen; ++i) {
+        S_ACTIVITY_TIMEER temp = REGISTER_ACTIVITY_TIMER_TAB[i];
+        registerTimer(temp.id, temp.time);
+    }
+}
+
+
+void DeviceUpdateActivity::onVideoPlayerMessage(ZKVideoView *pVideoView, int msg) {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SVideoViewCallbackTab[i].id == pVideoView->getID()) {
+        	if (SVideoViewCallbackTab[i].loop) {
+                //循环播放
+        		videoLoopPlayback(pVideoView, msg, i);
+        	} else if (SVideoViewCallbackTab[i].onVideoViewCallback != NULL){
+        	    SVideoViewCallbackTab[i].onVideoViewCallback(pVideoView, msg);
+        	}
+            break;
+        }
+    }
+}
+
+void DeviceUpdateActivity::videoLoopPlayback(ZKVideoView *pVideoView, int msg, size_t callbackTabIndex) {
+
+	switch (msg) {
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_STARTED:
+		LOGD("ZKVideoView::E_MSGTYPE_VIDEO_PLAY_STARTED\n");
+    if (callbackTabIndex >= (sizeof(SVideoViewCallbackTab)/sizeof(S_VideoViewCallback))) {
+      break;
+    }
+		pVideoView->setVolume(SVideoViewCallbackTab[callbackTabIndex].defaultvolume / 10.0);
+		mVideoLoopErrorCount = 0;
+		break;
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_ERROR:
+		/**错误处理 */
+		++mVideoLoopErrorCount;
+		if (mVideoLoopErrorCount > 100) {
+			LOGD("video loop error counts > 100, quit loop playback !");
+            break;
+		} //不用break, 继续尝试播放下一个
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED:
+		LOGD("ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED\n");
+        std::vector<std::string> videolist;
+        std::string fileName(getAppName());
+        if (fileName.size() < 4) {
+             LOGD("getAppName size < 4, ignore!");
+             break;
+        }
+        fileName = fileName.substr(0, fileName.length() - 4) + "_video_list.txt";
+        fileName = "/mnt/extsd/" + fileName;
+        if (!parseVideoFileList(fileName.c_str(), videolist)) {
+            LOGD("parseVideoFileList failed !");
+		    break;
+        }
+		if (pVideoView && !videolist.empty()) {
+			mVideoLoopIndex = (mVideoLoopIndex + 1) % videolist.size();
+			pVideoView->play(videolist[mVideoLoopIndex].c_str());
+		}
+		break;
+	}
+}
+
+void DeviceUpdateActivity::startVideoLoopPlayback() {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+    	if (SVideoViewCallbackTab[i].loop) {
+    		ZKVideoView* videoView = (ZKVideoView*)findControlByID(SVideoViewCallbackTab[i].id);
+    		if (!videoView) {
+    			return;
+    		}
+    		//循环播放
+    		videoLoopPlayback(videoView, ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED, i);
+    		return;
+    	}
+    }
+}
+
+void DeviceUpdateActivity::stopVideoLoopPlayback() {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+    	if (SVideoViewCallbackTab[i].loop) {
+    		ZKVideoView* videoView = (ZKVideoView*)findControlByID(SVideoViewCallbackTab[i].id);
+    		if (!videoView) {
+    			return;
+    		}
+    		if (videoView->isPlaying()) {
+    		    videoView->stop();
+    		}
+    		return;
+    	}
+    }
+}
+
+bool DeviceUpdateActivity::parseVideoFileList(const char *pFileListPath, std::vector<string>& mediaFileList) {
+	mediaFileList.clear();
+	if (NULL == pFileListPath || 0 == strlen(pFileListPath)) {
+        LOGD("video file list is null!");
+		return false;
+	}
+
+	ifstream is(pFileListPath, ios_base::in);
+	if (!is.is_open()) {
+		LOGD("cann't open file %s \n", pFileListPath);
+		return false;
+	}
+	char tmp[1024] = {0};
+	while (is.getline(tmp, sizeof(tmp))) {
+		string str = tmp;
+		removeCharFromString(str, '\"');
+		removeCharFromString(str, '\r');
+		removeCharFromString(str, '\n');
+		if (str.size() > 1) {
+     		mediaFileList.push_back(str.c_str());
+		}
+	}
+  LOGD("(f:%s, l:%d) parse fileList[%s], get [%d]files", __FUNCTION__,
+      __LINE__, pFileListPath, int(mediaFileList.size()));
+  for (std::vector<string>::size_type i = 0; i < mediaFileList.size(); i++) {
+    LOGD("file[%u]:[%s]", ::size_t(i), mediaFileList[i].c_str());
+  }
+	is.close();
+
+	return true;
+}
+
+int DeviceUpdateActivity::removeCharFromString(string& nString, char c) {
+    string::size_type   pos;
+    while(1) {
+        pos = nString.find(c);
+        if(pos != string::npos) {
+            nString.erase(pos, 1);
+        } else {
+            break;
+        }
+    }
+    return (int)nString.size();
+}
+
+void DeviceUpdateActivity::registerUserTimer(int id, int time) {
+	registerTimer(id, time);
+}
+
+void DeviceUpdateActivity::unregisterUserTimer(int id) {
+	unregisterTimer(id);
+}
+
+void DeviceUpdateActivity::resetUserTimer(int id, int time) {
+	resetTimer(id, time);
+}

+ 120 - 0
jni/activity/DeviceUpdateActivity.h

@@ -0,0 +1,120 @@
+/***********************************************
+/gen auto by zuitools
+***********************************************/
+#ifndef __DEVICEUPDATEACTIVITY_H__
+#define __DEVICEUPDATEACTIVITY_H__
+
+
+#include "app/Activity.h"
+#include "entry/EasyUIContext.h"
+
+#include "uart/ProtocolData.h"
+#include "uart/ProtocolParser.h"
+
+#include "utils/Log.h"
+#include "control/ZKDigitalClock.h"
+#include "control/ZKButton.h"
+#include "control/ZKCircleBar.h"
+#include "control/ZKDiagram.h"
+#include "control/ZKListView.h"
+#include "control/ZKPointer.h"
+#include "control/ZKQRCode.h"
+#include "control/ZKTextView.h"
+#include "control/ZKSeekBar.h"
+#include "control/ZKEditText.h"
+#include "control/ZKVideoView.h"
+#include "window/ZKSlideWindow.h"
+
+/*TAG:Macro宏ID*/
+#define ID_DEVICEUPDATE_sys_back   100
+#define ID_DEVICEUPDATE_Window1    110004
+#define ID_DEVICEUPDATE_VersionNoNew    50016
+#define ID_DEVICEUPDATE_TextView8    50015
+#define ID_DEVICEUPDATE_VersionNew    50004
+#define ID_DEVICEUPDATE_VersionNo    50014
+#define ID_DEVICEUPDATE_TextView7    50013
+#define ID_DEVICEUPDATE_Version    50002
+#define ID_DEVICEUPDATE_ButtonDialog1    20006
+#define ID_DEVICEUPDATE_TextViewDialog1    50011
+#define ID_DEVICEUPDATE_TextView6    50010
+#define ID_DEVICEUPDATE_WindowDialog1    110003
+#define ID_DEVICEUPDATE_TextViewProgressMessage    50012
+#define ID_DEVICEUPDATE_TextViewProgressLoading    50008
+#define ID_DEVICEUPDATE_TextView4    50007
+#define ID_DEVICEUPDATE_WindowProgress    110002
+#define ID_DEVICEUPDATE_ButtonInstantly    20002
+#define ID_DEVICEUPDATE_TextView3    50003
+#define ID_DEVICEUPDATE_TextView5    50005
+#define ID_DEVICEUPDATE_WindowFind    110001
+#define ID_DEVICEUPDATE_TextViewTitle    50009
+#define ID_DEVICEUPDATE_TextView1    50001
+#define ID_DEVICEUPDATE_ButtonUpdate    20001
+#define ID_DEVICEUPDATE_TextView2    50006
+/*TAG:Macro宏ID END*/
+
+class DeviceUpdateActivity : public Activity, 
+                     public ZKSeekBar::ISeekBarChangeListener, 
+                     public ZKListView::IItemClickListener,
+                     public ZKListView::AbsListAdapter,
+                     public ZKSlideWindow::ISlideItemClickListener,
+                     public EasyUIContext::ITouchListener,
+                     public ZKEditText::ITextChangeListener,
+                     public ZKVideoView::IVideoPlayerMessageListener
+{
+public:
+    DeviceUpdateActivity();
+    virtual ~DeviceUpdateActivity();
+
+    /**
+     * 注册定时器
+     */
+	void registerUserTimer(int id, int time);
+	/**
+	 * 取消定时器
+	 */
+	void unregisterUserTimer(int id);
+	/**
+	 * 重置定时器
+	 */
+	void resetUserTimer(int id, int time);
+
+protected:
+    /*TAG:PROTECTED_FUNCTION*/
+    virtual const char* getAppName() const;
+    virtual void onCreate();
+    virtual void onClick(ZKBase *pBase);
+    virtual void onResume();
+    virtual void onPause();
+    virtual void onIntent(const Intent *intentPtr);
+    virtual bool onTimer(int id);
+
+    virtual void onProgressChanged(ZKSeekBar *pSeekBar, int progress);
+
+    virtual int getListItemCount(const ZKListView *pListView) const;
+    virtual void obtainListItemData(ZKListView *pListView, ZKListView::ZKListItem *pListItem, int index);
+    virtual void onItemClick(ZKListView *pListView, int index, int subItemIndex);
+
+    virtual void onSlideItemClick(ZKSlideWindow *pSlideWindow, int index);
+
+    virtual bool onTouchEvent(const MotionEvent &ev);
+
+    virtual void onTextChanged(ZKTextView *pTextView, const string &text);
+
+    void rigesterActivityTimer();
+
+    virtual void onVideoPlayerMessage(ZKVideoView *pVideoView, int msg);
+    void videoLoopPlayback(ZKVideoView *pVideoView, int msg, size_t callbackTabIndex);
+    void startVideoLoopPlayback();
+    void stopVideoLoopPlayback();
+    bool parseVideoFileList(const char *pFileListPath, std::vector<string>& mediaFileList);
+    int removeCharFromString(string& nString, char c);
+
+
+private:
+    /*TAG:PRIVATE_VARIABLE*/
+    int mVideoLoopIndex;
+    int mVideoLoopErrorCount;
+
+};
+
+#endif

+ 426 - 0
jni/activity/callActivity.cpp

@@ -0,0 +1,426 @@
+/***********************************************
+/gen auto by zuitools
+***********************************************/
+#include "callActivity.h"
+
+/*TAG:GlobalVariable全局变量*/
+static ZKButton* mButtonHangupPtr;
+static ZKTextView* mTextViewNamePtr;
+static ZKTextView* mTextViewDurationPtr;
+static ZKTextView* mTextViewStatePtr;
+static ZKTextView* mTextViewOutputVolumePtr;
+static ZKSeekBar* mSeekBarOutputVolumePtr;
+static ZKButton* mButtonVolPtr;
+static ZKButton* mButtonAnswerPtr;
+static ZKVideoView* mVideoView1Ptr;
+static callActivity* mActivityPtr;
+
+/*register activity*/
+REGISTER_ACTIVITY(callActivity);
+
+typedef struct {
+	int id; // 定时器ID , 不能重复
+	int time; // 定时器  时间间隔  单位 毫秒
+}S_ACTIVITY_TIMEER;
+
+#include "logic/callLogic.cc"
+
+/***********/
+typedef struct {
+    int id;
+    const char *pApp;
+} SAppInfo;
+
+/**
+ *点击跳转window
+ */
+static SAppInfo sAppInfoTab[] = {
+//  { ID_MAIN_TEXT, "TextViewActivity" },
+};
+
+/***************/
+typedef bool (*ButtonCallback)(ZKButton *pButton);
+/**
+ * button onclick表
+ */
+typedef struct {
+    int id;
+    ButtonCallback callback;
+}S_ButtonCallback;
+
+/*TAG:ButtonCallbackTab按键映射表*/
+static S_ButtonCallback sButtonCallbackTab[] = {
+    ID_CALL_ButtonHangup, onButtonClick_ButtonHangup,
+    ID_CALL_ButtonVol, onButtonClick_ButtonVol,
+    ID_CALL_ButtonAnswer, onButtonClick_ButtonAnswer,
+};
+/***************/
+
+
+typedef void (*SeekBarCallback)(ZKSeekBar *pSeekBar, int progress);
+typedef struct {
+    int id;
+    SeekBarCallback callback;
+}S_ZKSeekBarCallback;
+/*TAG:SeekBarCallbackTab*/
+static S_ZKSeekBarCallback SZKSeekBarCallbackTab[] = {
+    ID_CALL_SeekBarOutputVolume, onProgressChanged_SeekBarOutputVolume,
+};
+
+
+typedef int (*ListViewGetItemCountCallback)(const ZKListView *pListView);
+typedef void (*ListViewobtainListItemDataCallback)(ZKListView *pListView,ZKListView::ZKListItem *pListItem, int index);
+typedef void (*ListViewonItemClickCallback)(ZKListView *pListView, int index, int id);
+typedef struct {
+    int id;
+    ListViewGetItemCountCallback getListItemCountCallback;
+    ListViewobtainListItemDataCallback obtainListItemDataCallback;
+    ListViewonItemClickCallback onItemClickCallback;
+}S_ListViewFunctionsCallback;
+/*TAG:ListViewFunctionsCallback*/
+static S_ListViewFunctionsCallback SListViewFunctionsCallbackTab[] = {
+};
+
+
+typedef void (*SlideWindowItemClickCallback)(ZKSlideWindow *pSlideWindow, int index);
+typedef struct {
+    int id;
+    SlideWindowItemClickCallback onSlideItemClickCallback;
+}S_SlideWindowItemClickCallback;
+/*TAG:SlideWindowFunctionsCallbackTab*/
+static S_SlideWindowItemClickCallback SSlideWindowItemClickCallbackTab[] = {
+};
+
+
+typedef void (*EditTextInputCallback)(const std::string &text);
+typedef struct {
+    int id;
+    EditTextInputCallback onEditTextChangedCallback;
+}S_EditTextInputCallback;
+/*TAG:EditTextInputCallback*/
+static S_EditTextInputCallback SEditTextInputCallbackTab[] = {
+};
+
+typedef void (*VideoViewCallback)(ZKVideoView *pVideoView, int msg);
+typedef struct {
+    int id; //VideoView ID
+    bool loop; // 是否是轮播类型
+    int defaultvolume;//轮播类型时,默认视频音量
+    VideoViewCallback onVideoViewCallback;
+}S_VideoViewCallback;
+/*TAG:VideoViewCallback*/
+static S_VideoViewCallback SVideoViewCallbackTab[] = {
+    ID_CALL_VideoView1, false, 5, onVideoViewPlayerMessageListener_VideoView1,
+};
+
+
+callActivity::callActivity() {
+	//todo add init code here
+	mVideoLoopIndex = -1;
+	mVideoLoopErrorCount = 0;
+}
+
+callActivity::~callActivity() {
+  //todo add init file here
+  // 退出应用时需要反注册
+    EASYUICONTEXT->unregisterGlobalTouchListener(this);
+    onUI_quit();
+    unregisterProtocolDataUpdateListener(onProtocolDataUpdate);
+    mButtonHangupPtr = NULL;
+    mTextViewNamePtr = NULL;
+    mTextViewDurationPtr = NULL;
+    mTextViewStatePtr = NULL;
+    mTextViewOutputVolumePtr = NULL;
+    mSeekBarOutputVolumePtr = NULL;
+    mButtonVolPtr = NULL;
+    mButtonAnswerPtr = NULL;
+    mVideoView1Ptr = NULL;
+    mActivityPtr = NULL;
+}
+
+const char* callActivity::getAppName() const{
+	return "call.ftu";
+}
+
+//TAG:onCreate
+void callActivity::onCreate() {
+	Activity::onCreate();
+    mButtonHangupPtr = (ZKButton*)findControlByID(ID_CALL_ButtonHangup);
+    mTextViewNamePtr = (ZKTextView*)findControlByID(ID_CALL_TextViewName);
+    mTextViewDurationPtr = (ZKTextView*)findControlByID(ID_CALL_TextViewDuration);
+    mTextViewStatePtr = (ZKTextView*)findControlByID(ID_CALL_TextViewState);
+    mTextViewOutputVolumePtr = (ZKTextView*)findControlByID(ID_CALL_TextViewOutputVolume);
+    mSeekBarOutputVolumePtr = (ZKSeekBar*)findControlByID(ID_CALL_SeekBarOutputVolume);if(mSeekBarOutputVolumePtr!= NULL){mSeekBarOutputVolumePtr->setSeekBarChangeListener(this);}
+    mButtonVolPtr = (ZKButton*)findControlByID(ID_CALL_ButtonVol);
+    mButtonAnswerPtr = (ZKButton*)findControlByID(ID_CALL_ButtonAnswer);
+    mVideoView1Ptr = (ZKVideoView*)findControlByID(ID_CALL_VideoView1);if(mVideoView1Ptr!= NULL){mVideoView1Ptr->setVideoPlayerMessageListener(this);}
+	mActivityPtr = this;
+	onUI_init();
+    registerProtocolDataUpdateListener(onProtocolDataUpdate); 
+    rigesterActivityTimer();
+}
+
+void callActivity::onClick(ZKBase *pBase) {
+	//TODO: add widget onClik code 
+    int buttonTablen = sizeof(sButtonCallbackTab) / sizeof(S_ButtonCallback);
+    for (int i = 0; i < buttonTablen; ++i) {
+        if (sButtonCallbackTab[i].id == pBase->getID()) {
+            if (sButtonCallbackTab[i].callback((ZKButton*)pBase)) {
+            	return;
+            }
+            break;
+        }
+    }
+
+
+    int len = sizeof(sAppInfoTab) / sizeof(sAppInfoTab[0]);
+    for (int i = 0; i < len; ++i) {
+        if (sAppInfoTab[i].id == pBase->getID()) {
+            EASYUICONTEXT->openActivity(sAppInfoTab[i].pApp);
+            return;
+        }
+    }
+
+	Activity::onClick(pBase);
+}
+
+void callActivity::onResume() {
+	Activity::onResume();
+	EASYUICONTEXT->registerGlobalTouchListener(this);
+	startVideoLoopPlayback();
+	onUI_show();
+}
+
+void callActivity::onPause() {
+	Activity::onPause();
+	EASYUICONTEXT->unregisterGlobalTouchListener(this);
+	stopVideoLoopPlayback();
+	onUI_hide();
+}
+
+void callActivity::onIntent(const Intent *intentPtr) {
+	Activity::onIntent(intentPtr);
+	onUI_intent(intentPtr);
+}
+
+bool callActivity::onTimer(int id) {
+	return onUI_Timer(id);
+}
+
+void callActivity::onProgressChanged(ZKSeekBar *pSeekBar, int progress){
+
+    int seekBarTablen = sizeof(SZKSeekBarCallbackTab) / sizeof(S_ZKSeekBarCallback);
+    for (int i = 0; i < seekBarTablen; ++i) {
+        if (SZKSeekBarCallbackTab[i].id == pSeekBar->getID()) {
+            SZKSeekBarCallbackTab[i].callback(pSeekBar, progress);
+            break;
+        }
+    }
+}
+
+int callActivity::getListItemCount(const ZKListView *pListView) const{
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            return SListViewFunctionsCallbackTab[i].getListItemCountCallback(pListView);
+            break;
+        }
+    }
+    return 0;
+}
+
+void callActivity::obtainListItemData(ZKListView *pListView,ZKListView::ZKListItem *pListItem, int index){
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            SListViewFunctionsCallbackTab[i].obtainListItemDataCallback(pListView, pListItem, index);
+            break;
+        }
+    }
+}
+
+void callActivity::onItemClick(ZKListView *pListView, int index, int id){
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            SListViewFunctionsCallbackTab[i].onItemClickCallback(pListView, index, id);
+            break;
+        }
+    }
+}
+
+void callActivity::onSlideItemClick(ZKSlideWindow *pSlideWindow, int index) {
+    int tablen = sizeof(SSlideWindowItemClickCallbackTab) / sizeof(S_SlideWindowItemClickCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SSlideWindowItemClickCallbackTab[i].id == pSlideWindow->getID()) {
+            SSlideWindowItemClickCallbackTab[i].onSlideItemClickCallback(pSlideWindow, index);
+            break;
+        }
+    }
+}
+
+bool callActivity::onTouchEvent(const MotionEvent &ev) {
+    return oncallActivityTouchEvent(ev);
+}
+
+void callActivity::onTextChanged(ZKTextView *pTextView, const std::string &text) {
+    int tablen = sizeof(SEditTextInputCallbackTab) / sizeof(S_EditTextInputCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SEditTextInputCallbackTab[i].id == pTextView->getID()) {
+            SEditTextInputCallbackTab[i].onEditTextChangedCallback(text);
+            break;
+        }
+    }
+}
+
+void callActivity::rigesterActivityTimer() {
+    int tablen = sizeof(REGISTER_ACTIVITY_TIMER_TAB) / sizeof(S_ACTIVITY_TIMEER);
+    for (int i = 0; i < tablen; ++i) {
+        S_ACTIVITY_TIMEER temp = REGISTER_ACTIVITY_TIMER_TAB[i];
+        registerTimer(temp.id, temp.time);
+    }
+}
+
+
+void callActivity::onVideoPlayerMessage(ZKVideoView *pVideoView, int msg) {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SVideoViewCallbackTab[i].id == pVideoView->getID()) {
+        	if (SVideoViewCallbackTab[i].loop) {
+                //循环播放
+        		videoLoopPlayback(pVideoView, msg, i);
+        	} else if (SVideoViewCallbackTab[i].onVideoViewCallback != NULL){
+        	    SVideoViewCallbackTab[i].onVideoViewCallback(pVideoView, msg);
+        	}
+            break;
+        }
+    }
+}
+
+void callActivity::videoLoopPlayback(ZKVideoView *pVideoView, int msg, size_t callbackTabIndex) {
+
+	switch (msg) {
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_STARTED:
+		LOGD("ZKVideoView::E_MSGTYPE_VIDEO_PLAY_STARTED\n");
+    if (callbackTabIndex >= (sizeof(SVideoViewCallbackTab)/sizeof(S_VideoViewCallback))) {
+      break;
+    }
+		pVideoView->setVolume(SVideoViewCallbackTab[callbackTabIndex].defaultvolume / 10.0);
+		mVideoLoopErrorCount = 0;
+		break;
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_ERROR:
+		/**错误处理 */
+		++mVideoLoopErrorCount;
+		if (mVideoLoopErrorCount > 100) {
+			LOGD("video loop error counts > 100, quit loop playback !");
+            break;
+		} //不用break, 继续尝试播放下一个
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED:
+		LOGD("ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED\n");
+        std::vector<std::string> videolist;
+        std::string fileName(getAppName());
+        if (fileName.size() < 4) {
+             LOGD("getAppName size < 4, ignore!");
+             break;
+        }
+        fileName = fileName.substr(0, fileName.length() - 4) + "_video_list.txt";
+        fileName = "/mnt/extsd/" + fileName;
+        if (!parseVideoFileList(fileName.c_str(), videolist)) {
+            LOGD("parseVideoFileList failed !");
+		    break;
+        }
+		if (pVideoView && !videolist.empty()) {
+			mVideoLoopIndex = (mVideoLoopIndex + 1) % videolist.size();
+			pVideoView->play(videolist[mVideoLoopIndex].c_str());
+		}
+		break;
+	}
+}
+
+void callActivity::startVideoLoopPlayback() {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+    	if (SVideoViewCallbackTab[i].loop) {
+    		ZKVideoView* videoView = (ZKVideoView*)findControlByID(SVideoViewCallbackTab[i].id);
+    		if (!videoView) {
+    			return;
+    		}
+    		//循环播放
+    		videoLoopPlayback(videoView, ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED, i);
+    		return;
+    	}
+    }
+}
+
+void callActivity::stopVideoLoopPlayback() {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+    	if (SVideoViewCallbackTab[i].loop) {
+    		ZKVideoView* videoView = (ZKVideoView*)findControlByID(SVideoViewCallbackTab[i].id);
+    		if (!videoView) {
+    			return;
+    		}
+    		if (videoView->isPlaying()) {
+    		    videoView->stop();
+    		}
+    		return;
+    	}
+    }
+}
+
+bool callActivity::parseVideoFileList(const char *pFileListPath, std::vector<string>& mediaFileList) {
+	mediaFileList.clear();
+	if (NULL == pFileListPath || 0 == strlen(pFileListPath)) {
+        LOGD("video file list is null!");
+		return false;
+	}
+
+	ifstream is(pFileListPath, ios_base::in);
+	if (!is.is_open()) {
+		LOGD("cann't open file %s \n", pFileListPath);
+		return false;
+	}
+	char tmp[1024] = {0};
+	while (is.getline(tmp, sizeof(tmp))) {
+		string str = tmp;
+		removeCharFromString(str, '\"');
+		removeCharFromString(str, '\r');
+		removeCharFromString(str, '\n');
+		if (str.size() > 1) {
+     		mediaFileList.push_back(str.c_str());
+		}
+	}
+  LOGD("(f:%s, l:%d) parse fileList[%s], get [%d]files", __FUNCTION__,
+      __LINE__, pFileListPath, int(mediaFileList.size()));
+  for (std::vector<string>::size_type i = 0; i < mediaFileList.size(); i++) {
+    LOGD("file[%u]:[%s]", ::size_t(i), mediaFileList[i].c_str());
+  }
+	is.close();
+
+	return true;
+}
+
+int callActivity::removeCharFromString(string& nString, char c) {
+    string::size_type   pos;
+    while(1) {
+        pos = nString.find(c);
+        if(pos != string::npos) {
+            nString.erase(pos, 1);
+        } else {
+            break;
+        }
+    }
+    return (int)nString.size();
+}
+
+void callActivity::registerUserTimer(int id, int time) {
+	registerTimer(id, time);
+}
+
+void callActivity::unregisterUserTimer(int id) {
+	unregisterTimer(id);
+}
+
+void callActivity::resetUserTimer(int id, int time) {
+	resetTimer(id, time);
+}

+ 105 - 0
jni/activity/callActivity.h

@@ -0,0 +1,105 @@
+/***********************************************
+/gen auto by zuitools
+***********************************************/
+#ifndef __CALLACTIVITY_H__
+#define __CALLACTIVITY_H__
+
+
+#include "app/Activity.h"
+#include "entry/EasyUIContext.h"
+
+#include "uart/ProtocolData.h"
+#include "uart/ProtocolParser.h"
+
+#include "utils/Log.h"
+#include "control/ZKDigitalClock.h"
+#include "control/ZKButton.h"
+#include "control/ZKCircleBar.h"
+#include "control/ZKDiagram.h"
+#include "control/ZKListView.h"
+#include "control/ZKPointer.h"
+#include "control/ZKQRCode.h"
+#include "control/ZKTextView.h"
+#include "control/ZKSeekBar.h"
+#include "control/ZKEditText.h"
+#include "control/ZKVideoView.h"
+#include "window/ZKSlideWindow.h"
+
+/*TAG:Macro宏ID*/
+#define ID_CALL_ButtonHangup    20004
+#define ID_CALL_TextViewName    50004
+#define ID_CALL_TextViewDuration    50001
+#define ID_CALL_TextViewState    50005
+#define ID_CALL_TextViewOutputVolume    50002
+#define ID_CALL_SeekBarOutputVolume    91001
+#define ID_CALL_ButtonVol    20003
+#define ID_CALL_ButtonAnswer    20001
+#define ID_CALL_VideoView1    95001
+/*TAG:Macro宏ID END*/
+
+class callActivity : public Activity, 
+                     public ZKSeekBar::ISeekBarChangeListener, 
+                     public ZKListView::IItemClickListener,
+                     public ZKListView::AbsListAdapter,
+                     public ZKSlideWindow::ISlideItemClickListener,
+                     public EasyUIContext::ITouchListener,
+                     public ZKEditText::ITextChangeListener,
+                     public ZKVideoView::IVideoPlayerMessageListener
+{
+public:
+    callActivity();
+    virtual ~callActivity();
+
+    /**
+     * 注册定时器
+     */
+	void registerUserTimer(int id, int time);
+	/**
+	 * 取消定时器
+	 */
+	void unregisterUserTimer(int id);
+	/**
+	 * 重置定时器
+	 */
+	void resetUserTimer(int id, int time);
+
+protected:
+    /*TAG:PROTECTED_FUNCTION*/
+    virtual const char* getAppName() const;
+    virtual void onCreate();
+    virtual void onClick(ZKBase *pBase);
+    virtual void onResume();
+    virtual void onPause();
+    virtual void onIntent(const Intent *intentPtr);
+    virtual bool onTimer(int id);
+
+    virtual void onProgressChanged(ZKSeekBar *pSeekBar, int progress);
+
+    virtual int getListItemCount(const ZKListView *pListView) const;
+    virtual void obtainListItemData(ZKListView *pListView, ZKListView::ZKListItem *pListItem, int index);
+    virtual void onItemClick(ZKListView *pListView, int index, int subItemIndex);
+
+    virtual void onSlideItemClick(ZKSlideWindow *pSlideWindow, int index);
+
+    virtual bool onTouchEvent(const MotionEvent &ev);
+
+    virtual void onTextChanged(ZKTextView *pTextView, const string &text);
+
+    void rigesterActivityTimer();
+
+    virtual void onVideoPlayerMessage(ZKVideoView *pVideoView, int msg);
+    void videoLoopPlayback(ZKVideoView *pVideoView, int msg, size_t callbackTabIndex);
+    void startVideoLoopPlayback();
+    void stopVideoLoopPlayback();
+    bool parseVideoFileList(const char *pFileListPath, std::vector<string>& mediaFileList);
+    int removeCharFromString(string& nString, char c);
+
+
+private:
+    /*TAG:PRIVATE_VARIABLE*/
+    int mVideoLoopIndex;
+    int mVideoLoopErrorCount;
+
+};
+
+#endif

+ 440 - 0
jni/activity/mainActivity.cpp

@@ -0,0 +1,440 @@
+/***********************************************
+/gen auto by zuitools
+***********************************************/
+#include "mainActivity.h"
+
+/*TAG:GlobalVariable全局变量*/
+static ZKButton* mMoreButtonPtr;
+static ZKButton* mNursingButtonPtr;
+static ZKButton* mCallCencelButtonPtr;
+static ZKButton* mHelpButtonPtr;
+static ZKButton* mCallNurseButtonPtr;
+static ZKButton* mCallBedButtonPtr;
+static ZKListView* mBedListViewPtr;
+static ZKTextView* mRoomNamePtr;
+static ZKTextView* mTextInfoPtr;
+static ZKTextView* mNurseNamePtr;
+static ZKTextView* mNurseTextPtr;
+static ZKTextView* mDoctorTextPtr;
+static ZKPainter* mPainterInfoPtr;
+static mainActivity* mActivityPtr;
+
+/*register activity*/
+REGISTER_ACTIVITY(mainActivity);
+
+typedef struct {
+	int id; // 定时器ID , 不能重复
+	int time; // 定时器  时间间隔  单位 毫秒
+}S_ACTIVITY_TIMEER;
+
+#include "logic/mainLogic.cc"
+
+/***********/
+typedef struct {
+    int id;
+    const char *pApp;
+} SAppInfo;
+
+/**
+ *点击跳转window
+ */
+static SAppInfo sAppInfoTab[] = {
+//  { ID_MAIN_TEXT, "TextViewActivity" },
+};
+
+/***************/
+typedef bool (*ButtonCallback)(ZKButton *pButton);
+/**
+ * button onclick表
+ */
+typedef struct {
+    int id;
+    ButtonCallback callback;
+}S_ButtonCallback;
+
+/*TAG:ButtonCallbackTab按键映射表*/
+static S_ButtonCallback sButtonCallbackTab[] = {
+    ID_MAIN_MoreButton, onButtonClick_MoreButton,
+    ID_MAIN_NursingButton, onButtonClick_NursingButton,
+    ID_MAIN_CallCencelButton, onButtonClick_CallCencelButton,
+    ID_MAIN_HelpButton, onButtonClick_HelpButton,
+    ID_MAIN_CallNurseButton, onButtonClick_CallNurseButton,
+    ID_MAIN_CallBedButton, onButtonClick_CallBedButton,
+};
+/***************/
+
+
+typedef void (*SeekBarCallback)(ZKSeekBar *pSeekBar, int progress);
+typedef struct {
+    int id;
+    SeekBarCallback callback;
+}S_ZKSeekBarCallback;
+/*TAG:SeekBarCallbackTab*/
+static S_ZKSeekBarCallback SZKSeekBarCallbackTab[] = {
+};
+
+
+typedef int (*ListViewGetItemCountCallback)(const ZKListView *pListView);
+typedef void (*ListViewobtainListItemDataCallback)(ZKListView *pListView,ZKListView::ZKListItem *pListItem, int index);
+typedef void (*ListViewonItemClickCallback)(ZKListView *pListView, int index, int id);
+typedef struct {
+    int id;
+    ListViewGetItemCountCallback getListItemCountCallback;
+    ListViewobtainListItemDataCallback obtainListItemDataCallback;
+    ListViewonItemClickCallback onItemClickCallback;
+}S_ListViewFunctionsCallback;
+/*TAG:ListViewFunctionsCallback*/
+static S_ListViewFunctionsCallback SListViewFunctionsCallbackTab[] = {
+    ID_MAIN_BedListView, getListItemCount_BedListView, obtainListItemData_BedListView, onListItemClick_BedListView,
+};
+
+
+typedef void (*SlideWindowItemClickCallback)(ZKSlideWindow *pSlideWindow, int index);
+typedef struct {
+    int id;
+    SlideWindowItemClickCallback onSlideItemClickCallback;
+}S_SlideWindowItemClickCallback;
+/*TAG:SlideWindowFunctionsCallbackTab*/
+static S_SlideWindowItemClickCallback SSlideWindowItemClickCallbackTab[] = {
+};
+
+
+typedef void (*EditTextInputCallback)(const std::string &text);
+typedef struct {
+    int id;
+    EditTextInputCallback onEditTextChangedCallback;
+}S_EditTextInputCallback;
+/*TAG:EditTextInputCallback*/
+static S_EditTextInputCallback SEditTextInputCallbackTab[] = {
+};
+
+typedef void (*VideoViewCallback)(ZKVideoView *pVideoView, int msg);
+typedef struct {
+    int id; //VideoView ID
+    bool loop; // 是否是轮播类型
+    int defaultvolume;//轮播类型时,默认视频音量
+    VideoViewCallback onVideoViewCallback;
+}S_VideoViewCallback;
+/*TAG:VideoViewCallback*/
+static S_VideoViewCallback SVideoViewCallbackTab[] = {
+};
+
+
+mainActivity::mainActivity() {
+	//todo add init code here
+	mVideoLoopIndex = -1;
+	mVideoLoopErrorCount = 0;
+}
+
+mainActivity::~mainActivity() {
+  //todo add init file here
+  // 退出应用时需要反注册
+    EASYUICONTEXT->unregisterGlobalTouchListener(this);
+    onUI_quit();
+    unregisterProtocolDataUpdateListener(onProtocolDataUpdate);
+    mMoreButtonPtr = NULL;
+    mNursingButtonPtr = NULL;
+    mCallCencelButtonPtr = NULL;
+    mHelpButtonPtr = NULL;
+    mCallNurseButtonPtr = NULL;
+    mCallBedButtonPtr = NULL;
+    mBedListViewPtr = NULL;
+    mRoomNamePtr = NULL;
+    mTextInfoPtr = NULL;
+    mNurseNamePtr = NULL;
+    mNurseTextPtr = NULL;
+    mDoctorTextPtr = NULL;
+    mPainterInfoPtr = NULL;
+    mActivityPtr = NULL;
+}
+
+const char* mainActivity::getAppName() const{
+	return "main.ftu";
+}
+
+//TAG:onCreate
+void mainActivity::onCreate() {
+	Activity::onCreate();
+    mMoreButtonPtr = (ZKButton*)findControlByID(ID_MAIN_MoreButton);
+    mNursingButtonPtr = (ZKButton*)findControlByID(ID_MAIN_NursingButton);
+    mCallCencelButtonPtr = (ZKButton*)findControlByID(ID_MAIN_CallCencelButton);
+    mHelpButtonPtr = (ZKButton*)findControlByID(ID_MAIN_HelpButton);
+    mCallNurseButtonPtr = (ZKButton*)findControlByID(ID_MAIN_CallNurseButton);
+    mCallBedButtonPtr = (ZKButton*)findControlByID(ID_MAIN_CallBedButton);
+    mBedListViewPtr = (ZKListView*)findControlByID(ID_MAIN_BedListView);if(mBedListViewPtr!= NULL){mBedListViewPtr->setListAdapter(this);mBedListViewPtr->setItemClickListener(this);}
+    mRoomNamePtr = (ZKTextView*)findControlByID(ID_MAIN_RoomName);
+    mTextInfoPtr = (ZKTextView*)findControlByID(ID_MAIN_TextInfo);
+    mNurseNamePtr = (ZKTextView*)findControlByID(ID_MAIN_NurseName);
+    mNurseTextPtr = (ZKTextView*)findControlByID(ID_MAIN_NurseText);
+    mDoctorTextPtr = (ZKTextView*)findControlByID(ID_MAIN_DoctorText);
+    mPainterInfoPtr = (ZKPainter*)findControlByID(ID_MAIN_PainterInfo);
+	mActivityPtr = this;
+	onUI_init();
+    registerProtocolDataUpdateListener(onProtocolDataUpdate); 
+    rigesterActivityTimer();
+}
+
+void mainActivity::onClick(ZKBase *pBase) {
+	//TODO: add widget onClik code 
+    int buttonTablen = sizeof(sButtonCallbackTab) / sizeof(S_ButtonCallback);
+    for (int i = 0; i < buttonTablen; ++i) {
+        if (sButtonCallbackTab[i].id == pBase->getID()) {
+            if (sButtonCallbackTab[i].callback((ZKButton*)pBase)) {
+            	return;
+            }
+            break;
+        }
+    }
+
+
+    int len = sizeof(sAppInfoTab) / sizeof(sAppInfoTab[0]);
+    for (int i = 0; i < len; ++i) {
+        if (sAppInfoTab[i].id == pBase->getID()) {
+            EASYUICONTEXT->openActivity(sAppInfoTab[i].pApp);
+            return;
+        }
+    }
+
+	Activity::onClick(pBase);
+}
+
+void mainActivity::onResume() {
+	Activity::onResume();
+	EASYUICONTEXT->registerGlobalTouchListener(this);
+	startVideoLoopPlayback();
+	onUI_show();
+}
+
+void mainActivity::onPause() {
+	Activity::onPause();
+	EASYUICONTEXT->unregisterGlobalTouchListener(this);
+	stopVideoLoopPlayback();
+	onUI_hide();
+}
+
+void mainActivity::onIntent(const Intent *intentPtr) {
+	Activity::onIntent(intentPtr);
+	onUI_intent(intentPtr);
+}
+
+bool mainActivity::onTimer(int id) {
+	return onUI_Timer(id);
+}
+
+void mainActivity::onProgressChanged(ZKSeekBar *pSeekBar, int progress){
+
+    int seekBarTablen = sizeof(SZKSeekBarCallbackTab) / sizeof(S_ZKSeekBarCallback);
+    for (int i = 0; i < seekBarTablen; ++i) {
+        if (SZKSeekBarCallbackTab[i].id == pSeekBar->getID()) {
+            SZKSeekBarCallbackTab[i].callback(pSeekBar, progress);
+            break;
+        }
+    }
+}
+
+int mainActivity::getListItemCount(const ZKListView *pListView) const{
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            return SListViewFunctionsCallbackTab[i].getListItemCountCallback(pListView);
+            break;
+        }
+    }
+    return 0;
+}
+
+void mainActivity::obtainListItemData(ZKListView *pListView,ZKListView::ZKListItem *pListItem, int index){
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            SListViewFunctionsCallbackTab[i].obtainListItemDataCallback(pListView, pListItem, index);
+            break;
+        }
+    }
+}
+
+void mainActivity::onItemClick(ZKListView *pListView, int index, int id){
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            SListViewFunctionsCallbackTab[i].onItemClickCallback(pListView, index, id);
+            break;
+        }
+    }
+}
+
+void mainActivity::onSlideItemClick(ZKSlideWindow *pSlideWindow, int index) {
+    int tablen = sizeof(SSlideWindowItemClickCallbackTab) / sizeof(S_SlideWindowItemClickCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SSlideWindowItemClickCallbackTab[i].id == pSlideWindow->getID()) {
+            SSlideWindowItemClickCallbackTab[i].onSlideItemClickCallback(pSlideWindow, index);
+            break;
+        }
+    }
+}
+
+bool mainActivity::onTouchEvent(const MotionEvent &ev) {
+    return onmainActivityTouchEvent(ev);
+}
+
+void mainActivity::onTextChanged(ZKTextView *pTextView, const std::string &text) {
+    int tablen = sizeof(SEditTextInputCallbackTab) / sizeof(S_EditTextInputCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SEditTextInputCallbackTab[i].id == pTextView->getID()) {
+            SEditTextInputCallbackTab[i].onEditTextChangedCallback(text);
+            break;
+        }
+    }
+}
+
+void mainActivity::rigesterActivityTimer() {
+    int tablen = sizeof(REGISTER_ACTIVITY_TIMER_TAB) / sizeof(S_ACTIVITY_TIMEER);
+    for (int i = 0; i < tablen; ++i) {
+        S_ACTIVITY_TIMEER temp = REGISTER_ACTIVITY_TIMER_TAB[i];
+        registerTimer(temp.id, temp.time);
+    }
+}
+
+
+void mainActivity::onVideoPlayerMessage(ZKVideoView *pVideoView, int msg) {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SVideoViewCallbackTab[i].id == pVideoView->getID()) {
+        	if (SVideoViewCallbackTab[i].loop) {
+                //循环播放
+        		videoLoopPlayback(pVideoView, msg, i);
+        	} else if (SVideoViewCallbackTab[i].onVideoViewCallback != NULL){
+        	    SVideoViewCallbackTab[i].onVideoViewCallback(pVideoView, msg);
+        	}
+            break;
+        }
+    }
+}
+
+void mainActivity::videoLoopPlayback(ZKVideoView *pVideoView, int msg, size_t callbackTabIndex) {
+
+	switch (msg) {
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_STARTED:
+		LOGD("ZKVideoView::E_MSGTYPE_VIDEO_PLAY_STARTED\n");
+    if (callbackTabIndex >= (sizeof(SVideoViewCallbackTab)/sizeof(S_VideoViewCallback))) {
+      break;
+    }
+		pVideoView->setVolume(SVideoViewCallbackTab[callbackTabIndex].defaultvolume / 10.0);
+		mVideoLoopErrorCount = 0;
+		break;
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_ERROR:
+		/**错误处理 */
+		++mVideoLoopErrorCount;
+		if (mVideoLoopErrorCount > 100) {
+			LOGD("video loop error counts > 100, quit loop playback !");
+            break;
+		} //不用break, 继续尝试播放下一个
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED:
+		LOGD("ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED\n");
+        std::vector<std::string> videolist;
+        std::string fileName(getAppName());
+        if (fileName.size() < 4) {
+             LOGD("getAppName size < 4, ignore!");
+             break;
+        }
+        fileName = fileName.substr(0, fileName.length() - 4) + "_video_list.txt";
+        fileName = "/mnt/extsd/" + fileName;
+        if (!parseVideoFileList(fileName.c_str(), videolist)) {
+            LOGD("parseVideoFileList failed !");
+		    break;
+        }
+		if (pVideoView && !videolist.empty()) {
+			mVideoLoopIndex = (mVideoLoopIndex + 1) % videolist.size();
+			pVideoView->play(videolist[mVideoLoopIndex].c_str());
+		}
+		break;
+	}
+}
+
+void mainActivity::startVideoLoopPlayback() {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+    	if (SVideoViewCallbackTab[i].loop) {
+    		ZKVideoView* videoView = (ZKVideoView*)findControlByID(SVideoViewCallbackTab[i].id);
+    		if (!videoView) {
+    			return;
+    		}
+    		//循环播放
+    		videoLoopPlayback(videoView, ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED, i);
+    		return;
+    	}
+    }
+}
+
+void mainActivity::stopVideoLoopPlayback() {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+    	if (SVideoViewCallbackTab[i].loop) {
+    		ZKVideoView* videoView = (ZKVideoView*)findControlByID(SVideoViewCallbackTab[i].id);
+    		if (!videoView) {
+    			return;
+    		}
+    		if (videoView->isPlaying()) {
+    		    videoView->stop();
+    		}
+    		return;
+    	}
+    }
+}
+
+bool mainActivity::parseVideoFileList(const char *pFileListPath, std::vector<string>& mediaFileList) {
+	mediaFileList.clear();
+	if (NULL == pFileListPath || 0 == strlen(pFileListPath)) {
+        LOGD("video file list is null!");
+		return false;
+	}
+
+	ifstream is(pFileListPath, ios_base::in);
+	if (!is.is_open()) {
+		LOGD("cann't open file %s \n", pFileListPath);
+		return false;
+	}
+	char tmp[1024] = {0};
+	while (is.getline(tmp, sizeof(tmp))) {
+		string str = tmp;
+		removeCharFromString(str, '\"');
+		removeCharFromString(str, '\r');
+		removeCharFromString(str, '\n');
+		if (str.size() > 1) {
+     		mediaFileList.push_back(str.c_str());
+		}
+	}
+  LOGD("(f:%s, l:%d) parse fileList[%s], get [%d]files", __FUNCTION__,
+      __LINE__, pFileListPath, int(mediaFileList.size()));
+  for (std::vector<string>::size_type i = 0; i < mediaFileList.size(); i++) {
+    LOGD("file[%u]:[%s]", ::size_t(i), mediaFileList[i].c_str());
+  }
+	is.close();
+
+	return true;
+}
+
+int mainActivity::removeCharFromString(string& nString, char c) {
+    string::size_type   pos;
+    while(1) {
+        pos = nString.find(c);
+        if(pos != string::npos) {
+            nString.erase(pos, 1);
+        } else {
+            break;
+        }
+    }
+    return (int)nString.size();
+}
+
+void mainActivity::registerUserTimer(int id, int time) {
+	registerTimer(id, time);
+}
+
+void mainActivity::unregisterUserTimer(int id) {
+	unregisterTimer(id);
+}
+
+void mainActivity::resetUserTimer(int id, int time) {
+	resetTimer(id, time);
+}

+ 132 - 0
jni/activity/mainActivity.h

@@ -0,0 +1,132 @@
+/***********************************************
+/gen auto by zuitools
+***********************************************/
+#ifndef __MAINACTIVITY_H__
+#define __MAINACTIVITY_H__
+
+
+#include "app/Activity.h"
+#include "entry/EasyUIContext.h"
+
+#include "uart/ProtocolData.h"
+#include "uart/ProtocolParser.h"
+
+#include "utils/Log.h"
+#include "control/ZKDigitalClock.h"
+#include "control/ZKPainter.h"
+#include "control/ZKButton.h"
+#include "control/ZKCircleBar.h"
+#include "control/ZKDiagram.h"
+#include "control/ZKListView.h"
+#include "control/ZKPointer.h"
+#include "control/ZKQRCode.h"
+#include "control/ZKTextView.h"
+#include "control/ZKSeekBar.h"
+#include "control/ZKEditText.h"
+#include "control/ZKVideoView.h"
+#include "window/ZKSlideWindow.h"
+
+/*TAG:Macro宏ID*/
+#define ID_MAIN_MoreButton    20006
+#define ID_MAIN_NursingButton    20005
+#define ID_MAIN_CallCencelButton    20003
+#define ID_MAIN_HelpButton    20004
+#define ID_MAIN_CallNurseButton    20002
+#define ID_MAIN_CallBedButton    20001
+#define ID_MAIN_DoctorName    24023
+#define ID_MAIN_NurseName    24025
+#define ID_MAIN_NurseText    24024
+#define ID_MAIN_DoctorText    24022
+#define ID_MAIN_CustomerAge    24021
+#define ID_MAIN_CustomerSex    24020
+#define ID_MAIN_CustomerName    24019
+#define ID_MAIN_CustomerPortrait    24018
+#define ID_MAIN_NursePortrait    24017
+#define ID_MAIN_DoctorPortrait    24016
+#define ID_MAIN_NurseOption5    24015
+#define ID_MAIN_NurseConfig5    24014
+#define ID_MAIN_NurseOption4    24013
+#define ID_MAIN_NurseConfig4    24012
+#define ID_MAIN_NurseOption3    24011
+#define ID_MAIN_NurseConfig3    24010
+#define ID_MAIN_NurseOption2    24009
+#define ID_MAIN_NurseConfig2    24008
+#define ID_MAIN_NurseOption1    24007
+#define ID_MAIN_NurseConfin1    24006
+#define ID_MAIN_NurseConfigColor5    24005
+#define ID_MAIN_NurseConfigColor4    24004
+#define ID_MAIN_NurseConfigColor3    24003
+#define ID_MAIN_NurseConfigColor2    24002
+#define ID_MAIN_NurseConfigColor1    24001
+#define ID_MAIN_BedListView    80001
+#define ID_MAIN_RoomName    50001
+#define ID_MAIN_TextInfo    50012
+#define ID_MAIN_PainterInfo    52001
+/*TAG:Macro宏ID END*/
+
+class mainActivity : public Activity, 
+                     public ZKSeekBar::ISeekBarChangeListener, 
+                     public ZKListView::IItemClickListener,
+                     public ZKListView::AbsListAdapter,
+                     public ZKSlideWindow::ISlideItemClickListener,
+                     public EasyUIContext::ITouchListener,
+                     public ZKEditText::ITextChangeListener,
+                     public ZKVideoView::IVideoPlayerMessageListener
+{
+public:
+    mainActivity();
+    virtual ~mainActivity();
+
+    /**
+     * 注册定时器
+     */
+	void registerUserTimer(int id, int time);
+	/**
+	 * 取消定时器
+	 */
+	void unregisterUserTimer(int id);
+	/**
+	 * 重置定时器
+	 */
+	void resetUserTimer(int id, int time);
+
+protected:
+    /*TAG:PROTECTED_FUNCTION*/
+    virtual const char* getAppName() const;
+    virtual void onCreate();
+    virtual void onClick(ZKBase *pBase);
+    virtual void onResume();
+    virtual void onPause();
+    virtual void onIntent(const Intent *intentPtr);
+    virtual bool onTimer(int id);
+
+    virtual void onProgressChanged(ZKSeekBar *pSeekBar, int progress);
+
+    virtual int getListItemCount(const ZKListView *pListView) const;
+    virtual void obtainListItemData(ZKListView *pListView, ZKListView::ZKListItem *pListItem, int index);
+    virtual void onItemClick(ZKListView *pListView, int index, int subItemIndex);
+
+    virtual void onSlideItemClick(ZKSlideWindow *pSlideWindow, int index);
+
+    virtual bool onTouchEvent(const MotionEvent &ev);
+
+    virtual void onTextChanged(ZKTextView *pTextView, const string &text);
+
+    void rigesterActivityTimer();
+
+    virtual void onVideoPlayerMessage(ZKVideoView *pVideoView, int msg);
+    void videoLoopPlayback(ZKVideoView *pVideoView, int msg, size_t callbackTabIndex);
+    void startVideoLoopPlayback();
+    void stopVideoLoopPlayback();
+    bool parseVideoFileList(const char *pFileListPath, std::vector<string>& mediaFileList);
+    int removeCharFromString(string& nString, char c);
+
+
+private:
+    /*TAG:PRIVATE_VARIABLE*/
+    int mVideoLoopIndex;
+    int mVideoLoopErrorCount;
+
+};
+
+#endif

+ 394 - 0
jni/activity/navibar.cpp

@@ -0,0 +1,394 @@
+#include "navibar.h"
+#include "entry/EasyUIContext.h"
+
+/*TAG:GlobalVariable全局变量*/
+static ZKWindow* mWindow1Ptr;
+static ZKButton* mBtnAboutPtr;
+static ZKButton* msys_homePtr;
+static ZKButton* msys_backPtr;
+static ZKButton* mBtnHelpPtr;
+static ZKButton* mBtnCallPtr;
+static navibar* mnavibarPtr;
+/* register sysapp */
+REGISTER_SYSAPP(APP_TYPE_SYS_NAVIBAR, navibar);
+
+typedef struct {
+	int id; // 定时器ID , 不能重复
+	int time; // 定时器  时间间隔  单位 毫秒
+}S_ACTIVITY_TIMEER;
+
+#include "logic/navibar.cc"
+
+
+/***********/
+typedef struct {
+    int id;
+    const char *pApp;
+} SAppInfo;
+
+/**
+ *点击跳转window
+ */
+static SAppInfo sAppInfoTab[] = {
+//  { ID_MAIN_TEXT, "TextViewActivity" },
+};
+
+/***************/
+typedef bool (*ButtonCallback)(ZKButton *pButton);
+/**
+ * button onclick表
+ */
+typedef struct {
+    int id;
+    ButtonCallback callback;
+}S_ButtonCallback;
+
+/*TAG:ButtonCallbackTab按键映射表*/
+static S_ButtonCallback sButtonCallbackTab[] = {
+    ID_NAVIBAR_BtnAbout, onButtonClick_BtnAbout,
+    ID_NAVIBAR_sys_home, onButtonClick_sys_home,
+    ID_NAVIBAR_sys_back, onButtonClick_sys_back,
+    ID_NAVIBAR_BtnHelp, onButtonClick_BtnHelp,
+    ID_NAVIBAR_BtnCall, onButtonClick_BtnCall,
+};
+/***************/
+
+
+typedef void (*SeekBarCallback)(ZKSeekBar *pSeekBar, int progress);
+typedef struct {
+    int id;
+    SeekBarCallback callback;
+}S_ZKSeekBarCallback;
+/*TAG:SeekBarCallbackTab*/
+static S_ZKSeekBarCallback SZKSeekBarCallbackTab[] = {
+};
+
+
+typedef int (*ListViewGetItemCountCallback)(const ZKListView *pListView);
+typedef void (*ListViewobtainListItemDataCallback)(ZKListView *pListView,ZKListView::ZKListItem *pListItem, int index);
+typedef void (*ListViewonItemClickCallback)(ZKListView *pListView, int index, int id);
+typedef struct {
+    int id;
+    ListViewGetItemCountCallback getListItemCountCallback;
+    ListViewobtainListItemDataCallback obtainListItemDataCallback;
+    ListViewonItemClickCallback onItemClickCallback;
+}S_ListViewFunctionsCallback;
+/*TAG:ListViewFunctionsCallback*/
+static S_ListViewFunctionsCallback SListViewFunctionsCallbackTab[] = {
+};
+
+
+typedef void (*SlideWindowItemClickCallback)(ZKSlideWindow *pSlideWindow, int index);
+typedef struct {
+    int id;
+    SlideWindowItemClickCallback onSlideItemClickCallback;
+}S_SlideWindowItemClickCallback;
+/*TAG:SlideWindowFunctionsCallbackTab*/
+static S_SlideWindowItemClickCallback SSlideWindowItemClickCallbackTab[] = {
+};
+
+typedef void (*EditTextInputCallback)(const std::string &text);
+typedef struct {
+    int id;
+    EditTextInputCallback onEditTextChangedCallback;
+}S_EditTextInputCallback;
+/*TAG:EditTextInputCallback*/
+static S_EditTextInputCallback SEditTextInputCallbackTab[] = {
+};
+
+typedef void (*VideoViewCallback)(ZKVideoView *pVideoView, int msg);
+typedef struct {
+    int id; //VideoView ID
+    bool loop; // 是否是轮播类型
+    int defaultvolume;//轮播类型时,默认视频音量
+    VideoViewCallback onVideoViewCallback;
+}S_VideoViewCallback;
+/*TAG:VideoViewCallback*/
+static S_VideoViewCallback SVideoViewCallbackTab[] = {
+};
+
+navibar::navibar() {
+	mVideoLoopIndex = -1;
+	mVideoLoopErrorCount = 0;
+}
+
+navibar::~navibar() {
+    // 退出应用时需要反注册
+    EASYUICONTEXT->unregisterGlobalTouchListener(this);
+    onUI_quit();
+    unregisterProtocolDataUpdateListener(onProtocolDataUpdate);
+    mWindow1Ptr = NULL;
+    mBtnAboutPtr = NULL;
+    msys_homePtr = NULL;
+    msys_backPtr = NULL;
+    mBtnHelpPtr = NULL;
+    mBtnCallPtr = NULL;
+    mnavibarPtr = NULL;
+}
+
+const char* navibar::getAppName() const{
+    return "navibar.ftu";
+}
+
+//TAG:onCreate
+void navibar::onCreate() {
+	BaseApp::onCreate();
+    mWindow1Ptr = (ZKWindow*)findControlByID(ID_NAVIBAR_Window1);
+    mBtnAboutPtr = (ZKButton*)findControlByID(ID_NAVIBAR_BtnAbout);
+    msys_homePtr = (ZKButton*)findControlByID(ID_NAVIBAR_sys_home);
+    msys_backPtr = (ZKButton*)findControlByID(ID_NAVIBAR_sys_back);
+    mBtnHelpPtr = (ZKButton*)findControlByID(ID_NAVIBAR_BtnHelp);
+    mBtnCallPtr = (ZKButton*)findControlByID(ID_NAVIBAR_BtnCall);
+	mnavibarPtr = this;
+	onUI_init();
+    // 注册监听全局触摸
+    EASYUICONTEXT->registerGlobalTouchListener(this);
+    registerProtocolDataUpdateListener(onProtocolDataUpdate); 
+    rigesterActivityTimer();
+    startVideoLoopPlayback();
+}
+
+void navibar::onClick(ZKBase *pBase) {
+    int buttonTablen = sizeof(sButtonCallbackTab) / sizeof(S_ButtonCallback);
+    for (int i = 0; i < buttonTablen; ++i) {
+        if (sButtonCallbackTab[i].id == pBase->getID()) {
+            if (sButtonCallbackTab[i].callback((ZKButton*)pBase)) {
+            	return;
+            }
+            break;
+        }
+    }
+
+
+    int len = sizeof(sAppInfoTab) / sizeof(sAppInfoTab[0]);
+    for (int i = 0; i < len; ++i) {
+        if (sAppInfoTab[i].id == pBase->getID()) {
+            EASYUICONTEXT->openActivity(sAppInfoTab[i].pApp);
+            return;
+        }
+    }
+
+	BaseApp::onClick(pBase);
+}
+
+bool navibar::onTimer(int id) {
+    return onUI_Timer(id);
+}
+
+
+void navibar::onProgressChanged(ZKSeekBar *pSeekBar, int progress){
+
+    int seekBarTablen = sizeof(SZKSeekBarCallbackTab) / sizeof(S_ZKSeekBarCallback);
+    for (int i = 0; i < seekBarTablen; ++i) {
+        if (SZKSeekBarCallbackTab[i].id == pSeekBar->getID()) {
+            SZKSeekBarCallbackTab[i].callback(pSeekBar, progress);
+            break;
+        }
+    }
+}
+
+int navibar::getListItemCount(const ZKListView *pListView) const{
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            return SListViewFunctionsCallbackTab[i].getListItemCountCallback(pListView);
+            break;
+        }
+    }
+    return 0;
+}
+void navibar::obtainListItemData(ZKListView *pListView,ZKListView::ZKListItem *pListItem, int index){
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            SListViewFunctionsCallbackTab[i].obtainListItemDataCallback(pListView, pListItem, index);
+            break;
+        }
+    }
+}
+void navibar::onItemClick(ZKListView *pListView, int index, int id){
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            SListViewFunctionsCallbackTab[i].onItemClickCallback(pListView, index, id);
+            break;
+        }
+    }
+}
+
+void navibar::onSlideItemClick(ZKSlideWindow *pSlideWindow, int index) {
+    int tablen = sizeof(SSlideWindowItemClickCallbackTab) / sizeof(S_SlideWindowItemClickCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SSlideWindowItemClickCallbackTab[i].id == pSlideWindow->getID()) {
+            SSlideWindowItemClickCallbackTab[i].onSlideItemClickCallback(pSlideWindow, index);
+            break;
+        }
+    }
+}
+
+bool navibar::onTouchEvent(const MotionEvent &ev) {
+    return onnavibarActivityTouchEvent(ev);
+}
+
+void navibar::onTextChanged(ZKTextView *pTextView, const std::string &text) {
+    int tablen = sizeof(SEditTextInputCallbackTab) / sizeof(S_EditTextInputCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SEditTextInputCallbackTab[i].id == pTextView->getID()) {
+            SEditTextInputCallbackTab[i].onEditTextChangedCallback(text);
+            break;
+        }
+    }
+}
+
+void navibar::rigesterActivityTimer() {
+    int tablen = sizeof(REGISTER_ACTIVITY_TIMER_TAB) / sizeof(S_ACTIVITY_TIMEER);
+    for (int i = 0; i < tablen; ++i) {
+        S_ACTIVITY_TIMEER temp = REGISTER_ACTIVITY_TIMER_TAB[i];
+        registerTimer(temp.id, temp.time);
+    }
+}
+
+
+void navibar::onVideoPlayerMessage(ZKVideoView *pVideoView, int msg) {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SVideoViewCallbackTab[i].id == pVideoView->getID()) {
+        	if (SVideoViewCallbackTab[i].loop) {
+                //循环播放
+        		videoLoopPlayback(pVideoView, msg, i);
+        	} else if (SVideoViewCallbackTab[i].onVideoViewCallback != NULL){
+        	    SVideoViewCallbackTab[i].onVideoViewCallback(pVideoView, msg);
+        	}
+            break;
+        }
+    }
+}
+
+void navibar::videoLoopPlayback(ZKVideoView *pVideoView, int msg, size_t callbackTabIndex) {
+
+	switch (msg) {
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_STARTED:
+		LOGD("ZKVideoView::E_MSGTYPE_VIDEO_PLAY_STARTED\n");
+    if (callbackTabIndex >= (sizeof(SVideoViewCallbackTab)/sizeof(S_VideoViewCallback))) {
+      break;
+    }
+		pVideoView->setVolume(SVideoViewCallbackTab[callbackTabIndex].defaultvolume / 10.0);
+		mVideoLoopErrorCount = 0;
+		break;
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_ERROR:
+		/**错误处理 */
+		++mVideoLoopErrorCount;
+		if (mVideoLoopErrorCount > 100) {
+			LOGD("video loop error counts > 100, quit loop playback !");
+            break;
+		} //不用break, 继续尝试播放下一个
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED:
+		LOGD("ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED\n");
+        std::vector<std::string> videolist;
+        std::string fileName(getAppName());
+        if (fileName.size() < 4) {
+             LOGD("getAppName size < 4, ignore!");
+             break;
+        }
+        fileName = fileName.substr(0, fileName.length() - 4) + "_video_list.txt";
+        fileName = "/mnt/extsd/" + fileName;
+        if (!parseVideoFileList(fileName.c_str(), videolist)) {
+            LOGD("parseVideoFileList failed !");
+		    break;
+        }
+		if (pVideoView && !videolist.empty()) {
+			mVideoLoopIndex = (mVideoLoopIndex + 1) % videolist.size();
+			pVideoView->play(videolist[mVideoLoopIndex].c_str());
+		}
+		break;
+	}
+}
+
+void navibar::startVideoLoopPlayback() {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+    	if (SVideoViewCallbackTab[i].loop) {
+    		ZKVideoView* videoView = (ZKVideoView*)findControlByID(SVideoViewCallbackTab[i].id);
+    		if (!videoView) {
+    			return;
+    		}
+    		//循环播放
+    		videoLoopPlayback(videoView, ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED, i);
+    		return;
+    	}
+    }
+}
+
+void navibar::stopVideoLoopPlayback() {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+    	if (SVideoViewCallbackTab[i].loop) {
+    		ZKVideoView* videoView = (ZKVideoView*)findControlByID(SVideoViewCallbackTab[i].id);
+    		if (!videoView) {
+    			return;
+    		}
+    		if (videoView->isPlaying()) {
+    		    videoView->stop();
+    		}
+    		return;
+    	}
+    }
+}
+
+bool navibar::parseVideoFileList(const char *pFileListPath, std::vector<string>& mediaFileList) {
+	mediaFileList.clear();
+	if (NULL == pFileListPath || 0 == strlen(pFileListPath)) {
+        LOGD("video file list is null!");
+		return false;
+	}
+
+	ifstream is(pFileListPath, ios_base::in);
+	if (!is.is_open()) {
+		LOGD("cann't open file %s \n", pFileListPath);
+		return false;
+	}
+	char tmp[1024] = {0};
+	while (is.getline(tmp, sizeof(tmp))) {
+		string str = tmp;
+		removeCharFromString(str, '\"');
+		removeCharFromString(str, '\r');
+		removeCharFromString(str, '\n');
+		if (str.size() > 1) {
+     		mediaFileList.push_back(str.c_str());
+		}
+	}
+	LOGD("(f:%s, l:%d) parse fileList[%s], get [%d]files\n", __FUNCTION__,
+			__LINE__, pFileListPath, mediaFileList.size());
+	for (size_t i = 0; i < mediaFileList.size(); i++) {
+		LOGD("file[%d]:[%s]\n", i, mediaFileList[i].c_str());
+	}
+	is.close();
+
+	return true;
+}
+
+int navibar::removeCharFromString(string& nString, char c)
+{
+    string::size_type   pos;
+    while(1) {
+        pos = nString.find(c);
+        if(pos != string::npos) {
+            nString.erase(pos, 1);
+        } else {
+            break;
+        }
+    }
+    return (int)nString.size();
+}
+
+void navibar::registerUserTimer(int id, int time) {
+	registerTimer(id, time);
+}
+
+void navibar::unregisterUserTimer(int id) {
+	unregisterTimer(id);
+}
+
+void navibar::resetUserTimer(int id, int time) {
+	resetTimer(id, time);
+}

+ 92 - 0
jni/activity/navibar.h

@@ -0,0 +1,92 @@
+#ifndef _SYSAPP_NAVIBAR_H_
+#define _SYSAPP_NAVIBAR_H_
+
+#include "entry/EasyUIContext.h"
+#include "app/SysAppFactory.h"
+
+#include "uart/ProtocolData.h"
+#include "uart/ProtocolParser.h"
+
+#include "utils/Log.h"
+#include "control/ZKDigitalClock.h"
+#include "control/ZKButton.h"
+#include "control/ZKCircleBar.h"
+#include "control/ZKDiagram.h"
+#include "control/ZKListView.h"
+#include "control/ZKPointer.h"
+#include "control/ZKQRCode.h"
+#include "control/ZKTextView.h"
+#include "control/ZKSeekBar.h"
+#include "control/ZKEditText.h"
+#include "control/ZKVideoView.h"
+#include "window/ZKSlideWindow.h"
+/*TAG:Macro宏ID*/
+#define ID_NAVIBAR_Window1    110001
+#define ID_NAVIBAR_BtnAbout    20004
+#define ID_NAVIBAR_sys_home   101
+#define ID_NAVIBAR_sys_back   100
+#define ID_NAVIBAR_BtnHelp    20002
+#define ID_NAVIBAR_BtnCall    20001
+/*TAG:Macro宏ID END*/
+class navibar : public BaseApp,
+                  public ZKSeekBar::ISeekBarChangeListener, 
+                  public ZKListView::IItemClickListener,
+                  public ZKListView::AbsListAdapter,
+                  public ZKSlideWindow::ISlideItemClickListener,
+                  public EasyUIContext::ITouchListener,
+                  public ZKEditText::ITextChangeListener,
+                  public ZKVideoView::IVideoPlayerMessageListener
+{
+public:
+	navibar();
+	virtual ~navibar();
+	virtual void onCreate();
+	virtual void onClick(ZKBase *pBase);
+	virtual bool onTimer(int id);
+
+    virtual void onProgressChanged(ZKSeekBar *pSeekBar, int progress);
+
+    virtual int getListItemCount(const ZKListView *pListView) const;
+    virtual void obtainListItemData(ZKListView *pListView, ZKListView::ZKListItem *pListItem, int index);
+    virtual void onItemClick(ZKListView *pListView, int index, int subItemIndex);
+
+    virtual void onSlideItemClick(ZKSlideWindow *pSlideWindow, int index);
+
+    virtual bool onTouchEvent(const MotionEvent &ev);
+
+    virtual void onTextChanged(ZKTextView *pTextView, const string &text);
+
+    void rigesterActivityTimer();
+
+    virtual void onVideoPlayerMessage(ZKVideoView *pVideoView, int msg);
+    void videoLoopPlayback(ZKVideoView *pVideoView, int msg, size_t callbackTabIndex);
+    void startVideoLoopPlayback();
+    void stopVideoLoopPlayback();
+    bool parseVideoFileList(const char *pFileListPath, std::vector<string>& mediaFileList);
+    int removeCharFromString(string& nString, char c);
+
+    /**
+     * 注册定时器
+     */
+	void registerUserTimer(int id, int time);
+	/**
+	 * 取消定时器
+	 */
+	void unregisterUserTimer(int id);
+	/**
+	 * 重置定时器
+	 */
+	void resetUserTimer(int id, int time);
+
+protected:
+    /*TAG:PROTECTED_FUNCTION*/
+	virtual const char* getAppName() const;
+
+
+private:
+    /*TAG:PRIVATE_VARIABLE*/
+    int mVideoLoopIndex;
+    int mVideoLoopErrorCount;
+};
+
+#endif

+ 397 - 0
jni/activity/startActivity.cpp

@@ -0,0 +1,397 @@
+/***********************************************
+/gen auto by zuitools
+***********************************************/
+#include "startActivity.h"
+
+/*TAG:GlobalVariable全局变量*/
+static ZKTextView* mTextView1Ptr;
+static startActivity* mActivityPtr;
+
+/*register activity*/
+REGISTER_ACTIVITY(startActivity);
+
+typedef struct {
+	int id; // 定时器ID , 不能重复
+	int time; // 定时器  时间间隔  单位 毫秒
+}S_ACTIVITY_TIMEER;
+
+#include "logic/startLogic.cc"
+
+/***********/
+typedef struct {
+    int id;
+    const char *pApp;
+} SAppInfo;
+
+/**
+ *点击跳转window
+ */
+static SAppInfo sAppInfoTab[] = {
+//  { ID_MAIN_TEXT, "TextViewActivity" },
+};
+
+/***************/
+typedef bool (*ButtonCallback)(ZKButton *pButton);
+/**
+ * button onclick表
+ */
+typedef struct {
+    int id;
+    ButtonCallback callback;
+}S_ButtonCallback;
+
+/*TAG:ButtonCallbackTab按键映射表*/
+static S_ButtonCallback sButtonCallbackTab[] = {
+};
+/***************/
+
+
+typedef void (*SeekBarCallback)(ZKSeekBar *pSeekBar, int progress);
+typedef struct {
+    int id;
+    SeekBarCallback callback;
+}S_ZKSeekBarCallback;
+/*TAG:SeekBarCallbackTab*/
+static S_ZKSeekBarCallback SZKSeekBarCallbackTab[] = {
+};
+
+
+typedef int (*ListViewGetItemCountCallback)(const ZKListView *pListView);
+typedef void (*ListViewobtainListItemDataCallback)(ZKListView *pListView,ZKListView::ZKListItem *pListItem, int index);
+typedef void (*ListViewonItemClickCallback)(ZKListView *pListView, int index, int id);
+typedef struct {
+    int id;
+    ListViewGetItemCountCallback getListItemCountCallback;
+    ListViewobtainListItemDataCallback obtainListItemDataCallback;
+    ListViewonItemClickCallback onItemClickCallback;
+}S_ListViewFunctionsCallback;
+/*TAG:ListViewFunctionsCallback*/
+static S_ListViewFunctionsCallback SListViewFunctionsCallbackTab[] = {
+};
+
+
+typedef void (*SlideWindowItemClickCallback)(ZKSlideWindow *pSlideWindow, int index);
+typedef struct {
+    int id;
+    SlideWindowItemClickCallback onSlideItemClickCallback;
+}S_SlideWindowItemClickCallback;
+/*TAG:SlideWindowFunctionsCallbackTab*/
+static S_SlideWindowItemClickCallback SSlideWindowItemClickCallbackTab[] = {
+};
+
+
+typedef void (*EditTextInputCallback)(const std::string &text);
+typedef struct {
+    int id;
+    EditTextInputCallback onEditTextChangedCallback;
+}S_EditTextInputCallback;
+/*TAG:EditTextInputCallback*/
+static S_EditTextInputCallback SEditTextInputCallbackTab[] = {
+};
+
+typedef void (*VideoViewCallback)(ZKVideoView *pVideoView, int msg);
+typedef struct {
+    int id; //VideoView ID
+    bool loop; // 是否是轮播类型
+    int defaultvolume;//轮播类型时,默认视频音量
+    VideoViewCallback onVideoViewCallback;
+}S_VideoViewCallback;
+/*TAG:VideoViewCallback*/
+static S_VideoViewCallback SVideoViewCallbackTab[] = {
+};
+
+
+startActivity::startActivity() {
+	//todo add init code here
+	mVideoLoopIndex = -1;
+	mVideoLoopErrorCount = 0;
+}
+
+startActivity::~startActivity() {
+  //todo add init file here
+  // 退出应用时需要反注册
+    EASYUICONTEXT->unregisterGlobalTouchListener(this);
+    onUI_quit();
+    unregisterProtocolDataUpdateListener(onProtocolDataUpdate);
+    mTextView1Ptr = NULL;
+    mActivityPtr = NULL;
+}
+
+const char* startActivity::getAppName() const{
+	return "start.ftu";
+}
+
+//TAG:onCreate
+void startActivity::onCreate() {
+	Activity::onCreate();
+    mTextView1Ptr = (ZKTextView*)findControlByID(ID_START_TextView1);
+	mActivityPtr = this;
+	onUI_init();
+    registerProtocolDataUpdateListener(onProtocolDataUpdate); 
+    rigesterActivityTimer();
+}
+
+void startActivity::onClick(ZKBase *pBase) {
+	//TODO: add widget onClik code 
+    int buttonTablen = sizeof(sButtonCallbackTab) / sizeof(S_ButtonCallback);
+    for (int i = 0; i < buttonTablen; ++i) {
+        if (sButtonCallbackTab[i].id == pBase->getID()) {
+            if (sButtonCallbackTab[i].callback((ZKButton*)pBase)) {
+            	return;
+            }
+            break;
+        }
+    }
+
+
+    int len = sizeof(sAppInfoTab) / sizeof(sAppInfoTab[0]);
+    for (int i = 0; i < len; ++i) {
+        if (sAppInfoTab[i].id == pBase->getID()) {
+            EASYUICONTEXT->openActivity(sAppInfoTab[i].pApp);
+            return;
+        }
+    }
+
+	Activity::onClick(pBase);
+}
+
+void startActivity::onResume() {
+	Activity::onResume();
+	EASYUICONTEXT->registerGlobalTouchListener(this);
+	startVideoLoopPlayback();
+	onUI_show();
+}
+
+void startActivity::onPause() {
+	Activity::onPause();
+	EASYUICONTEXT->unregisterGlobalTouchListener(this);
+	stopVideoLoopPlayback();
+	onUI_hide();
+}
+
+void startActivity::onIntent(const Intent *intentPtr) {
+	Activity::onIntent(intentPtr);
+	onUI_intent(intentPtr);
+}
+
+bool startActivity::onTimer(int id) {
+	return onUI_Timer(id);
+}
+
+void startActivity::onProgressChanged(ZKSeekBar *pSeekBar, int progress){
+
+    int seekBarTablen = sizeof(SZKSeekBarCallbackTab) / sizeof(S_ZKSeekBarCallback);
+    for (int i = 0; i < seekBarTablen; ++i) {
+        if (SZKSeekBarCallbackTab[i].id == pSeekBar->getID()) {
+            SZKSeekBarCallbackTab[i].callback(pSeekBar, progress);
+            break;
+        }
+    }
+}
+
+int startActivity::getListItemCount(const ZKListView *pListView) const{
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            return SListViewFunctionsCallbackTab[i].getListItemCountCallback(pListView);
+            break;
+        }
+    }
+    return 0;
+}
+
+void startActivity::obtainListItemData(ZKListView *pListView,ZKListView::ZKListItem *pListItem, int index){
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            SListViewFunctionsCallbackTab[i].obtainListItemDataCallback(pListView, pListItem, index);
+            break;
+        }
+    }
+}
+
+void startActivity::onItemClick(ZKListView *pListView, int index, int id){
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            SListViewFunctionsCallbackTab[i].onItemClickCallback(pListView, index, id);
+            break;
+        }
+    }
+}
+
+void startActivity::onSlideItemClick(ZKSlideWindow *pSlideWindow, int index) {
+    int tablen = sizeof(SSlideWindowItemClickCallbackTab) / sizeof(S_SlideWindowItemClickCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SSlideWindowItemClickCallbackTab[i].id == pSlideWindow->getID()) {
+            SSlideWindowItemClickCallbackTab[i].onSlideItemClickCallback(pSlideWindow, index);
+            break;
+        }
+    }
+}
+
+bool startActivity::onTouchEvent(const MotionEvent &ev) {
+    return onstartActivityTouchEvent(ev);
+}
+
+void startActivity::onTextChanged(ZKTextView *pTextView, const std::string &text) {
+    int tablen = sizeof(SEditTextInputCallbackTab) / sizeof(S_EditTextInputCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SEditTextInputCallbackTab[i].id == pTextView->getID()) {
+            SEditTextInputCallbackTab[i].onEditTextChangedCallback(text);
+            break;
+        }
+    }
+}
+
+void startActivity::rigesterActivityTimer() {
+    int tablen = sizeof(REGISTER_ACTIVITY_TIMER_TAB) / sizeof(S_ACTIVITY_TIMEER);
+    for (int i = 0; i < tablen; ++i) {
+        S_ACTIVITY_TIMEER temp = REGISTER_ACTIVITY_TIMER_TAB[i];
+        registerTimer(temp.id, temp.time);
+    }
+}
+
+
+void startActivity::onVideoPlayerMessage(ZKVideoView *pVideoView, int msg) {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SVideoViewCallbackTab[i].id == pVideoView->getID()) {
+        	if (SVideoViewCallbackTab[i].loop) {
+                //循环播放
+        		videoLoopPlayback(pVideoView, msg, i);
+        	} else if (SVideoViewCallbackTab[i].onVideoViewCallback != NULL){
+        	    SVideoViewCallbackTab[i].onVideoViewCallback(pVideoView, msg);
+        	}
+            break;
+        }
+    }
+}
+
+void startActivity::videoLoopPlayback(ZKVideoView *pVideoView, int msg, size_t callbackTabIndex) {
+
+	switch (msg) {
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_STARTED:
+		LOGD("ZKVideoView::E_MSGTYPE_VIDEO_PLAY_STARTED\n");
+    if (callbackTabIndex >= (sizeof(SVideoViewCallbackTab)/sizeof(S_VideoViewCallback))) {
+      break;
+    }
+		pVideoView->setVolume(SVideoViewCallbackTab[callbackTabIndex].defaultvolume / 10.0);
+		mVideoLoopErrorCount = 0;
+		break;
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_ERROR:
+		/**错误处理 */
+		++mVideoLoopErrorCount;
+		if (mVideoLoopErrorCount > 100) {
+			LOGD("video loop error counts > 100, quit loop playback !");
+            break;
+		} //不用break, 继续尝试播放下一个
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED:
+		LOGD("ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED\n");
+        std::vector<std::string> videolist;
+        std::string fileName(getAppName());
+        if (fileName.size() < 4) {
+             LOGD("getAppName size < 4, ignore!");
+             break;
+        }
+        fileName = fileName.substr(0, fileName.length() - 4) + "_video_list.txt";
+        fileName = "/mnt/extsd/" + fileName;
+        if (!parseVideoFileList(fileName.c_str(), videolist)) {
+            LOGD("parseVideoFileList failed !");
+		    break;
+        }
+		if (pVideoView && !videolist.empty()) {
+			mVideoLoopIndex = (mVideoLoopIndex + 1) % videolist.size();
+			pVideoView->play(videolist[mVideoLoopIndex].c_str());
+		}
+		break;
+	}
+}
+
+void startActivity::startVideoLoopPlayback() {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+    	if (SVideoViewCallbackTab[i].loop) {
+    		ZKVideoView* videoView = (ZKVideoView*)findControlByID(SVideoViewCallbackTab[i].id);
+    		if (!videoView) {
+    			return;
+    		}
+    		//循环播放
+    		videoLoopPlayback(videoView, ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED, i);
+    		return;
+    	}
+    }
+}
+
+void startActivity::stopVideoLoopPlayback() {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+    	if (SVideoViewCallbackTab[i].loop) {
+    		ZKVideoView* videoView = (ZKVideoView*)findControlByID(SVideoViewCallbackTab[i].id);
+    		if (!videoView) {
+    			return;
+    		}
+    		if (videoView->isPlaying()) {
+    		    videoView->stop();
+    		}
+    		return;
+    	}
+    }
+}
+
+bool startActivity::parseVideoFileList(const char *pFileListPath, std::vector<string>& mediaFileList) {
+	mediaFileList.clear();
+	if (NULL == pFileListPath || 0 == strlen(pFileListPath)) {
+        LOGD("video file list is null!");
+		return false;
+	}
+
+	ifstream is(pFileListPath, ios_base::in);
+	if (!is.is_open()) {
+		LOGD("cann't open file %s \n", pFileListPath);
+		return false;
+	}
+	char tmp[1024] = {0};
+	while (is.getline(tmp, sizeof(tmp))) {
+		string str = tmp;
+		removeCharFromString(str, '\"');
+		removeCharFromString(str, '\r');
+		removeCharFromString(str, '\n');
+		if (str.size() > 1) {
+     		mediaFileList.push_back(str.c_str());
+		}
+	}
+  LOGD("(f:%s, l:%d) parse fileList[%s], get [%d]files", __FUNCTION__,
+      __LINE__, pFileListPath, int(mediaFileList.size()));
+  for (std::vector<string>::size_type i = 0; i < mediaFileList.size(); i++) {
+    LOGD("file[%u]:[%s]", ::size_t(i), mediaFileList[i].c_str());
+  }
+	is.close();
+
+	return true;
+}
+
+int startActivity::removeCharFromString(string& nString, char c) {
+    string::size_type   pos;
+    while(1) {
+        pos = nString.find(c);
+        if(pos != string::npos) {
+            nString.erase(pos, 1);
+        } else {
+            break;
+        }
+    }
+    return (int)nString.size();
+}
+
+void startActivity::registerUserTimer(int id, int time) {
+	registerTimer(id, time);
+}
+
+void startActivity::unregisterUserTimer(int id) {
+	unregisterTimer(id);
+}
+
+void startActivity::resetUserTimer(int id, int time) {
+	resetTimer(id, time);
+}

+ 97 - 0
jni/activity/startActivity.h

@@ -0,0 +1,97 @@
+/***********************************************
+/gen auto by zuitools
+***********************************************/
+#ifndef __STARTACTIVITY_H__
+#define __STARTACTIVITY_H__
+
+
+#include "app/Activity.h"
+#include "entry/EasyUIContext.h"
+
+#include "uart/ProtocolData.h"
+#include "uart/ProtocolParser.h"
+
+#include "utils/Log.h"
+#include "control/ZKDigitalClock.h"
+#include "control/ZKButton.h"
+#include "control/ZKCircleBar.h"
+#include "control/ZKDiagram.h"
+#include "control/ZKListView.h"
+#include "control/ZKPointer.h"
+#include "control/ZKQRCode.h"
+#include "control/ZKTextView.h"
+#include "control/ZKSeekBar.h"
+#include "control/ZKEditText.h"
+#include "control/ZKVideoView.h"
+#include "window/ZKSlideWindow.h"
+
+/*TAG:Macro宏ID*/
+#define ID_START_TextView1    50001
+/*TAG:Macro宏ID END*/
+
+class startActivity : public Activity, 
+                     public ZKSeekBar::ISeekBarChangeListener, 
+                     public ZKListView::IItemClickListener,
+                     public ZKListView::AbsListAdapter,
+                     public ZKSlideWindow::ISlideItemClickListener,
+                     public EasyUIContext::ITouchListener,
+                     public ZKEditText::ITextChangeListener,
+                     public ZKVideoView::IVideoPlayerMessageListener
+{
+public:
+    startActivity();
+    virtual ~startActivity();
+
+    /**
+     * 注册定时器
+     */
+	void registerUserTimer(int id, int time);
+	/**
+	 * 取消定时器
+	 */
+	void unregisterUserTimer(int id);
+	/**
+	 * 重置定时器
+	 */
+	void resetUserTimer(int id, int time);
+
+protected:
+    /*TAG:PROTECTED_FUNCTION*/
+    virtual const char* getAppName() const;
+    virtual void onCreate();
+    virtual void onClick(ZKBase *pBase);
+    virtual void onResume();
+    virtual void onPause();
+    virtual void onIntent(const Intent *intentPtr);
+    virtual bool onTimer(int id);
+
+    virtual void onProgressChanged(ZKSeekBar *pSeekBar, int progress);
+
+    virtual int getListItemCount(const ZKListView *pListView) const;
+    virtual void obtainListItemData(ZKListView *pListView, ZKListView::ZKListItem *pListItem, int index);
+    virtual void onItemClick(ZKListView *pListView, int index, int subItemIndex);
+
+    virtual void onSlideItemClick(ZKSlideWindow *pSlideWindow, int index);
+
+    virtual bool onTouchEvent(const MotionEvent &ev);
+
+    virtual void onTextChanged(ZKTextView *pTextView, const string &text);
+
+    void rigesterActivityTimer();
+
+    virtual void onVideoPlayerMessage(ZKVideoView *pVideoView, int msg);
+    void videoLoopPlayback(ZKVideoView *pVideoView, int msg, size_t callbackTabIndex);
+    void startVideoLoopPlayback();
+    void stopVideoLoopPlayback();
+    bool parseVideoFileList(const char *pFileListPath, std::vector<string>& mediaFileList);
+    int removeCharFromString(string& nString, char c);
+
+
+private:
+    /*TAG:PRIVATE_VARIABLE*/
+    int mVideoLoopIndex;
+    int mVideoLoopErrorCount;
+
+};
+
+#endif

+ 386 - 0
jni/activity/statusbar.cpp

@@ -0,0 +1,386 @@
+#include "statusbar.h"
+#include "entry/EasyUIContext.h"
+
+/*TAG:GlobalVariable全局变量*/
+static ZKTextView* mTextViewTCPPtr;
+static ZKTextView* mTextViewRegPtr;
+static ZKTextView* mPartNamePtr;
+static ZKPainter* mPainter1Ptr;
+static ZKTextView* mDateViewPtr;
+static statusbar* mstatusbarPtr;
+/* register sysapp */
+REGISTER_SYSAPP(APP_TYPE_SYS_STATUSBAR, statusbar);
+
+typedef struct {
+	int id; // 定时器ID , 不能重复
+	int time; // 定时器  时间间隔  单位 毫秒
+}S_ACTIVITY_TIMEER;
+
+#include "logic/statusbar.cc"
+
+
+/***********/
+typedef struct {
+    int id;
+    const char *pApp;
+} SAppInfo;
+
+/**
+ *点击跳转window
+ */
+static SAppInfo sAppInfoTab[] = {
+//  { ID_MAIN_TEXT, "TextViewActivity" },
+};
+
+/***************/
+typedef bool (*ButtonCallback)(ZKButton *pButton);
+/**
+ * button onclick表
+ */
+typedef struct {
+    int id;
+    ButtonCallback callback;
+}S_ButtonCallback;
+
+/*TAG:ButtonCallbackTab按键映射表*/
+static S_ButtonCallback sButtonCallbackTab[] = {
+};
+/***************/
+
+
+typedef void (*SeekBarCallback)(ZKSeekBar *pSeekBar, int progress);
+typedef struct {
+    int id;
+    SeekBarCallback callback;
+}S_ZKSeekBarCallback;
+/*TAG:SeekBarCallbackTab*/
+static S_ZKSeekBarCallback SZKSeekBarCallbackTab[] = {
+};
+
+
+typedef int (*ListViewGetItemCountCallback)(const ZKListView *pListView);
+typedef void (*ListViewobtainListItemDataCallback)(ZKListView *pListView,ZKListView::ZKListItem *pListItem, int index);
+typedef void (*ListViewonItemClickCallback)(ZKListView *pListView, int index, int id);
+typedef struct {
+    int id;
+    ListViewGetItemCountCallback getListItemCountCallback;
+    ListViewobtainListItemDataCallback obtainListItemDataCallback;
+    ListViewonItemClickCallback onItemClickCallback;
+}S_ListViewFunctionsCallback;
+/*TAG:ListViewFunctionsCallback*/
+static S_ListViewFunctionsCallback SListViewFunctionsCallbackTab[] = {
+};
+
+
+typedef void (*SlideWindowItemClickCallback)(ZKSlideWindow *pSlideWindow, int index);
+typedef struct {
+    int id;
+    SlideWindowItemClickCallback onSlideItemClickCallback;
+}S_SlideWindowItemClickCallback;
+/*TAG:SlideWindowFunctionsCallbackTab*/
+static S_SlideWindowItemClickCallback SSlideWindowItemClickCallbackTab[] = {
+};
+
+typedef void (*EditTextInputCallback)(const std::string &text);
+typedef struct {
+    int id;
+    EditTextInputCallback onEditTextChangedCallback;
+}S_EditTextInputCallback;
+/*TAG:EditTextInputCallback*/
+static S_EditTextInputCallback SEditTextInputCallbackTab[] = {
+};
+
+typedef void (*VideoViewCallback)(ZKVideoView *pVideoView, int msg);
+typedef struct {
+    int id; //VideoView ID
+    bool loop; // 是否是轮播类型
+    int defaultvolume;//轮播类型时,默认视频音量
+    VideoViewCallback onVideoViewCallback;
+}S_VideoViewCallback;
+/*TAG:VideoViewCallback*/
+static S_VideoViewCallback SVideoViewCallbackTab[] = {
+};
+
+statusbar::statusbar() {
+	mVideoLoopIndex = -1;
+	mVideoLoopErrorCount = 0;
+}
+
+statusbar::~statusbar() {
+    // 退出应用时需要反注册
+    EASYUICONTEXT->unregisterGlobalTouchListener(this);
+    onUI_quit();
+    unregisterProtocolDataUpdateListener(onProtocolDataUpdate);
+    mTextViewTCPPtr = NULL;
+    mTextViewRegPtr = NULL;
+    mPartNamePtr = NULL;
+    mPainter1Ptr = NULL;
+    mDateViewPtr = NULL;
+    mstatusbarPtr = NULL;
+}
+
+const char* statusbar::getAppName() const{
+    return "statusbar.ftu";
+}
+
+//TAG:onCreate
+void statusbar::onCreate() {
+	BaseApp::onCreate();
+    mTextViewTCPPtr = (ZKTextView*)findControlByID(ID_STATUSBAR_TextViewTCP);
+    mTextViewRegPtr = (ZKTextView*)findControlByID(ID_STATUSBAR_TextViewReg);
+    mPartNamePtr = (ZKTextView*)findControlByID(ID_STATUSBAR_PartName);
+    mPainter1Ptr = (ZKPainter*)findControlByID(ID_STATUSBAR_Painter1);
+    mDateViewPtr = (ZKTextView*)findControlByID(ID_STATUSBAR_DateView);
+	mstatusbarPtr = this;
+	onUI_init();
+    // 注册监听全局触摸
+    EASYUICONTEXT->registerGlobalTouchListener(this);
+    registerProtocolDataUpdateListener(onProtocolDataUpdate); 
+    rigesterActivityTimer();
+    startVideoLoopPlayback();
+}
+
+void statusbar::onClick(ZKBase *pBase) {
+    int buttonTablen = sizeof(sButtonCallbackTab) / sizeof(S_ButtonCallback);
+    for (int i = 0; i < buttonTablen; ++i) {
+        if (sButtonCallbackTab[i].id == pBase->getID()) {
+            if (sButtonCallbackTab[i].callback((ZKButton*)pBase)) {
+            	return;
+            }
+            break;
+        }
+    }
+
+
+    int len = sizeof(sAppInfoTab) / sizeof(sAppInfoTab[0]);
+    for (int i = 0; i < len; ++i) {
+        if (sAppInfoTab[i].id == pBase->getID()) {
+            EASYUICONTEXT->openActivity(sAppInfoTab[i].pApp);
+            return;
+        }
+    }
+
+	BaseApp::onClick(pBase);
+}
+
+bool statusbar::onTimer(int id) {
+    return onUI_Timer(id);
+}
+
+
+void statusbar::onProgressChanged(ZKSeekBar *pSeekBar, int progress){
+
+    int seekBarTablen = sizeof(SZKSeekBarCallbackTab) / sizeof(S_ZKSeekBarCallback);
+    for (int i = 0; i < seekBarTablen; ++i) {
+        if (SZKSeekBarCallbackTab[i].id == pSeekBar->getID()) {
+            SZKSeekBarCallbackTab[i].callback(pSeekBar, progress);
+            break;
+        }
+    }
+}
+
+int statusbar::getListItemCount(const ZKListView *pListView) const{
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            return SListViewFunctionsCallbackTab[i].getListItemCountCallback(pListView);
+            break;
+        }
+    }
+    return 0;
+}
+void statusbar::obtainListItemData(ZKListView *pListView,ZKListView::ZKListItem *pListItem, int index){
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            SListViewFunctionsCallbackTab[i].obtainListItemDataCallback(pListView, pListItem, index);
+            break;
+        }
+    }
+}
+void statusbar::onItemClick(ZKListView *pListView, int index, int id){
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            SListViewFunctionsCallbackTab[i].onItemClickCallback(pListView, index, id);
+            break;
+        }
+    }
+}
+
+void statusbar::onSlideItemClick(ZKSlideWindow *pSlideWindow, int index) {
+    int tablen = sizeof(SSlideWindowItemClickCallbackTab) / sizeof(S_SlideWindowItemClickCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SSlideWindowItemClickCallbackTab[i].id == pSlideWindow->getID()) {
+            SSlideWindowItemClickCallbackTab[i].onSlideItemClickCallback(pSlideWindow, index);
+            break;
+        }
+    }
+}
+
+bool statusbar::onTouchEvent(const MotionEvent &ev) {
+    return onstatusbarActivityTouchEvent(ev);
+}
+
+void statusbar::onTextChanged(ZKTextView *pTextView, const std::string &text) {
+    int tablen = sizeof(SEditTextInputCallbackTab) / sizeof(S_EditTextInputCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SEditTextInputCallbackTab[i].id == pTextView->getID()) {
+            SEditTextInputCallbackTab[i].onEditTextChangedCallback(text);
+            break;
+        }
+    }
+}
+
+void statusbar::rigesterActivityTimer() {
+    int tablen = sizeof(REGISTER_ACTIVITY_TIMER_TAB) / sizeof(S_ACTIVITY_TIMEER);
+    for (int i = 0; i < tablen; ++i) {
+        S_ACTIVITY_TIMEER temp = REGISTER_ACTIVITY_TIMER_TAB[i];
+        registerTimer(temp.id, temp.time);
+    }
+}
+
+
+void statusbar::onVideoPlayerMessage(ZKVideoView *pVideoView, int msg) {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SVideoViewCallbackTab[i].id == pVideoView->getID()) {
+        	if (SVideoViewCallbackTab[i].loop) {
+                //循环播放
+        		videoLoopPlayback(pVideoView, msg, i);
+        	} else if (SVideoViewCallbackTab[i].onVideoViewCallback != NULL){
+        	    SVideoViewCallbackTab[i].onVideoViewCallback(pVideoView, msg);
+        	}
+            break;
+        }
+    }
+}
+
+void statusbar::videoLoopPlayback(ZKVideoView *pVideoView, int msg, size_t callbackTabIndex) {
+
+	switch (msg) {
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_STARTED:
+		LOGD("ZKVideoView::E_MSGTYPE_VIDEO_PLAY_STARTED\n");
+    if (callbackTabIndex >= (sizeof(SVideoViewCallbackTab)/sizeof(S_VideoViewCallback))) {
+      break;
+    }
+		pVideoView->setVolume(SVideoViewCallbackTab[callbackTabIndex].defaultvolume / 10.0);
+		mVideoLoopErrorCount = 0;
+		break;
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_ERROR:
+		/**错误处理 */
+		++mVideoLoopErrorCount;
+		if (mVideoLoopErrorCount > 100) {
+			LOGD("video loop error counts > 100, quit loop playback !");
+            break;
+		} //不用break, 继续尝试播放下一个
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED:
+		LOGD("ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED\n");
+        std::vector<std::string> videolist;
+        std::string fileName(getAppName());
+        if (fileName.size() < 4) {
+             LOGD("getAppName size < 4, ignore!");
+             break;
+        }
+        fileName = fileName.substr(0, fileName.length() - 4) + "_video_list.txt";
+        fileName = "/mnt/extsd/" + fileName;
+        if (!parseVideoFileList(fileName.c_str(), videolist)) {
+            LOGD("parseVideoFileList failed !");
+		    break;
+        }
+		if (pVideoView && !videolist.empty()) {
+			mVideoLoopIndex = (mVideoLoopIndex + 1) % videolist.size();
+			pVideoView->play(videolist[mVideoLoopIndex].c_str());
+		}
+		break;
+	}
+}
+
+void statusbar::startVideoLoopPlayback() {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+    	if (SVideoViewCallbackTab[i].loop) {
+    		ZKVideoView* videoView = (ZKVideoView*)findControlByID(SVideoViewCallbackTab[i].id);
+    		if (!videoView) {
+    			return;
+    		}
+    		//循环播放
+    		videoLoopPlayback(videoView, ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED, i);
+    		return;
+    	}
+    }
+}
+
+void statusbar::stopVideoLoopPlayback() {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+    	if (SVideoViewCallbackTab[i].loop) {
+    		ZKVideoView* videoView = (ZKVideoView*)findControlByID(SVideoViewCallbackTab[i].id);
+    		if (!videoView) {
+    			return;
+    		}
+    		if (videoView->isPlaying()) {
+    		    videoView->stop();
+    		}
+    		return;
+    	}
+    }
+}
+
+bool statusbar::parseVideoFileList(const char *pFileListPath, std::vector<string>& mediaFileList) {
+	mediaFileList.clear();
+	if (NULL == pFileListPath || 0 == strlen(pFileListPath)) {
+        LOGD("video file list is null!");
+		return false;
+	}
+
+	ifstream is(pFileListPath, ios_base::in);
+	if (!is.is_open()) {
+		LOGD("cann't open file %s \n", pFileListPath);
+		return false;
+	}
+	char tmp[1024] = {0};
+	while (is.getline(tmp, sizeof(tmp))) {
+		string str = tmp;
+		removeCharFromString(str, '\"');
+		removeCharFromString(str, '\r');
+		removeCharFromString(str, '\n');
+		if (str.size() > 1) {
+     		mediaFileList.push_back(str.c_str());
+		}
+	}
+	LOGD("(f:%s, l:%d) parse fileList[%s], get [%d]files\n", __FUNCTION__,
+			__LINE__, pFileListPath, mediaFileList.size());
+	for (size_t i = 0; i < mediaFileList.size(); i++) {
+		LOGD("file[%d]:[%s]\n", i, mediaFileList[i].c_str());
+	}
+	is.close();
+
+	return true;
+}
+
+int statusbar::removeCharFromString(string& nString, char c)
+{
+    string::size_type   pos;
+    while(1) {
+        pos = nString.find(c);
+        if(pos != string::npos) {
+            nString.erase(pos, 1);
+        } else {
+            break;
+        }
+    }
+    return (int)nString.size();
+}
+
+void statusbar::registerUserTimer(int id, int time) {
+	registerTimer(id, time);
+}
+
+void statusbar::unregisterUserTimer(int id) {
+	unregisterTimer(id);
+}
+
+void statusbar::resetUserTimer(int id, int time) {
+	resetTimer(id, time);
+}

+ 92 - 0
jni/activity/statusbar.h

@@ -0,0 +1,92 @@
+#ifndef _SYSAPP_STATUSBAR_H_
+#define _SYSAPP_STATUSBAR_H_
+
+#include "entry/EasyUIContext.h"
+#include "app/SysAppFactory.h"
+
+#include "uart/ProtocolData.h"
+#include "uart/ProtocolParser.h"
+
+#include "utils/Log.h"
+#include "control/ZKDigitalClock.h"
+#include "control/ZKButton.h"
+#include "control/ZKCircleBar.h"
+#include "control/ZKDiagram.h"
+#include "control/ZKListView.h"
+#include "control/ZKPainter.h"
+#include "control/ZKPointer.h"
+#include "control/ZKQRCode.h"
+#include "control/ZKTextView.h"
+#include "control/ZKSeekBar.h"
+#include "control/ZKEditText.h"
+#include "control/ZKVideoView.h"
+#include "window/ZKSlideWindow.h"
+/*TAG:Macro宏ID*/
+#define ID_STATUSBAR_TextViewTCP    50004
+#define ID_STATUSBAR_TextViewReg    50002
+#define ID_STATUSBAR_PartName    50003
+#define ID_STATUSBAR_Painter1    52001
+#define ID_STATUSBAR_DateView    50001
+/*TAG:Macro宏ID END*/
+class statusbar : public BaseApp,
+                  public ZKSeekBar::ISeekBarChangeListener, 
+                  public ZKListView::IItemClickListener,
+                  public ZKListView::AbsListAdapter,
+                  public ZKSlideWindow::ISlideItemClickListener,
+                  public EasyUIContext::ITouchListener,
+                  public ZKEditText::ITextChangeListener,
+                  public ZKVideoView::IVideoPlayerMessageListener
+{
+public:
+	statusbar();
+	virtual ~statusbar();
+	virtual void onCreate();
+	virtual void onClick(ZKBase *pBase);
+	virtual bool onTimer(int id);
+
+    virtual void onProgressChanged(ZKSeekBar *pSeekBar, int progress);
+
+    virtual int getListItemCount(const ZKListView *pListView) const;
+    virtual void obtainListItemData(ZKListView *pListView, ZKListView::ZKListItem *pListItem, int index);
+    virtual void onItemClick(ZKListView *pListView, int index, int subItemIndex);
+
+    virtual void onSlideItemClick(ZKSlideWindow *pSlideWindow, int index);
+
+    virtual bool onTouchEvent(const MotionEvent &ev);
+
+    virtual void onTextChanged(ZKTextView *pTextView, const string &text);
+
+    void rigesterActivityTimer();
+
+    virtual void onVideoPlayerMessage(ZKVideoView *pVideoView, int msg);
+    void videoLoopPlayback(ZKVideoView *pVideoView, int msg, size_t callbackTabIndex);
+    void startVideoLoopPlayback();
+    void stopVideoLoopPlayback();
+    bool parseVideoFileList(const char *pFileListPath, std::vector<string>& mediaFileList);
+    int removeCharFromString(string& nString, char c);
+
+    /**
+     * 注册定时器
+     */
+	void registerUserTimer(int id, int time);
+	/**
+	 * 取消定时器
+	 */
+	void unregisterUserTimer(int id);
+	/**
+	 * 重置定时器
+	 */
+	void resetUserTimer(int id, int time);
+
+protected:
+    /*TAG:PROTECTED_FUNCTION*/
+	virtual const char* getAppName() const;
+
+
+private:
+    /*TAG:PRIVATE_VARIABLE*/
+    int mVideoLoopIndex;
+    int mVideoLoopErrorCount;
+};
+
+#endif

+ 422 - 0
jni/activity/testActivity.cpp

@@ -0,0 +1,422 @@
+/***********************************************
+/gen auto by zuitools
+***********************************************/
+#include "testActivity.h"
+
+/*TAG:GlobalVariable全局变量*/
+static ZKButton* mButton8Ptr;
+static ZKButton* mButton7Ptr;
+static ZKButton* mButton6Ptr;
+static ZKButton* mButton4Ptr;
+static ZKButton* mButton3Ptr;
+static ZKButton* mButton2Ptr;
+static ZKButton* mButton1Ptr;
+static testActivity* mActivityPtr;
+
+/*register activity*/
+REGISTER_ACTIVITY(testActivity);
+
+typedef struct {
+	int id; // 定时器ID , 不能重复
+	int time; // 定时器  时间间隔  单位 毫秒
+}S_ACTIVITY_TIMEER;
+
+#include "../logic/testLogic.cc"
+
+/***********/
+typedef struct {
+    int id;
+    const char *pApp;
+} SAppInfo;
+
+/**
+ *点击跳转window
+ */
+static SAppInfo sAppInfoTab[] = {
+//  { ID_TEST_TEXT, "TextViewActivity" },
+};
+
+/***************/
+typedef bool (*ButtonCallback)(ZKButton *pButton);
+/**
+ * button onclick表
+ */
+typedef struct {
+    int id;
+    ButtonCallback callback;
+}S_ButtonCallback;
+
+/*TAG:ButtonCallbackTab按键映射表*/
+static S_ButtonCallback sButtonCallbackTab[] = {
+    ID_TEST_Button8, onButtonClick_Button8,
+    ID_TEST_Button7, onButtonClick_Button7,
+    ID_TEST_Button6, onButtonClick_Button6,
+    ID_TEST_Button4, onButtonClick_Button4,
+    ID_TEST_Button3, onButtonClick_Button3,
+    ID_TEST_Button2, onButtonClick_Button2,
+    ID_TEST_Button1, onButtonClick_Button1,
+};
+/***************/
+
+
+typedef void (*SeekBarCallback)(ZKSeekBar *pSeekBar, int progress);
+typedef struct {
+    int id;
+    SeekBarCallback callback;
+}S_ZKSeekBarCallback;
+/*TAG:SeekBarCallbackTab*/
+static S_ZKSeekBarCallback SZKSeekBarCallbackTab[] = {
+};
+
+
+typedef int (*ListViewGetItemCountCallback)(const ZKListView *pListView);
+typedef void (*ListViewobtainListItemDataCallback)(ZKListView *pListView,ZKListView::ZKListItem *pListItem, int index);
+typedef void (*ListViewonItemClickCallback)(ZKListView *pListView, int index, int id);
+typedef struct {
+    int id;
+    ListViewGetItemCountCallback getListItemCountCallback;
+    ListViewobtainListItemDataCallback obtainListItemDataCallback;
+    ListViewonItemClickCallback onItemClickCallback;
+}S_ListViewFunctionsCallback;
+/*TAG:ListViewFunctionsCallback*/
+static S_ListViewFunctionsCallback SListViewFunctionsCallbackTab[] = {
+};
+
+
+typedef void (*SlideWindowItemClickCallback)(ZKSlideWindow *pSlideWindow, int index);
+typedef struct {
+    int id;
+    SlideWindowItemClickCallback onSlideItemClickCallback;
+}S_SlideWindowItemClickCallback;
+/*TAG:SlideWindowFunctionsCallbackTab*/
+static S_SlideWindowItemClickCallback SSlideWindowItemClickCallbackTab[] = {
+};
+
+
+typedef void (*EditTextInputCallback)(const std::string &text);
+typedef struct {
+    int id;
+    EditTextInputCallback onEditTextChangedCallback;
+}S_EditTextInputCallback;
+/*TAG:EditTextInputCallback*/
+static S_EditTextInputCallback SEditTextInputCallbackTab[] = {
+};
+
+typedef void (*VideoViewCallback)(ZKVideoView *pVideoView, int msg);
+typedef struct {
+    int id; //VideoView ID
+    bool loop; // 是否是轮播类型
+    int defaultvolume;//轮播类型时,默认视频音量
+    VideoViewCallback onVideoViewCallback;
+}S_VideoViewCallback;
+/*TAG:VideoViewCallback*/
+static S_VideoViewCallback SVideoViewCallbackTab[] = {
+};
+
+
+testActivity::testActivity() {
+	//todo add init code here
+	mVideoLoopIndex = -1;
+	mVideoLoopErrorCount = 0;
+}
+
+testActivity::~testActivity() {
+  //todo add init file here
+  // 退出应用时需要反注册
+    EASYUICONTEXT->unregisterGlobalTouchListener(this);
+    onUI_quit();
+    unregisterProtocolDataUpdateListener(onProtocolDataUpdate);
+    mButton8Ptr = NULL;
+    mButton7Ptr = NULL;
+    mButton6Ptr = NULL;
+    mButton4Ptr = NULL;
+    mButton3Ptr = NULL;
+    mButton2Ptr = NULL;
+    mButton1Ptr = NULL;
+    mActivityPtr = NULL;
+}
+
+const char* testActivity::getAppName() const{
+	return "test.ftu";
+}
+
+//TAG:onCreate
+void testActivity::onCreate() {
+	Activity::onCreate();
+    mButton8Ptr = (ZKButton*)findControlByID(ID_TEST_Button8);
+    mButton7Ptr = (ZKButton*)findControlByID(ID_TEST_Button7);
+    mButton6Ptr = (ZKButton*)findControlByID(ID_TEST_Button6);
+    mButton4Ptr = (ZKButton*)findControlByID(ID_TEST_Button4);
+    mButton3Ptr = (ZKButton*)findControlByID(ID_TEST_Button3);
+    mButton2Ptr = (ZKButton*)findControlByID(ID_TEST_Button2);
+    mButton1Ptr = (ZKButton*)findControlByID(ID_TEST_Button1);
+	mActivityPtr = this;
+	onUI_init();
+    registerProtocolDataUpdateListener(onProtocolDataUpdate); 
+    rigesterActivityTimer();
+}
+
+void testActivity::onClick(ZKBase *pBase) {
+	//TODO: add widget onClik code 
+    int buttonTablen = sizeof(sButtonCallbackTab) / sizeof(S_ButtonCallback);
+    for (int i = 0; i < buttonTablen; ++i) {
+        if (sButtonCallbackTab[i].id == pBase->getID()) {
+            if (sButtonCallbackTab[i].callback((ZKButton*)pBase)) {
+            	return;
+            }
+            break;
+        }
+    }
+
+
+    int len = sizeof(sAppInfoTab) / sizeof(sAppInfoTab[0]);
+    for (int i = 0; i < len; ++i) {
+        if (sAppInfoTab[i].id == pBase->getID()) {
+            EASYUICONTEXT->openActivity(sAppInfoTab[i].pApp);
+            return;
+        }
+    }
+
+	Activity::onClick(pBase);
+}
+
+void testActivity::onResume() {
+	Activity::onResume();
+	EASYUICONTEXT->registerGlobalTouchListener(this);
+	startVideoLoopPlayback();
+	onUI_show();
+}
+
+void testActivity::onPause() {
+	Activity::onPause();
+	EASYUICONTEXT->unregisterGlobalTouchListener(this);
+	stopVideoLoopPlayback();
+	onUI_hide();
+}
+
+void testActivity::onIntent(const Intent *intentPtr) {
+	Activity::onIntent(intentPtr);
+	onUI_intent(intentPtr);
+}
+
+bool testActivity::onTimer(int id) {
+	return onUI_Timer(id);
+}
+
+void testActivity::onProgressChanged(ZKSeekBar *pSeekBar, int progress){
+
+    int seekBarTablen = sizeof(SZKSeekBarCallbackTab) / sizeof(S_ZKSeekBarCallback);
+    for (int i = 0; i < seekBarTablen; ++i) {
+        if (SZKSeekBarCallbackTab[i].id == pSeekBar->getID()) {
+            SZKSeekBarCallbackTab[i].callback(pSeekBar, progress);
+            break;
+        }
+    }
+}
+
+int testActivity::getListItemCount(const ZKListView *pListView) const{
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            return SListViewFunctionsCallbackTab[i].getListItemCountCallback(pListView);
+            break;
+        }
+    }
+    return 0;
+}
+
+void testActivity::obtainListItemData(ZKListView *pListView,ZKListView::ZKListItem *pListItem, int index){
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            SListViewFunctionsCallbackTab[i].obtainListItemDataCallback(pListView, pListItem, index);
+            break;
+        }
+    }
+}
+
+void testActivity::onItemClick(ZKListView *pListView, int index, int id){
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            SListViewFunctionsCallbackTab[i].onItemClickCallback(pListView, index, id);
+            break;
+        }
+    }
+}
+
+void testActivity::onSlideItemClick(ZKSlideWindow *pSlideWindow, int index) {
+    int tablen = sizeof(SSlideWindowItemClickCallbackTab) / sizeof(S_SlideWindowItemClickCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SSlideWindowItemClickCallbackTab[i].id == pSlideWindow->getID()) {
+            SSlideWindowItemClickCallbackTab[i].onSlideItemClickCallback(pSlideWindow, index);
+            break;
+        }
+    }
+}
+
+bool testActivity::onTouchEvent(const MotionEvent &ev) {
+    return ontestActivityTouchEvent(ev);
+}
+
+void testActivity::onTextChanged(ZKTextView *pTextView, const std::string &text) {
+    int tablen = sizeof(SEditTextInputCallbackTab) / sizeof(S_EditTextInputCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SEditTextInputCallbackTab[i].id == pTextView->getID()) {
+            SEditTextInputCallbackTab[i].onEditTextChangedCallback(text);
+            break;
+        }
+    }
+}
+
+void testActivity::rigesterActivityTimer() {
+    int tablen = sizeof(REGISTER_ACTIVITY_TIMER_TAB) / sizeof(S_ACTIVITY_TIMEER);
+    for (int i = 0; i < tablen; ++i) {
+        S_ACTIVITY_TIMEER temp = REGISTER_ACTIVITY_TIMER_TAB[i];
+        registerTimer(temp.id, temp.time);
+    }
+}
+
+
+void testActivity::onVideoPlayerMessage(ZKVideoView *pVideoView, int msg) {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SVideoViewCallbackTab[i].id == pVideoView->getID()) {
+        	if (SVideoViewCallbackTab[i].loop) {
+                //循环播放
+        		videoLoopPlayback(pVideoView, msg, i);
+        	} else if (SVideoViewCallbackTab[i].onVideoViewCallback != NULL){
+        	    SVideoViewCallbackTab[i].onVideoViewCallback(pVideoView, msg);
+        	}
+            break;
+        }
+    }
+}
+
+void testActivity::videoLoopPlayback(ZKVideoView *pVideoView, int msg, size_t callbackTabIndex) {
+
+	switch (msg) {
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_STARTED:
+		LOGD("ZKVideoView::E_MSGTYPE_VIDEO_PLAY_STARTED\n");
+    if (callbackTabIndex >= (sizeof(SVideoViewCallbackTab)/sizeof(S_VideoViewCallback))) {
+      break;
+    }
+		pVideoView->setVolume(SVideoViewCallbackTab[callbackTabIndex].defaultvolume / 10.0);
+		mVideoLoopErrorCount = 0;
+		break;
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_ERROR:
+		/**错误处理 */
+		++mVideoLoopErrorCount;
+		if (mVideoLoopErrorCount > 100) {
+			LOGD("video loop error counts > 100, quit loop playback !");
+            break;
+		} //不用break, 继续尝试播放下一个
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED:
+		LOGD("ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED\n");
+        std::vector<std::string> videolist;
+        std::string fileName(getAppName());
+        if (fileName.size() < 4) {
+             LOGD("getAppName size < 4, ignore!");
+             break;
+        }
+        fileName = fileName.substr(0, fileName.length() - 4) + "_video_list.txt";
+        fileName = "/mnt/extsd/" + fileName;
+        if (!parseVideoFileList(fileName.c_str(), videolist)) {
+            LOGD("parseVideoFileList failed !");
+		    break;
+        }
+		if (pVideoView && !videolist.empty()) {
+			mVideoLoopIndex = (mVideoLoopIndex + 1) % videolist.size();
+			pVideoView->play(videolist[mVideoLoopIndex].c_str());
+		}
+		break;
+	}
+}
+
+void testActivity::startVideoLoopPlayback() {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+    	if (SVideoViewCallbackTab[i].loop) {
+    		ZKVideoView* videoView = (ZKVideoView*)findControlByID(SVideoViewCallbackTab[i].id);
+    		if (!videoView) {
+    			return;
+    		}
+    		//循环播放
+    		videoLoopPlayback(videoView, ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED, i);
+    		return;
+    	}
+    }
+}
+
+void testActivity::stopVideoLoopPlayback() {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+    	if (SVideoViewCallbackTab[i].loop) {
+    		ZKVideoView* videoView = (ZKVideoView*)findControlByID(SVideoViewCallbackTab[i].id);
+    		if (!videoView) {
+    			return;
+    		}
+    		if (videoView->isPlaying()) {
+    		    videoView->stop();
+    		}
+    		return;
+    	}
+    }
+}
+
+bool testActivity::parseVideoFileList(const char *pFileListPath, std::vector<string>& mediaFileList) {
+	mediaFileList.clear();
+	if (NULL == pFileListPath || 0 == strlen(pFileListPath)) {
+        LOGD("video file list is null!");
+		return false;
+	}
+
+	ifstream is(pFileListPath, ios_base::in);
+	if (!is.is_open()) {
+		LOGD("cann't open file %s \n", pFileListPath);
+		return false;
+	}
+	char tmp[1024] = {0};
+	while (is.getline(tmp, sizeof(tmp))) {
+		string str = tmp;
+		removeCharFromString(str, '\"');
+		removeCharFromString(str, '\r');
+		removeCharFromString(str, '\n');
+		if (str.size() > 1) {
+     		mediaFileList.push_back(str.c_str());
+		}
+	}
+  LOGD("(f:%s, l:%d) parse fileList[%s], get [%d]files", __FUNCTION__,
+      __LINE__, pFileListPath, int(mediaFileList.size()));
+  for (std::vector<string>::size_type i = 0; i < mediaFileList.size(); i++) {
+    LOGD("file[%u]:[%s]", ::size_t(i), mediaFileList[i].c_str());
+  }
+	is.close();
+
+	return true;
+}
+
+int testActivity::removeCharFromString(string& nString, char c) {
+    string::size_type   pos;
+    while(1) {
+        pos = nString.find(c);
+        if(pos != string::npos) {
+            nString.erase(pos, 1);
+        } else {
+            break;
+        }
+    }
+    return (int)nString.size();
+}
+
+void testActivity::registerUserTimer(int id, int time) {
+	registerTimer(id, time);
+}
+
+void testActivity::unregisterUserTimer(int id) {
+	unregisterTimer(id);
+}
+
+void testActivity::resetUserTimer(int id, int time) {
+	resetTimer(id, time);
+}

+ 103 - 0
jni/activity/testActivity.h

@@ -0,0 +1,103 @@
+/***********************************************
+/gen auto by zuitools
+***********************************************/
+#ifndef __TESTACTIVITY_H__
+#define __TESTACTIVITY_H__
+
+
+#include "app/Activity.h"
+#include "entry/EasyUIContext.h"
+
+#include "uart/ProtocolData.h"
+#include "uart/ProtocolParser.h"
+
+#include "utils/Log.h"
+#include "control/ZKDigitalClock.h"
+#include "control/ZKButton.h"
+#include "control/ZKCircleBar.h"
+#include "control/ZKDiagram.h"
+#include "control/ZKListView.h"
+#include "control/ZKPointer.h"
+#include "control/ZKQRCode.h"
+#include "control/ZKTextView.h"
+#include "control/ZKSeekBar.h"
+#include "control/ZKEditText.h"
+#include "control/ZKVideoView.h"
+#include "window/ZKSlideWindow.h"
+
+/*TAG:Macro宏ID*/
+#define ID_TEST_Button8    20008
+#define ID_TEST_Button7    20007
+#define ID_TEST_Button6    20006
+#define ID_TEST_Button4    20004
+#define ID_TEST_Button3    20003
+#define ID_TEST_Button2    20002
+#define ID_TEST_Button1    20001
+/*TAG:Macro宏ID END*/
+
+class testActivity : public Activity,
+                     public ZKSeekBar::ISeekBarChangeListener, 
+                     public ZKListView::IItemClickListener,
+                     public ZKListView::AbsListAdapter,
+                     public ZKSlideWindow::ISlideItemClickListener,
+                     public EasyUIContext::ITouchListener,
+                     public ZKEditText::ITextChangeListener,
+                     public ZKVideoView::IVideoPlayerMessageListener
+{
+public:
+    testActivity();
+    virtual ~testActivity();
+
+    /**
+     * 注册定时器
+     */
+	void registerUserTimer(int id, int time);
+	/**
+	 * 取消定时器
+	 */
+	void unregisterUserTimer(int id);
+	/**
+	 * 重置定时器
+	 */
+	void resetUserTimer(int id, int time);
+
+protected:
+    /*TAG:PROTECTED_FUNCTION*/
+    virtual const char* getAppName() const;
+    virtual void onCreate();
+    virtual void onClick(ZKBase *pBase);
+    virtual void onResume();
+    virtual void onPause();
+    virtual void onIntent(const Intent *intentPtr);
+    virtual bool onTimer(int id);
+
+    virtual void onProgressChanged(ZKSeekBar *pSeekBar, int progress);
+
+    virtual int getListItemCount(const ZKListView *pListView) const;
+    virtual void obtainListItemData(ZKListView *pListView, ZKListView::ZKListItem *pListItem, int index);
+    virtual void onItemClick(ZKListView *pListView, int index, int subItemIndex);
+
+    virtual void onSlideItemClick(ZKSlideWindow *pSlideWindow, int index);
+
+    virtual bool onTouchEvent(const MotionEvent &ev);
+
+    virtual void onTextChanged(ZKTextView *pTextView, const string &text);
+
+    void rigesterActivityTimer();
+
+    virtual void onVideoPlayerMessage(ZKVideoView *pVideoView, int msg);
+    void videoLoopPlayback(ZKVideoView *pVideoView, int msg, size_t callbackTabIndex);
+    void startVideoLoopPlayback();
+    void stopVideoLoopPlayback();
+    bool parseVideoFileList(const char *pFileListPath, std::vector<string>& mediaFileList);
+    int removeCharFromString(string& nString, char c);
+
+
+private:
+    /*TAG:PRIVATE_VARIABLE*/
+    int mVideoLoopIndex;
+    int mVideoLoopErrorCount;
+
+};
+
+#endif

+ 511 - 0
jni/activity/ui3Activity.cpp

@@ -0,0 +1,511 @@
+/***********************************************
+/gen auto by zuitools
+***********************************************/
+#include "ui3Activity.h"
+
+/*TAG:GlobalVariable全局变量*/
+static ZKButton* msys_backPtr;
+static ZKTextView* mVoiceDomainPtr;
+static ZKButton* mBtnSoftVerPtr;
+static ZKButton* mBtnNetSettingPtr;
+static ZKTextView* mServerIPPtr;
+static ZKTextView* mTextView7Ptr;
+static ZKTextView* mTextView10Ptr;
+static ZKTextView* mDeviceCodePtr;
+static ZKTextView* mTextPwdInfoPtr;
+static ZKButton* mBtnRestartPtr;
+static ZKTextView* mTextView12Ptr;
+static ZKTextView* mGatewayPtr;
+static ZKTextView* mTextView8Ptr;
+static ZKTextView* mNetMaskPtr;
+static ZKTextView* mServerIPMsgPtr;
+static ZKButton* mBtnServerIPConfirmPtr;
+static ZKTextView* mTextView6Ptr;
+static ZKEditText* mEditTextServerIPPtr;
+static ZKWindow* mWindowServerIPPtr;
+static ZKWindow* mWindowPwdPtr;
+static ZKButton* mBtnPwdConfirmPtr;
+static ZKTextView* mTextView2Ptr;
+static ZKEditText* mEditTextPwdPtr;
+static ZKButton* mSettingPtr;
+static ZKTextView* mTextView4Ptr;
+static ZKTextView* mDeviceIpPtr;
+static ZKQRCode* mQRCode1Ptr;
+static ZKTextView* mTextView11Ptr;
+static ZKTextView* mVersionPtr;
+static ZKTextView* mTextView9Ptr;
+static ZKTextView* mVoiceIdPtr;
+static ZKTextView* mTextView5Ptr;
+static ZKTextView* mDeviceMacPtr;
+static ZKTextView* mTextView3Ptr;
+static ZKTextView* mDeviceIdPtr;
+static ZKTextView* mTextView1Ptr;
+static ui3Activity* mActivityPtr;
+
+/*register activity*/
+REGISTER_ACTIVITY(ui3Activity);
+
+typedef struct {
+	int id; // 定时器ID , 不能重复
+	int time; // 定时器  时间间隔  单位 毫秒
+}S_ACTIVITY_TIMEER;
+
+#include "logic/ui3Logic.cc"
+
+/***********/
+typedef struct {
+    int id;
+    const char *pApp;
+} SAppInfo;
+
+/**
+ *点击跳转window
+ */
+static SAppInfo sAppInfoTab[] = {
+//  { ID_MAIN_TEXT, "TextViewActivity" },
+};
+
+/***************/
+typedef bool (*ButtonCallback)(ZKButton *pButton);
+/**
+ * button onclick表
+ */
+typedef struct {
+    int id;
+    ButtonCallback callback;
+}S_ButtonCallback;
+
+/*TAG:ButtonCallbackTab按键映射表*/
+static S_ButtonCallback sButtonCallbackTab[] = {
+    ID_UI3_sys_back, onButtonClick_sys_back,
+    ID_UI3_BtnSoftVer, onButtonClick_BtnSoftVer,
+    ID_UI3_BtnNetSetting, onButtonClick_BtnNetSetting,
+    ID_UI3_BtnRestart, onButtonClick_BtnRestart,
+    ID_UI3_BtnServerIPConfirm, onButtonClick_BtnServerIPConfirm,
+    ID_UI3_BtnPwdConfirm, onButtonClick_BtnPwdConfirm,
+    ID_UI3_Setting, onButtonClick_Setting,
+};
+/***************/
+
+
+typedef void (*SeekBarCallback)(ZKSeekBar *pSeekBar, int progress);
+typedef struct {
+    int id;
+    SeekBarCallback callback;
+}S_ZKSeekBarCallback;
+/*TAG:SeekBarCallbackTab*/
+static S_ZKSeekBarCallback SZKSeekBarCallbackTab[] = {
+};
+
+
+typedef int (*ListViewGetItemCountCallback)(const ZKListView *pListView);
+typedef void (*ListViewobtainListItemDataCallback)(ZKListView *pListView,ZKListView::ZKListItem *pListItem, int index);
+typedef void (*ListViewonItemClickCallback)(ZKListView *pListView, int index, int id);
+typedef struct {
+    int id;
+    ListViewGetItemCountCallback getListItemCountCallback;
+    ListViewobtainListItemDataCallback obtainListItemDataCallback;
+    ListViewonItemClickCallback onItemClickCallback;
+}S_ListViewFunctionsCallback;
+/*TAG:ListViewFunctionsCallback*/
+static S_ListViewFunctionsCallback SListViewFunctionsCallbackTab[] = {
+};
+
+
+typedef void (*SlideWindowItemClickCallback)(ZKSlideWindow *pSlideWindow, int index);
+typedef struct {
+    int id;
+    SlideWindowItemClickCallback onSlideItemClickCallback;
+}S_SlideWindowItemClickCallback;
+/*TAG:SlideWindowFunctionsCallbackTab*/
+static S_SlideWindowItemClickCallback SSlideWindowItemClickCallbackTab[] = {
+};
+
+
+typedef void (*EditTextInputCallback)(const std::string &text);
+typedef struct {
+    int id;
+    EditTextInputCallback onEditTextChangedCallback;
+}S_EditTextInputCallback;
+/*TAG:EditTextInputCallback*/
+static S_EditTextInputCallback SEditTextInputCallbackTab[] = {
+    ID_UI3_EditTextServerIP, onEditTextChanged_EditTextServerIP,
+    ID_UI3_EditTextPwd, onEditTextChanged_EditTextPwd,
+};
+
+typedef void (*VideoViewCallback)(ZKVideoView *pVideoView, int msg);
+typedef struct {
+    int id; //VideoView ID
+    bool loop; // 是否是轮播类型
+    int defaultvolume;//轮播类型时,默认视频音量
+    VideoViewCallback onVideoViewCallback;
+}S_VideoViewCallback;
+/*TAG:VideoViewCallback*/
+static S_VideoViewCallback SVideoViewCallbackTab[] = {
+};
+
+
+ui3Activity::ui3Activity() {
+	//todo add init code here
+	mVideoLoopIndex = -1;
+	mVideoLoopErrorCount = 0;
+}
+
+ui3Activity::~ui3Activity() {
+  //todo add init file here
+  // 退出应用时需要反注册
+    EASYUICONTEXT->unregisterGlobalTouchListener(this);
+    onUI_quit();
+    unregisterProtocolDataUpdateListener(onProtocolDataUpdate);
+    msys_backPtr = NULL;
+    mVoiceDomainPtr = NULL;
+    mBtnSoftVerPtr = NULL;
+    mBtnNetSettingPtr = NULL;
+    mServerIPPtr = NULL;
+    mTextView7Ptr = NULL;
+    mTextView10Ptr = NULL;
+    mDeviceCodePtr = NULL;
+    mTextPwdInfoPtr = NULL;
+    mBtnRestartPtr = NULL;
+    mTextView12Ptr = NULL;
+    mGatewayPtr = NULL;
+    mTextView8Ptr = NULL;
+    mNetMaskPtr = NULL;
+    mServerIPMsgPtr = NULL;
+    mBtnServerIPConfirmPtr = NULL;
+    mTextView6Ptr = NULL;
+    mEditTextServerIPPtr = NULL;
+    mWindowServerIPPtr = NULL;
+    mWindowPwdPtr = NULL;
+    mBtnPwdConfirmPtr = NULL;
+    mTextView2Ptr = NULL;
+    mEditTextPwdPtr = NULL;
+    mSettingPtr = NULL;
+    mTextView4Ptr = NULL;
+    mDeviceIpPtr = NULL;
+    mQRCode1Ptr = NULL;
+    mTextView11Ptr = NULL;
+    mVersionPtr = NULL;
+    mTextView9Ptr = NULL;
+    mVoiceIdPtr = NULL;
+    mTextView5Ptr = NULL;
+    mDeviceMacPtr = NULL;
+    mTextView3Ptr = NULL;
+    mDeviceIdPtr = NULL;
+    mTextView1Ptr = NULL;
+    mActivityPtr = NULL;
+}
+
+const char* ui3Activity::getAppName() const{
+	return "ui3.ftu";
+}
+
+//TAG:onCreate
+void ui3Activity::onCreate() {
+	Activity::onCreate();
+    msys_backPtr = (ZKButton*)findControlByID(ID_UI3_sys_back);
+    mVoiceDomainPtr = (ZKTextView*)findControlByID(ID_UI3_VoiceDomain);
+    mBtnSoftVerPtr = (ZKButton*)findControlByID(ID_UI3_BtnSoftVer);
+    mBtnNetSettingPtr = (ZKButton*)findControlByID(ID_UI3_BtnNetSetting);
+    mServerIPPtr = (ZKTextView*)findControlByID(ID_UI3_ServerIP);
+    mTextView7Ptr = (ZKTextView*)findControlByID(ID_UI3_TextView7);
+    mTextView10Ptr = (ZKTextView*)findControlByID(ID_UI3_TextView10);
+    mDeviceCodePtr = (ZKTextView*)findControlByID(ID_UI3_DeviceCode);
+    mTextPwdInfoPtr = (ZKTextView*)findControlByID(ID_UI3_TextPwdInfo);
+    mBtnRestartPtr = (ZKButton*)findControlByID(ID_UI3_BtnRestart);
+    mTextView12Ptr = (ZKTextView*)findControlByID(ID_UI3_TextView12);
+    mGatewayPtr = (ZKTextView*)findControlByID(ID_UI3_Gateway);
+    mTextView8Ptr = (ZKTextView*)findControlByID(ID_UI3_TextView8);
+    mNetMaskPtr = (ZKTextView*)findControlByID(ID_UI3_NetMask);
+    mServerIPMsgPtr = (ZKTextView*)findControlByID(ID_UI3_ServerIPMsg);
+    mBtnServerIPConfirmPtr = (ZKButton*)findControlByID(ID_UI3_BtnServerIPConfirm);
+    mTextView6Ptr = (ZKTextView*)findControlByID(ID_UI3_TextView6);
+    mEditTextServerIPPtr = (ZKEditText*)findControlByID(ID_UI3_EditTextServerIP);if(mEditTextServerIPPtr!= NULL){mEditTextServerIPPtr->setTextChangeListener(this);}
+    mWindowServerIPPtr = (ZKWindow*)findControlByID(ID_UI3_WindowServerIP);
+    mWindowPwdPtr = (ZKWindow*)findControlByID(ID_UI3_WindowPwd);
+    mBtnPwdConfirmPtr = (ZKButton*)findControlByID(ID_UI3_BtnPwdConfirm);
+    mTextView2Ptr = (ZKTextView*)findControlByID(ID_UI3_TextView2);
+    mEditTextPwdPtr = (ZKEditText*)findControlByID(ID_UI3_EditTextPwd);if(mEditTextPwdPtr!= NULL){mEditTextPwdPtr->setTextChangeListener(this);}
+    mSettingPtr = (ZKButton*)findControlByID(ID_UI3_Setting);
+    mTextView4Ptr = (ZKTextView*)findControlByID(ID_UI3_TextView4);
+    mDeviceIpPtr = (ZKTextView*)findControlByID(ID_UI3_DeviceIp);
+    mQRCode1Ptr = (ZKQRCode*)findControlByID(ID_UI3_QRCode1);
+    mTextView11Ptr = (ZKTextView*)findControlByID(ID_UI3_TextView11);
+    mVersionPtr = (ZKTextView*)findControlByID(ID_UI3_Version);
+    mTextView9Ptr = (ZKTextView*)findControlByID(ID_UI3_TextView9);
+    mVoiceIdPtr = (ZKTextView*)findControlByID(ID_UI3_VoiceId);
+    mTextView5Ptr = (ZKTextView*)findControlByID(ID_UI3_TextView5);
+    mDeviceMacPtr = (ZKTextView*)findControlByID(ID_UI3_DeviceMac);
+    mTextView3Ptr = (ZKTextView*)findControlByID(ID_UI3_TextView3);
+    mDeviceIdPtr = (ZKTextView*)findControlByID(ID_UI3_DeviceId);
+    mTextView1Ptr = (ZKTextView*)findControlByID(ID_UI3_TextView1);
+	mActivityPtr = this;
+	onUI_init();
+    registerProtocolDataUpdateListener(onProtocolDataUpdate); 
+    rigesterActivityTimer();
+}
+
+void ui3Activity::onClick(ZKBase *pBase) {
+	//TODO: add widget onClik code 
+    int buttonTablen = sizeof(sButtonCallbackTab) / sizeof(S_ButtonCallback);
+    for (int i = 0; i < buttonTablen; ++i) {
+        if (sButtonCallbackTab[i].id == pBase->getID()) {
+            if (sButtonCallbackTab[i].callback((ZKButton*)pBase)) {
+            	return;
+            }
+            break;
+        }
+    }
+
+
+    int len = sizeof(sAppInfoTab) / sizeof(sAppInfoTab[0]);
+    for (int i = 0; i < len; ++i) {
+        if (sAppInfoTab[i].id == pBase->getID()) {
+            EASYUICONTEXT->openActivity(sAppInfoTab[i].pApp);
+            return;
+        }
+    }
+
+	Activity::onClick(pBase);
+}
+
+void ui3Activity::onResume() {
+	Activity::onResume();
+	EASYUICONTEXT->registerGlobalTouchListener(this);
+	startVideoLoopPlayback();
+	onUI_show();
+}
+
+void ui3Activity::onPause() {
+	Activity::onPause();
+	EASYUICONTEXT->unregisterGlobalTouchListener(this);
+	stopVideoLoopPlayback();
+	onUI_hide();
+}
+
+void ui3Activity::onIntent(const Intent *intentPtr) {
+	Activity::onIntent(intentPtr);
+	onUI_intent(intentPtr);
+}
+
+bool ui3Activity::onTimer(int id) {
+	return onUI_Timer(id);
+}
+
+void ui3Activity::onProgressChanged(ZKSeekBar *pSeekBar, int progress){
+
+    int seekBarTablen = sizeof(SZKSeekBarCallbackTab) / sizeof(S_ZKSeekBarCallback);
+    for (int i = 0; i < seekBarTablen; ++i) {
+        if (SZKSeekBarCallbackTab[i].id == pSeekBar->getID()) {
+            SZKSeekBarCallbackTab[i].callback(pSeekBar, progress);
+            break;
+        }
+    }
+}
+
+int ui3Activity::getListItemCount(const ZKListView *pListView) const{
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            return SListViewFunctionsCallbackTab[i].getListItemCountCallback(pListView);
+            break;
+        }
+    }
+    return 0;
+}
+
+void ui3Activity::obtainListItemData(ZKListView *pListView,ZKListView::ZKListItem *pListItem, int index){
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            SListViewFunctionsCallbackTab[i].obtainListItemDataCallback(pListView, pListItem, index);
+            break;
+        }
+    }
+}
+
+void ui3Activity::onItemClick(ZKListView *pListView, int index, int id){
+    int tablen = sizeof(SListViewFunctionsCallbackTab) / sizeof(S_ListViewFunctionsCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SListViewFunctionsCallbackTab[i].id == pListView->getID()) {
+            SListViewFunctionsCallbackTab[i].onItemClickCallback(pListView, index, id);
+            break;
+        }
+    }
+}
+
+void ui3Activity::onSlideItemClick(ZKSlideWindow *pSlideWindow, int index) {
+    int tablen = sizeof(SSlideWindowItemClickCallbackTab) / sizeof(S_SlideWindowItemClickCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SSlideWindowItemClickCallbackTab[i].id == pSlideWindow->getID()) {
+            SSlideWindowItemClickCallbackTab[i].onSlideItemClickCallback(pSlideWindow, index);
+            break;
+        }
+    }
+}
+
+bool ui3Activity::onTouchEvent(const MotionEvent &ev) {
+    return onui3ActivityTouchEvent(ev);
+}
+
+void ui3Activity::onTextChanged(ZKTextView *pTextView, const std::string &text) {
+    int tablen = sizeof(SEditTextInputCallbackTab) / sizeof(S_EditTextInputCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SEditTextInputCallbackTab[i].id == pTextView->getID()) {
+            SEditTextInputCallbackTab[i].onEditTextChangedCallback(text);
+            break;
+        }
+    }
+}
+
+void ui3Activity::rigesterActivityTimer() {
+    int tablen = sizeof(REGISTER_ACTIVITY_TIMER_TAB) / sizeof(S_ACTIVITY_TIMEER);
+    for (int i = 0; i < tablen; ++i) {
+        S_ACTIVITY_TIMEER temp = REGISTER_ACTIVITY_TIMER_TAB[i];
+        registerTimer(temp.id, temp.time);
+    }
+}
+
+
+void ui3Activity::onVideoPlayerMessage(ZKVideoView *pVideoView, int msg) {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+        if (SVideoViewCallbackTab[i].id == pVideoView->getID()) {
+        	if (SVideoViewCallbackTab[i].loop) {
+                //循环播放
+        		videoLoopPlayback(pVideoView, msg, i);
+        	} else if (SVideoViewCallbackTab[i].onVideoViewCallback != NULL){
+        	    SVideoViewCallbackTab[i].onVideoViewCallback(pVideoView, msg);
+        	}
+            break;
+        }
+    }
+}
+
+void ui3Activity::videoLoopPlayback(ZKVideoView *pVideoView, int msg, size_t callbackTabIndex) {
+
+	switch (msg) {
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_STARTED:
+		LOGD("ZKVideoView::E_MSGTYPE_VIDEO_PLAY_STARTED\n");
+    if (callbackTabIndex >= (sizeof(SVideoViewCallbackTab)/sizeof(S_VideoViewCallback))) {
+      break;
+    }
+		pVideoView->setVolume(SVideoViewCallbackTab[callbackTabIndex].defaultvolume / 10.0);
+		mVideoLoopErrorCount = 0;
+		break;
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_ERROR:
+		/**错误处理 */
+		++mVideoLoopErrorCount;
+		if (mVideoLoopErrorCount > 100) {
+			LOGD("video loop error counts > 100, quit loop playback !");
+            break;
+		} //不用break, 继续尝试播放下一个
+	case ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED:
+		LOGD("ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED\n");
+        std::vector<std::string> videolist;
+        std::string fileName(getAppName());
+        if (fileName.size() < 4) {
+             LOGD("getAppName size < 4, ignore!");
+             break;
+        }
+        fileName = fileName.substr(0, fileName.length() - 4) + "_video_list.txt";
+        fileName = "/mnt/extsd/" + fileName;
+        if (!parseVideoFileList(fileName.c_str(), videolist)) {
+            LOGD("parseVideoFileList failed !");
+		    break;
+        }
+		if (pVideoView && !videolist.empty()) {
+			mVideoLoopIndex = (mVideoLoopIndex + 1) % videolist.size();
+			pVideoView->play(videolist[mVideoLoopIndex].c_str());
+		}
+		break;
+	}
+}
+
+void ui3Activity::startVideoLoopPlayback() {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+    	if (SVideoViewCallbackTab[i].loop) {
+    		ZKVideoView* videoView = (ZKVideoView*)findControlByID(SVideoViewCallbackTab[i].id);
+    		if (!videoView) {
+    			return;
+    		}
+    		//循环播放
+    		videoLoopPlayback(videoView, ZKVideoView::E_MSGTYPE_VIDEO_PLAY_COMPLETED, i);
+    		return;
+    	}
+    }
+}
+
+void ui3Activity::stopVideoLoopPlayback() {
+    int tablen = sizeof(SVideoViewCallbackTab) / sizeof(S_VideoViewCallback);
+    for (int i = 0; i < tablen; ++i) {
+    	if (SVideoViewCallbackTab[i].loop) {
+    		ZKVideoView* videoView = (ZKVideoView*)findControlByID(SVideoViewCallbackTab[i].id);
+    		if (!videoView) {
+    			return;
+    		}
+    		if (videoView->isPlaying()) {
+    		    videoView->stop();
+    		}
+    		return;
+    	}
+    }
+}
+
+bool ui3Activity::parseVideoFileList(const char *pFileListPath, std::vector<string>& mediaFileList) {
+	mediaFileList.clear();
+	if (NULL == pFileListPath || 0 == strlen(pFileListPath)) {
+        LOGD("video file list is null!");
+		return false;
+	}
+
+	ifstream is(pFileListPath, ios_base::in);
+	if (!is.is_open()) {
+		LOGD("cann't open file %s \n", pFileListPath);
+		return false;
+	}
+	char tmp[1024] = {0};
+	while (is.getline(tmp, sizeof(tmp))) {
+		string str = tmp;
+		removeCharFromString(str, '\"');
+		removeCharFromString(str, '\r');
+		removeCharFromString(str, '\n');
+		if (str.size() > 1) {
+     		mediaFileList.push_back(str.c_str());
+		}
+	}
+  LOGD("(f:%s, l:%d) parse fileList[%s], get [%d]files", __FUNCTION__,
+      __LINE__, pFileListPath, int(mediaFileList.size()));
+  for (std::vector<string>::size_type i = 0; i < mediaFileList.size(); i++) {
+    LOGD("file[%u]:[%s]", ::size_t(i), mediaFileList[i].c_str());
+  }
+	is.close();
+
+	return true;
+}
+
+int ui3Activity::removeCharFromString(string& nString, char c) {
+    string::size_type   pos;
+    while(1) {
+        pos = nString.find(c);
+        if(pos != string::npos) {
+            nString.erase(pos, 1);
+        } else {
+            break;
+        }
+    }
+    return (int)nString.size();
+}
+
+void ui3Activity::registerUserTimer(int id, int time) {
+	registerTimer(id, time);
+}
+
+void ui3Activity::unregisterUserTimer(int id) {
+	unregisterTimer(id);
+}
+
+void ui3Activity::resetUserTimer(int id, int time) {
+	resetTimer(id, time);
+}

+ 132 - 0
jni/activity/ui3Activity.h

@@ -0,0 +1,132 @@
+/***********************************************
+/gen auto by zuitools
+***********************************************/
+#ifndef __UI3ACTIVITY_H__
+#define __UI3ACTIVITY_H__
+
+
+#include "app/Activity.h"
+#include "entry/EasyUIContext.h"
+
+#include "uart/ProtocolData.h"
+#include "uart/ProtocolParser.h"
+
+#include "utils/Log.h"
+#include "control/ZKDigitalClock.h"
+#include "control/ZKButton.h"
+#include "control/ZKCircleBar.h"
+#include "control/ZKDiagram.h"
+#include "control/ZKListView.h"
+#include "control/ZKPointer.h"
+#include "control/ZKQRCode.h"
+#include "control/ZKTextView.h"
+#include "control/ZKSeekBar.h"
+#include "control/ZKEditText.h"
+#include "control/ZKVideoView.h"
+#include "window/ZKSlideWindow.h"
+
+/*TAG:Macro宏ID*/
+#define ID_UI3_sys_back   100
+#define ID_UI3_VoiceDomain    50012
+#define ID_UI3_BtnSoftVer    20006
+#define ID_UI3_BtnNetSetting    20005
+#define ID_UI3_ServerIP    50024
+#define ID_UI3_TextView7    50023
+#define ID_UI3_TextView10    50021
+#define ID_UI3_DeviceCode    50020
+#define ID_UI3_TextPwdInfo    50022
+#define ID_UI3_BtnRestart    20004
+#define ID_UI3_TextView12    50019
+#define ID_UI3_Gateway    50018
+#define ID_UI3_TextView8    50017
+#define ID_UI3_NetMask    50016
+#define ID_UI3_ServerIPMsg    50015
+#define ID_UI3_BtnServerIPConfirm    20003
+#define ID_UI3_TextView6    50014
+#define ID_UI3_EditTextServerIP    51002
+#define ID_UI3_WindowServerIP    110002
+#define ID_UI3_WindowPwd    110001
+#define ID_UI3_BtnPwdConfirm    20002
+#define ID_UI3_TextView2    50013
+#define ID_UI3_EditTextPwd    51001
+#define ID_UI3_Setting    20001
+#define ID_UI3_TextView4    50008
+#define ID_UI3_DeviceIp    50007
+#define ID_UI3_QRCode1    92001
+#define ID_UI3_TextView11    50011
+#define ID_UI3_Version    50010
+#define ID_UI3_TextView9    50009
+#define ID_UI3_VoiceId    50006
+#define ID_UI3_TextView5    50005
+#define ID_UI3_DeviceMac    50004
+#define ID_UI3_TextView3    50003
+#define ID_UI3_DeviceId    50002
+#define ID_UI3_TextView1    50001
+/*TAG:Macro宏ID END*/
+
+class ui3Activity : public Activity, 
+                     public ZKSeekBar::ISeekBarChangeListener, 
+                     public ZKListView::IItemClickListener,
+                     public ZKListView::AbsListAdapter,
+                     public ZKSlideWindow::ISlideItemClickListener,
+                     public EasyUIContext::ITouchListener,
+                     public ZKEditText::ITextChangeListener,
+                     public ZKVideoView::IVideoPlayerMessageListener
+{
+public:
+    ui3Activity();
+    virtual ~ui3Activity();
+
+    /**
+     * 注册定时器
+     */
+	void registerUserTimer(int id, int time);
+	/**
+	 * 取消定时器
+	 */
+	void unregisterUserTimer(int id);
+	/**
+	 * 重置定时器
+	 */
+	void resetUserTimer(int id, int time);
+
+protected:
+    /*TAG:PROTECTED_FUNCTION*/
+    virtual const char* getAppName() const;
+    virtual void onCreate();
+    virtual void onClick(ZKBase *pBase);
+    virtual void onResume();
+    virtual void onPause();
+    virtual void onIntent(const Intent *intentPtr);
+    virtual bool onTimer(int id);
+
+    virtual void onProgressChanged(ZKSeekBar *pSeekBar, int progress);
+
+    virtual int getListItemCount(const ZKListView *pListView) const;
+    virtual void obtainListItemData(ZKListView *pListView, ZKListView::ZKListItem *pListItem, int index);
+    virtual void onItemClick(ZKListView *pListView, int index, int subItemIndex);
+
+    virtual void onSlideItemClick(ZKSlideWindow *pSlideWindow, int index);
+
+    virtual bool onTouchEvent(const MotionEvent &ev);
+
+    virtual void onTextChanged(ZKTextView *pTextView, const string &text);
+
+    void rigesterActivityTimer();
+
+    virtual void onVideoPlayerMessage(ZKVideoView *pVideoView, int msg);
+    void videoLoopPlayback(ZKVideoView *pVideoView, int msg, size_t callbackTabIndex);
+    void startVideoLoopPlayback();
+    void stopVideoLoopPlayback();
+    bool parseVideoFileList(const char *pFileListPath, std::vector<string>& mediaFileList);
+    int removeCharFromString(string& nString, char c);
+
+
+private:
+    /*TAG:PRIVATE_VARIABLE*/
+    int mVideoLoopIndex;
+    int mVideoLoopErrorCount;
+
+};
+
+#endif

+ 58 - 0
jni/base/asio.hpp

@@ -0,0 +1,58 @@
+#ifndef _FY_ASIO_H_
+#define _FY_ASIO_H_
+
+#include <poll.h>
+#include <errno.h>
+#include <string.h>
+
+namespace base {
+
+namespace asio {
+
+/**
+ * -1 error
+ * 0 timeout
+ * >0 get event
+ */
+inline int readable(int fd, int timeout_ms) {
+  int ret = -1;
+  struct pollfd pfd;
+  memset(&pfd, 0, sizeof(pfd));
+  pfd.fd = fd;
+  pfd.events = POLLIN;
+
+  // retry again for EINTR
+  for (int i = 0; i < 2; i++) {
+    ret = ::poll(&pfd, 1, timeout_ms);
+    if (-1 == ret && EINTR == errno)
+      continue;
+    break;
+  }
+  return ret;
+}
+
+/**
+ * -1 error
+ * 0 timeout
+ * >0 get event
+ */
+inline int writable(int fd, int timeout_ms) {
+  int ret = -1;
+  struct pollfd pfd;
+  memset(&pfd, 0, sizeof(pfd));
+  pfd.fd = fd;
+  pfd.events = POLLOUT;
+  // retry again for EINTR
+  for (int i = 0; i < 2; i++) {
+    ret = ::poll(&pfd, 1, timeout_ms);
+    if (-1 == ret && EINTR == errno)
+      continue;
+    break;
+  }
+  return ret;
+}
+
+} /* namespace asio */
+} /* namespace sup */
+
+#endif

+ 52 - 0
jni/base/base.hpp

@@ -0,0 +1,52 @@
+#ifndef _BASE_BASE_H_
+#define _BASE_BASE_H_
+
+#include <stddef.h>
+#include <string>
+
+
+#define CLOSE_ACTIVITY_WITH(activity_ptr) \
+  EASYUICONTEXT->closeActivity(class_name(activity_ptr).c_str())
+
+
+/**
+ * 数组长度
+ */
+template <class T>
+int array_length(T&array) {
+    return sizeof(array) / sizeof(array[0]);
+}
+
+/**
+ * 释放指针,并将指针置为空
+ */
+template <typename Ptr>
+void deleteptr(Ptr *p) {
+  if (p == NULL) {
+    return;
+  }
+  if(*p == NULL) {
+    return;
+  }
+  delete *p;
+  *p = NULL;
+}
+
+/**
+ * 通过typid获得类名,不具备通用性
+ */
+template <typename Ptr>
+std::string class_name(Ptr ptr) {
+  if (ptr == NULL) {
+    return "";
+  }
+  char* begin = (char*)typeid(*ptr).name();
+  while (isdigit(*begin)) {
+    ++begin;
+  }
+  return begin;
+}
+
+//} /* namespace base */
+
+#endif

+ 89 - 0
jni/base/crypto.hpp

@@ -0,0 +1,89 @@
+#ifndef _FY_CRYPTO_HPP_
+#define _FY_CRYPTO_HPP_
+
+#include <stdint.h>
+
+namespace fy {
+
+namespace crypto {
+
+inline uint16_t crc16(const void *data, uint64_t len) {
+  /* Table of CRC values for high-order byte */
+  const uint8_t table_crc_hi[] = {
+      0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
+      0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+      0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
+      0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+      0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
+      0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+      0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
+      0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+      0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
+      0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
+      0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
+      0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+      0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
+      0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
+      0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
+      0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+      0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
+      0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+      0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
+      0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+      0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
+      0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
+      0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
+      0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+      0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
+      0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
+  };
+
+  /* Table of CRC values for low-order byte */
+  const uint8_t table_crc_lo[] = {
+      0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
+      0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
+      0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
+      0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
+      0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
+      0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
+      0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
+      0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
+      0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
+      0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
+      0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
+      0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
+      0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
+      0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
+      0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
+      0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
+      0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
+      0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
+      0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
+      0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
+      0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
+      0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
+      0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
+      0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
+      0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
+      0x43, 0x83, 0x41, 0x81, 0x80, 0x40
+  };
+
+  uint8_t* ptr = (uint8_t*)data;
+  uint8_t crc_hi = 0xFF; /* high CRC byte initialized */
+  uint8_t crc_lo = 0xFF; /* low CRC byte initialized */
+  unsigned int i; /* will index into CRC lookup */
+
+  /* pass through message buffer */
+  while (len--) {
+      i = crc_hi ^ *ptr++; /* calculate the CRC  */
+      crc_hi = crc_lo ^ table_crc_hi[i];
+      crc_lo = table_crc_lo[i];
+  }
+
+  return (crc_hi << 8 | crc_lo);
+}
+
+} /* namespace crypto */
+} /* namespace sup */
+
+#endif /* _FY_CRYPTO_HPP_ */

+ 31 - 0
jni/base/errors.hpp

@@ -0,0 +1,31 @@
+#ifndef _FY_ERRORS_HPP_
+#define _FY_ERRORS_HPP_
+
+#include <string>
+
+namespace base {
+
+class error {
+public:
+  error(const std::string& what):what_(what.c_str()) {
+  }
+  std::string what() const {
+    return what_;
+  }
+  bool operator!=(const error& e) const {
+    return e.what_.compare(what_) != 0;
+  }
+  bool operator==(const error& e) const {
+    return e.what_.compare(what_) == 0;
+  }
+private:
+  std::string what_;
+};
+
+} /* namespace fy */
+
+
+#define nil base::error("nil")
+#define error_timeout base::error("timeout")
+
+#endif /* _FY_ERRORS_HPP_ */

+ 173 - 0
jni/base/files.hpp

@@ -0,0 +1,173 @@
+#ifndef _FY_FILES_HPP_
+#define _FY_FILES_HPP_
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <stdint.h>
+#include <string>
+#include <vector>
+#include <fstream>
+#include <sstream>
+
+#include "base/strings.hpp"
+#include "base/os.hpp"
+#include "utils/Log.h"
+
+namespace base {
+
+inline bool remove(const char* file) {
+  return unlink(file) == 0;
+}
+
+//文件存在返回真,否则假
+inline bool exists(const char* path) {
+    if (path == NULL) {
+        return false;
+    }
+    if (access(path, F_OK) == 0) {
+        return true;
+    }
+    return false;
+}
+
+inline bool write_all(const std::string& file_path, const std::string& content) {
+  std::ofstream ofs(file_path.c_str(), std::ios::binary | std::ios::out);
+  if (!ofs.is_open()) {
+    return false;
+  }
+  ofs << content;
+  ofs.flush();
+  return ofs.good();
+}
+
+inline std::string read_all(const std::string& file) {
+  std::ifstream ifs(file, std::ios::binary | std::ios::in);
+  if (!ifs.is_open()) {
+    return "";
+  }
+  std::stringstream ss;
+  ss << ifs.rdbuf();
+  return ss.str();
+}
+
+// 文件大小
+inline int64_t size_of(const std::string &file) {
+    long filesize = -1;
+    struct stat statbuff;
+    if(stat(file.c_str(), &statbuff) < 0){
+        return filesize;
+    } else {
+        filesize = statbuff.st_size;
+    }
+    return filesize;
+}
+
+inline int copy_file(const std::string &source,
+    const std::string &target,
+    void *user_data,
+    void (*progress)(const void* user_data, int64_t now, int64_t all)) {
+
+  if (!exists(source.c_str())) {
+    LOGE("%s file not exist", source.c_str());
+    return -1;
+  }
+  FILE* in = fopen(source.c_str(), "rb");
+  if (in == NULL) {
+    LOGE("failed to open file %s", source.c_str());
+    return -2;
+  }
+  FILE* out = fopen(target.c_str(), "wb");
+  if (out == NULL) {
+    LOGE("failed to create file %s", target.c_str());
+    return -3;
+  }
+
+  int64_t all = size_of(source.c_str());
+  if (all < 0) {
+    LOGE("unknown file size");
+    return -4;
+  }
+  int64_t now = 0;
+  char buf[4096] = {0};
+  int read_ret = 0;
+  int write_ret = 0;
+
+  if (progress) {
+    progress(user_data, now, all);
+  }
+  while (!feof(in)) {
+    read_ret = fread(buf, 1, int(sizeof(buf)), in);
+    if (read_ret < 0) {
+      fclose(in);
+      fclose(out);
+      LOGE("failed to read %s", source.c_str());
+      return -5;
+    }
+    write_ret = fwrite(buf, 1, read_ret, out);
+    if (write_ret != read_ret) {
+      fclose(in);
+      fclose(out);
+      LOGE("failed to write %s", target.c_str());
+      return -6;
+    }
+    now += write_ret;
+    if (progress) {
+      progress(user_data, now, all);
+    }
+  }
+  if (now != all) {
+    LOGE("copy_file failed");
+    return -7;
+  }
+  fflush(out);
+  fclose(in);
+  fclose(out);
+  return 0;
+}
+
+inline bool _match(const std::string &str, const std::string &pattern) {
+  if (pattern.compare("*") == 0) {
+    return true;
+  }
+  std::string::size_type pos = pattern.find("*"); //*.mp3
+  if (pos == 0) {
+    return endswith(str, pattern.substr(1, pattern.size() - 1));
+  } else if (pos == (pattern.size() - 1)) {
+    return startswith(str, pattern.substr(0, pattern.size() - 1));
+  }
+  return true;
+}
+
+inline std::vector<std::string> list(const std::string &path, const std::string &pattern, bool recursive) {
+  std::vector<std::string> ret;
+  DIR *d;
+  struct dirent *entry;
+  if ((d = opendir(path.c_str())) == NULL) {
+    //can't open dir
+    return ret;
+  }
+
+  while ((entry = readdir(d)) != NULL) {
+    if ((strcmp(".", entry->d_name) == 0) || (strcmp("..", entry->d_name) == 0)) {
+      continue;
+    }
+
+    if ((entry->d_type == DT_DIR) && recursive) {
+      std::vector<std::string> sub = list(base::path::join(path, entry->d_name), pattern, recursive);
+      ret.insert(ret.end(), sub.begin(), sub.end());
+    } else {
+      if (!_match(entry->d_name, pattern)) {
+        continue;
+      }
+      ret.push_back(base::path::join(path, entry->d_name));
+    }
+  }
+  closedir(d);
+  return ret;
+}
+
+} /* namespace base */
+
+#endif /* _FY_FILES_HPP_ */

+ 296 - 0
jni/base/handler.hpp

@@ -0,0 +1,296 @@
+#ifndef _FY_HANDLER_HPP_
+#define _FY_HANDLER_HPP_
+
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/eventfd.h>
+#include <sys/epoll.h>
+#include <pthread.h>
+#include <list>
+
+#include <system/Thread.h>
+#include "time.hpp"
+#include "utils/Log.h"
+
+
+#define TEMP_FAILURE_RETRY2(exp) ({         \
+    int _rc;                      \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+
+
+namespace base {
+
+template <typename T = void*>
+class handler;
+
+template <typename T = void*>
+class message {
+public:
+  message(int what): what(what),when_(0),period_(0),runable_(NULL),user_data_(NULL) {
+  }
+  message(int what, T obj): what(what),obj(obj),when_(0),period_(0),runable_(NULL),user_data_(NULL) {
+  }
+
+  int what;
+  T obj;
+private:
+  int64_t when_;
+  int64_t period_;
+  void* runable_;
+  const void* user_data_;
+  friend class base::handler<T>;
+};
+
+template <typename T>
+class handler {
+public:
+  typedef void (*func_message_handler)(const message<T>* msg, const void* user_data);
+  typedef void (*func_runable)(const void* user_data);
+
+public:
+  explicit handler(func_message_handler func_handler, const void* user_data)
+  :looper_(this), user_data_((void*)user_data) {
+    initialize();
+    message_handler_ = func_handler;
+  }
+
+  explicit handler():looper_(this), user_data_(NULL) {
+    initialize();
+  }
+
+  ~handler() {
+    exit_ = true;
+    wake();
+    looper_.requestExitAndWait();
+    close(epoll_fd_);
+    close(wake_event_fd_);
+    message_queue_.clear();
+  }
+
+  /**
+   * typedef void (*func_message_handler)(const message* msg, const void* user_data);
+   */
+  void set_message_handler(func_message_handler func, const void* user_data) {
+    message_handler_ = func;
+    user_data_ = (void*)user_data;
+  }
+
+  void send_message(int what) {
+    message<T> msg(what);
+    enqueue_with_lock(msg);
+  }
+
+  void send_message(message<T> &msg) {
+    enqueue_with_lock(msg);
+  }
+
+  void send_message_delayed(int what, int delay_millis) {
+    message<T> msg(what);
+    msg.when_ = base::time::uptime() + delay_millis;
+    enqueue_with_lock(msg);
+  }
+
+  void send_message_delayed(message<T> &msg, int delay_millis) {
+    msg.when_ = base::time::uptime() + delay_millis;
+    enqueue_with_lock(msg);
+  }
+
+  void post(func_runable runable, const void* user_data) {
+    message<T> msg(0);
+    msg.runable_ = (void*)runable;
+    msg.user_data_ = user_data;
+    enqueue_with_lock(msg);
+  }
+
+  /**
+   * typedef void (*func_runable)(const void* user_data);
+   */
+  void post_delayed(func_runable runable, const void* user_data, int delay_millis) {
+    message<T> msg(0);
+    msg.runable_ = (void*)runable;
+    msg.user_data_ = user_data;
+    msg.when_ = base::time::uptime() + delay_millis;
+    enqueue_with_lock(msg);
+  }
+
+  void schedule(int what, int period_millis, int delay_millis) {
+    message<T> msg(what);
+    msg.when_ = base::time::uptime() + delay_millis;
+    msg.period_ = period_millis;
+    enqueue_with_lock(msg);
+  }
+
+  void schedule(message<T> &msg, int period_millis, int delay_millis) {
+    msg.when_ = base::time::uptime() + delay_millis;
+    msg.period_ = period_millis;
+    enqueue_with_lock(msg);
+  }
+
+  void remove_messages(int what) {
+    Mutex::Autolock lock(mutex_);
+    typename std::list<message<T> >::iterator it;
+    for (it = message_queue_.begin(); it != message_queue_.end(); ) {
+      if (it->what == what) {
+        it = message_queue_.erase(it);
+      } else {
+        ++it;
+      }
+    }
+  }
+
+  typedef bool (*remove_filter)(const message<T>& msg, void* user_data);
+  void remove_messages(remove_filter filter, void* user_data) {
+    Mutex::Autolock lock(mutex_);
+    typename std::list<message<T> >::iterator it;
+    for (it = message_queue_.begin(); it != message_queue_.end(); ) {
+      if (filter(*it, user_data)) {
+        it = message_queue_.erase(it);
+      } else {
+        ++it;
+      }
+    }
+  }
+
+  bool has_message(int what) {
+    Mutex::Autolock lock(mutex_);
+    typename std::list<message<T> >::iterator it;
+    for (it = message_queue_.begin(); it != message_queue_.end(); ) {
+      if (it->what == what) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+
+private:
+  void initialize() {
+    init_ = false;
+    wake_event_fd_ = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
+    message_handler_ = NULL;
+    const int kEpollSizeHint  = 1;
+    epoll_fd_ = epoll_create(kEpollSizeHint);
+    if (epoll_fd_ < 0) {
+      LOGE("%s %d epoll_create failed", __func__, __LINE__);
+      return;
+    }
+    struct epoll_event eventItem;
+     memset(&eventItem, 0, sizeof(epoll_event));
+     eventItem.events = EPOLLIN | EPOLLET;
+     eventItem.data.fd = wake_event_fd_;
+     int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, wake_event_fd_, &eventItem);
+     if (result < 0) {
+       LOGE("%s %d epoll_ctl failed", __func__, __LINE__);
+       return;
+     }
+    exit_ = false;
+    init_ = true;
+    looper_.run("sup.handler");
+  }
+
+  void loop() {
+    while (!exit_) {
+      if (message_queue_.empty()) {
+        wait(10 * 1000);
+        awoken();
+        continue;
+      }
+
+      mutex_.lock();
+      base::message<T> front = message_queue_.front();
+      int64_t now = base::time::uptime();
+
+      if (front.when_ <= now) {
+        message_queue_.pop_front();
+        if (front.period_ > 0) {
+          front.when_ = base::time::uptime() + front.period_;
+          enqueue(front);
+        }
+        mutex_.unlock();
+        if (front.runable_) {
+          ((func_runable)front.runable_)(front.user_data_);
+        } else if (message_handler_) {
+          message_handler_(&front, user_data_);
+        }
+        continue;
+      }
+      mutex_.unlock();
+      wait(front.when_ - now);
+      awoken();
+    }
+  }
+
+  void wait(int timeout_millis) {
+    const int kEpollMaxEvents = 1;
+    struct epoll_event eventItems[kEpollMaxEvents];
+    int event_count = epoll_wait(epoll_fd_, eventItems, kEpollMaxEvents, timeout_millis);
+    if (event_count < 0) {
+      LOGE("%s %d epoll_wait failed", __func__, __LINE__);
+    }
+  }
+
+  void wake() {
+    uint64_t inc = 1;
+    ssize_t nWrite = TEMP_FAILURE_RETRY2(write(wake_event_fd_, &inc, sizeof(uint64_t)));
+    if (nWrite != sizeof(uint64_t)) {
+        if (errno != EAGAIN) {
+            LOGE("Could not write wake signal, errno=%d", errno);
+        }
+    }
+  }
+
+  void awoken() {
+    uint64_t counter = 0;
+    TEMP_FAILURE_RETRY2(read(wake_event_fd_, &counter, sizeof(uint64_t)));
+  }
+
+  void enqueue(const message<T> &msg) {
+    typename std::list<message<T> >::iterator it;
+    for (it = message_queue_.begin(); it != message_queue_.end(); ++it) {
+      if (msg.when_ < it->when_) {
+        it = message_queue_.insert(it, msg);
+        if (it == message_queue_.begin()) {
+          wake();
+        }
+        return;
+      }
+    }
+    message_queue_.push_back(msg);
+    if (message_queue_.size() == 1) {
+      wake();
+    }
+  }
+
+  void enqueue_with_lock(const message<T> &msg) {
+    Mutex::Autolock lock(mutex_);
+    enqueue(msg);
+  }
+
+  class Looper : public Thread {
+  public:
+    Looper(handler<T> *handler):handler_(handler){}
+    virtual bool threadLoop() {
+      handler_->loop();
+      return false;
+    }
+    handler<T>* handler_;
+  };
+
+  Looper looper_;
+  std::list<message<T> > message_queue_;
+  func_message_handler message_handler_;
+  void* user_data_;
+  int wake_event_fd_;
+  int epoll_fd_;
+  bool init_;
+  volatile bool exit_;
+  Mutex mutex_;
+};
+
+} /* namespace sup */
+
+#endif /* _FY_HANDLER_HPP_ */

+ 638 - 0
jni/base/http_client.cpp

@@ -0,0 +1,638 @@
+/*
+ * client.cpp
+ *
+ *  Created on: 2021年8月16日
+ *      Author: pengzc
+ */
+
+#include "http_client.h"
+#include <string.h>
+#include <algorithm>
+#include <signal.h>
+#include <unistd.h>
+#include <fstream>
+#include "utils/Log.h"
+#include "manager/ConfigManager.h"
+
+namespace {
+class CURLGlobal {
+public:
+  CURLGlobal() {
+    CURLcode res = curl_global_init(CURL_GLOBAL_ALL);
+    if (res != CURLE_OK) {
+      LOGE("CURL curl_global_init failed");
+    }
+
+    //忽略SIGPIPE
+    struct sigaction sa;
+    sa.sa_handler = SIG_IGN;
+    sa.sa_flags = 0;
+    if (sigemptyset(&sa.sa_mask) == -1 ||
+        sigaction(SIGPIPE, &sa, 0) == -1) {
+      LOGE("failed ignore SIGPIPE");
+    }
+  }
+
+  ~ CURLGlobal() {
+    curl_global_cleanup();
+  }
+};
+
+} /* anonymous namespace */
+
+namespace base {
+
+HttpClient::HttpClient() {
+  static CURLGlobal global;
+  curl_ = curl_easy_init();
+  if (curl_ == NULL) {
+    LOGE("curl_easy_init failed");
+  }
+
+  timeout_ = 0;
+  connection_timeout_ = 0;
+
+  ssl_verify_ = true;
+  aborted_ = false;
+
+  low_speed_limit_.bytes = 0;
+  low_speed_limit_.seconds = 0;
+
+  debug_ = false;
+
+  ca_info_file_path_ = CONFIGMANAGER->getResFilePath("cacert.pem");
+
+}
+
+HttpClient::~HttpClient() {
+  if (curl_) {
+    curl_easy_cleanup(curl_);
+  }
+}
+
+HttpResponse HttpClient::Do(const HttpRequest& request) {
+  return Do(request, "", NULL);
+}
+
+HttpResponse HttpClient::Do(const HttpRequest& request, ProgressCallback progress) {
+  return Do(request, "", progress);
+}
+
+HttpResponse HttpClient::Do(const HttpRequest& request, const std::string& save_path,
+    ProgressCallback progress) {
+  Mutex::Autolock lock(do_mutex_);
+
+  if (curl_ == NULL) {
+    return HttpResponse();
+  }
+  curl_easy_reset(curl_);
+
+  aborted_ = false;
+  HttpResponse response;
+  std::string url = request.url_;
+  std::string header_string;
+  CURLcode res = CURLE_OK;
+
+  /** set query URL */
+  curl_easy_setopt(curl_, CURLOPT_URL, url.c_str());
+
+#if 0
+  if (request.method_.compare("download") != 0) {
+      /** set callback function */
+      curl_easy_setopt(this->curl_, CURLOPT_WRITEFUNCTION,
+                       Helpers::write_callback);
+      /** set data object to pass to callback function */
+      curl_easy_setopt(this->curl_, CURLOPT_WRITEDATA, &ret);
+  } else
+#endif
+
+  /** set data callback */
+  curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION,
+      curl_response_write_callback);
+  /** set data object to pass to callback function */
+  curl_easy_setopt(curl_, CURLOPT_WRITEDATA, &response);
+
+  if (request.method_.compare("GET") == 0) {
+
+  } else if (request.method_.compare("POST") == 0) {
+    /** Now specify we want to POST data */
+    curl_easy_setopt(this->curl_, CURLOPT_POST, 1L);
+
+    if (!request.body_.empty()) {
+      /** set post fields */
+      curl_easy_setopt(this->curl_, CURLOPT_POSTFIELDS,
+          request.body_.c_str());
+      curl_easy_setopt(this->curl_, CURLOPT_POSTFIELDSIZE,
+          request.body_.size());
+    }
+
+    if (!request.multiparts_.empty()) {
+      struct curl_httppost *formpost = NULL;
+      struct curl_httppost *lastptr  = NULL;
+      for (auto it = request.multiparts_.begin(); it != request.multiparts_.end(); ++it) {
+        curl_formadd(&formpost, &lastptr,
+            CURLFORM_PTRNAME, it->first.c_str(),
+            CURLFORM_PTRCONTENTS, it->second.data(),
+            CURLFORM_CONTENTSLENGTH, it->second.length(),
+            CURLFORM_END);
+      }
+
+      /** Now specify we want to POST data */
+      curl_easy_setopt(this->curl_, CURLOPT_HTTPPOST, formpost);
+    }
+  }
+
+
+#if 0
+  /** set the header callback function */
+  curl_easy_setopt(this->curl_, CURLOPT_HEADERFUNCTION, header_callback);
+  /** callback object for headers */
+  curl_easy_setopt(this->curl_, CURLOPT_HEADERDATA, &response);
+#endif
+
+  /** set http headers */
+  curl_slist* header_list = NULL;
+  for (HttpRequest::HeaderFields::const_iterator it = request.header.begin();
+      it != request.header.end(); ++it) {
+    header_string = it->first;
+    header_string += ": ";
+    header_string += it->second;
+    curl_slist* temp = curl_slist_append(header_list, header_string.c_str());
+    if (temp == NULL) {
+      LOGE("curl_slist_append failed");
+      curl_slist_free_all(header_list);
+      header_list = NULL;
+      break;
+    }
+    header_list = temp;
+  }
+  if (header_list != NULL) {
+    curl_easy_setopt(curl_, CURLOPT_HTTPHEADER, header_list);
+  }
+
+  progress_callback_ = progress;
+  curl_easy_setopt(curl_, CURLOPT_XFERINFOFUNCTION,
+      HttpClient::curl_progress_callback);
+  curl_easy_setopt(curl_, CURLOPT_XFERINFODATA, this);
+  curl_easy_setopt(curl_, CURLOPT_NOPROGRESS, 0);
+
+  if ((low_speed_limit_.bytes > 0) && (low_speed_limit_.seconds > 0)) {
+    curl_easy_setopt(curl_, CURLOPT_LOW_SPEED_LIMIT, low_speed_limit_.bytes);
+    curl_easy_setopt(curl_, CURLOPT_LOW_SPEED_TIME, low_speed_limit_.seconds);
+  }
+
+#if 0
+  // set basic auth if configured
+  if (this->basicAuth.username.length() > 0) {
+    std::string authString = std::string(this->basicAuth.username + ":" +
+                                         this->basicAuth.password);
+    curl_easy_setopt(this->curl_, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
+    curl_easy_setopt(this->curl_, CURLOPT_USERPWD, authString.c_str());
+  }
+#endif
+
+#if 0
+  /** set user agent */
+  curl_easy_setopt(this->curl_, CURLOPT_USERAGENT,
+                   this->GetUserAgent().c_str());
+#endif
+
+  // set timeout
+  if (connection_timeout_ > 0) {
+    curl_easy_setopt(this->curl_, CURLOPT_CONNECTTIMEOUT_MS,
+        connection_timeout_);
+    // dont want to get a sig alarm on timeout
+    curl_easy_setopt(curl_, CURLOPT_NOSIGNAL, 1L);
+  }
+  if (timeout_ > 0) {
+    curl_easy_setopt(this->curl_, CURLOPT_TIMEOUT_MS, timeout_);
+    // dont want to get a sig alarm on timeout
+    curl_easy_setopt(curl_, CURLOPT_NOSIGNAL, 1L);
+  }
+
+  //允许重定向
+  curl_easy_setopt(this->curl_, CURLOPT_FOLLOWLOCATION, 1L);
+  curl_easy_setopt(this->curl_, CURLOPT_MAXREDIRS, static_cast<int64_t>(9));
+
+  //多线程下使用超时禁用SIGNAL
+  curl_easy_setopt(curl_, CURLOPT_NOSIGNAL, 1L);
+
+  //指定DNS解析规范为IPV4
+  curl_easy_setopt(curl_, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+
+    //指定DNS
+  curl_easy_setopt(curl_, CURLOPT_DNS_SERVERS,
+      "1.2.4.8,210.2.4.8,114.114.114.114,119.29.29.29");
+
+  // if provided, supply CA path
+  if (!this->ca_info_file_path_.empty()) {
+    curl_easy_setopt(curl_, CURLOPT_CAINFO, ca_info_file_path_.c_str());
+  }
+
+  if (!ssl_verify_) {
+    curl_easy_setopt(curl_, CURLOPT_SSL_VERIFYPEER, 0L);
+    curl_easy_setopt(curl_, CURLOPT_SSL_VERIFYHOST, 0L);
+  }
+
+  if (debug_) {
+    curl_easy_setopt(curl_, CURLOPT_DEBUGFUNCTION, debug_trace);
+    /* the DEBUGFUNCTION has no effect until we enable VERBOSE */
+    curl_easy_setopt(curl_, CURLOPT_VERBOSE, 1L);
+  }
+
+  if (!save_path.empty()) {
+    response.dst_file_ = fopen(save_path.c_str(), "wb");
+    if (response.dst_file_ == NULL) {
+      LOGE("open %s failed, %s", save_path.c_str(), strerror(errno));
+      response.error_code_ = errno;
+      response.error_message_ = strerror(errno);
+      return response;
+    }
+  }
+
+#if 0
+  // set cert file path
+  if (!this->certPath.empty()) {
+    curl_easy_setopt(this->curl_, CURLOPT_SSLCERT,
+                     this->certPath.c_str());
+  }
+
+  // set cert type
+  if (!this->certType.empty()) {
+    curl_easy_setopt(this->curl_, CURLOPT_SSLCERTTYPE,
+                     this->certType.c_str());
+  }
+  // set key file path
+  if (!this->keyPath.empty()) {
+    curl_easy_setopt(this->curl_, CURLOPT_SSLKEY,
+                     this->keyPath.c_str());
+  }
+  // set key password
+  if (!this->keyPassword.empty()) {
+    curl_easy_setopt(this->curl_, CURLOPT_KEYPASSWD,
+                     this->keyPassword.c_str());
+  }
+
+  // set web proxy address
+  if (!this->uriProxy.empty()) {
+    curl_easy_setopt(this->curl_, CURLOPT_PROXY,
+                     uriProxy.c_str());
+    curl_easy_setopt(this->curl_, CURLOPT_HTTPPROXYTUNNEL,
+                     1L);
+  }
+#endif
+
+  char error_buffer[CURL_ERROR_SIZE] = { 0 };
+  curl_easy_setopt(curl_, CURLOPT_ERRORBUFFER, error_buffer);
+
+  res = curl_easy_perform(curl_);
+  if (res != CURLE_OK) {
+    response.error_message_ = error_buffer;
+    response.error_code_ = res;
+  } else {
+    int64_t http_code = 0;
+    curl_easy_getinfo(curl_, CURLINFO_RESPONSE_CODE, &http_code);
+    response.status_code_ = static_cast<int>(http_code);
+  }
+
+  curl_easy_getinfo(curl_, CURLINFO_TOTAL_TIME,
+                    &response.total_time);
+  curl_easy_getinfo(this->curl_, CURLINFO_NAMELOOKUP_TIME,
+                    &response.name_lookup_time);
+  curl_easy_getinfo(this->curl_, CURLINFO_CONNECT_TIME,
+                    &response.connect_time);
+  curl_easy_getinfo(this->curl_, CURLINFO_APPCONNECT_TIME,
+                    &response.app_connect_time);
+  curl_easy_getinfo(this->curl_, CURLINFO_PRETRANSFER_TIME,
+                    &response.pre_transfer_time);
+  curl_easy_getinfo(this->curl_, CURLINFO_STARTTRANSFER_TIME,
+                    &response.start_transfer_time);
+  curl_easy_getinfo(this->curl_, CURLINFO_REDIRECT_TIME,
+                    &response.redirect_time);
+  curl_easy_getinfo(this->curl_, CURLINFO_REDIRECT_COUNT,
+                    &response.redirect_count);
+
+  if (response.dst_file_ != NULL) {
+    fflush(response.dst_file_);
+    fclose(response.dst_file_);
+    sync();
+    response.dst_file_ = NULL;
+  }
+
+  // free header list
+  curl_slist_free_all(header_list);
+  return response;
+}
+
+/**
+ * @brief set custom Certificate Authority (CA) path
+ *
+ * @param caInfoFilePath - The path to a file holding the certificates used to
+ * verify the peer with. See CURLOPT_CAINFO
+ *
+ */
+void
+HttpClient::SetCAInfoFilePath(const std::string& caInfoFilePath) {
+  this->ca_info_file_path_ = caInfoFilePath;
+}
+
+#if 0
+/**
+ * @brief set username and password for basic auth
+ *
+ * @param username
+ * @param password
+ *
+ */
+void
+HttpClient::SetBasicAuth(const std::string& username,
+                                     const std::string& password) {
+  this->basicAuth.username = username;
+  this->basicAuth.password = password;
+}
+
+#endif
+
+/**
+ * @brief set certificate path
+ *
+ * @param path to certificate file
+ *
+ */
+//void
+//HttpClient::SetCertPath(const std::string& cert) {
+//  this->certPath = cert;
+//}
+
+/**
+ * @brief set certificate type
+ *
+ * @param certificate type (e.g. "PEM" or "DER")
+ *
+ */
+//void
+//HttpClient::SetCertType(const std::string& certType) {
+//  this->certType = certType;
+//}
+
+/**
+ * @brief set key path
+ *
+ * @param path to key file
+ *
+ */
+//void
+//HttpClient::SetKeyPath(const std::string& keyPath) {
+//  this->keyPath = keyPath;
+//}
+
+/**
+ * @brief set key password
+ *
+ * @param key password
+ *
+ */
+//void
+//HttpClient::SetKeyPassword(const std::string& keyPassword) {
+//  this->keyPassword = keyPassword;
+//}
+
+/**
+ * @brief set HTTP proxy address and port
+ *
+ * @param proxy address with port number
+ *
+ */
+//void
+//HttpClient::SetProxy(const std::string& uriProxy) {
+//  std::string uriProxyUpper = uriProxy;
+//  // check if the provided address is prefixed with "http"
+//  std::transform(uriProxyUpper.begin(), uriProxyUpper.end(),
+//    uriProxyUpper.begin(), ::toupper);
+//
+//  if ((uriProxy.length() > 0) && (uriProxyUpper.compare(0, 4, "HTTP") != 0)) {
+//    this->uriProxy = "http://" + uriProxy;
+//  } else {
+//    this->uriProxy = uriProxy;
+//  }
+//}
+
+/**
+ * @brief helper function to get called from the actual request methods to
+ * prepare the curlHandle for transfer with generic options, perform the
+ * request and record some stats from the last request and then reset the
+ * handle with curl_easy_reset to its default state. This will keep things
+ * like connections and session ID intact but makes sure you can change
+ * parameters on the object for another request.
+ *
+ * @param uri URI to query
+ * @param ret Reference to the Response struct that should be filled
+ *
+ * @return 0 on success and 1 on error
+ */
+//Response
+//HttpClient::performCurlRequest(const std::string& uri, const std::string method_type) {}
+
+/**
+ * @brief HTTP GET method
+ *
+ * @param url to query
+ *
+ * @return response struct
+ */
+//Response
+//HttpClient::get(const std::string& url) {
+//  return this->performCurlRequest(url);
+//}
+/**
+ * @brief HTTP POST method
+ *
+ * @param url to query
+ * @param data HTTP POST body
+ *
+ * @return response struct
+ */
+//Response
+//HttpClient::post(const std::string& url,
+//                             const std::string& data) {
+//  /** Now specify we want to POST data */
+//  curl_easy_setopt(this->curlHandle, CURLOPT_POST, 1L);
+//  /** set post fields */
+//  curl_easy_setopt(this->curlHandle, CURLOPT_POSTFIELDS, data.c_str());
+//  curl_easy_setopt(this->curlHandle, CURLOPT_POSTFIELDSIZE, data.size());
+//
+//  return this->performCurlRequest(url);
+//}
+
+//Response
+//HttpClient::post(const std::string& url,
+//    const std::map<std::string, std::string>& form_data) {
+//
+//  struct curl_httppost *formpost = 0;
+//  struct curl_httppost *lastptr  = 0;
+//  for (auto it = form_data.begin(); it != form_data.end(); ++it) {
+//    curl_formadd(&formpost, &lastptr,
+//        CURLFORM_PTRNAME, it->first.c_str(),
+//        CURLFORM_PTRCONTENTS, it->second.data(),
+//        CURLFORM_CONTENTSLENGTH, it->second.length(),
+//        CURLFORM_END);
+//  }
+//
+//  /** Now specify we want to POST data */
+//  curl_easy_setopt(this->curlHandle, CURLOPT_HTTPPOST, formpost);
+//
+//  Response response = this->performCurlRequest(url);
+//  curl_formfree(formpost);
+//  return response;
+//}
+
+HttpClient& HttpClient::SetConnectionTimeout(int ms) {
+  connection_timeout_ = ms;
+  return *this;
+}
+
+HttpClient& HttpClient::SetTimeout(int ms) {
+  timeout_ = ms;
+  return *this;
+}
+
+
+// trim from start
+static inline std::string &ltrim(std::string &s) {  // NOLINT
+  s.erase(s.begin(), std::find_if(s.begin(), s.end(),
+        std::not1(std::ptr_fun<int, int>(std::isspace))));
+  return s;
+}
+
+// trim from end
+static inline std::string &rtrim(std::string &s) { // NOLINT
+  s.erase(std::find_if(s.rbegin(), s.rend(),
+        std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
+  return s;
+}
+
+// trim from both ends
+static inline std::string &trim(std::string &s) {  // NOLINT
+  return ltrim(rtrim(s));
+}
+
+size_t HttpClient::curl_response_write_callback(void* data, size_t size,
+    size_t nmemb, void* userdata) {
+  HttpResponse* response = (HttpResponse*) userdata;
+  if (response->dst_file_ == NULL) {
+    response->body_.append(reinterpret_cast<char*>(data), size * nmemb);
+    return size * nmemb;
+  }
+  return fwrite(reinterpret_cast<char*>(data), 1, size * nmemb,
+      response->dst_file_);
+}
+
+size_t HttpClient::header_callback(void *data, size_t size,
+                                            size_t nmemb, void *userdata) {
+
+  HttpResponse* r = (HttpResponse*)userdata;
+  std::string header(reinterpret_cast<char*>(data), size*nmemb);
+
+  //LOGD("Header Callback  [%s]", trim(header).c_str());
+
+  size_t seperator = header.find_first_of(':');
+  if ( std::string::npos == seperator ) {
+    // roll with non seperated headers...
+    trim(header);
+    if (0 == header.length()) {
+      return (size * nmemb);  // blank line;
+    }
+    r->header_[header] = "present";
+  } else {
+    std::string key = header.substr(0, seperator);
+    trim(key);
+    std::string value = header.substr(seperator + 1);
+    trim(value);
+
+    auto it = r->header_.find(key);
+    if (it == r->header_.end()) {
+      //LOGD("It's new Head Field %s", key.c_str());
+      r->header_[key] = value;
+    } else {
+      //LOGD("Duplicate Head Field %s", key.c_str());
+    }
+    //LOGD("headers size %d", r->header_.size());
+//    LOGD("HHHHHHHHHHHHHead%p %s %s", r,  key.c_str(), value.c_str());
+  }
+  return (size * nmemb);
+}
+
+void HttpClient::SetSSLVerify(bool verify) {
+  ssl_verify_ = verify;
+}
+
+void HttpClient::Abort() {
+  aborted_ = true;
+  Mutex::Autolock lock(do_mutex_);
+}
+
+int HttpClient::curl_progress_callback(void* data, curl_off_t dltotal,
+    curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) {
+  HttpClient* client = (HttpClient*)data;
+
+  if (client->aborted_) {
+    return -1;
+  }
+  if (client->progress_callback_ != NULL) {
+    return client->progress_callback_(dltotal, dlnow, ultotal, ulnow);
+  }
+  return 0;
+}
+
+static void dump(const char *text, unsigned char *ptr, size_t size) {
+  LOGD("%s, %10.10ld bytes (0x%8.8lx)\n",
+          text, (long)size, (long)size);
+}
+
+int HttpClient::debug_trace(CURL *handle, curl_infotype type, char *data, ::size_t size,
+    void *userp) {
+  const char *text;
+   (void)handle; /* prevent compiler warning */
+   (void)userp;
+
+   switch (type) {
+   case CURLINFO_TEXT:
+     LOGD("== Info: %s", data);
+   default: /* in case a new one is introduced to shock us */
+     return 0;
+
+   case CURLINFO_HEADER_OUT:
+     text = "=> Send header";
+     break;
+   case CURLINFO_DATA_OUT:
+     text = "=> Send data";
+     break;
+   case CURLINFO_SSL_DATA_OUT:
+     text = "=> Send SSL data";
+     break;
+   case CURLINFO_HEADER_IN:
+     text = "<= Recv header";
+     break;
+   case CURLINFO_DATA_IN:
+     text = "<= Recv data";
+     break;
+   case CURLINFO_SSL_DATA_IN:
+     text = "<= Recv SSL data";
+     break;
+   }
+
+   dump(text, (unsigned char *)data, size);
+   return 0;
+}
+
+HttpClient& HttpClient::SetLowSpeedLimit(int bytes, int seconds) {
+  low_speed_limit_.bytes = bytes;
+  low_speed_limit_.seconds = seconds;
+  return *this;
+}
+
+void HttpClient::SetDebug(bool debug) {
+  debug_ = debug;
+}
+
+} /* namespace base */

+ 92 - 0
jni/base/http_client.h

@@ -0,0 +1,92 @@
+/*
+ * client.h
+ *
+ *  Created on: 2021年8月16日
+ *      Author: pengzc
+ */
+
+#ifndef JNI_HTTP_CLIENT_H_
+#define JNI_HTTP_CLIENT_H_
+
+#include <cstdlib>
+#include <cctype>
+#include <string>
+#include "http_request.h"
+#include "http_response.h"
+#include "curl/curl.h"
+#include <system/Thread.h>
+#include <functional>
+
+namespace base {
+
+class HttpClient {
+public:
+  HttpClient();
+  virtual ~HttpClient();
+
+  typedef std::function<int (int64_t dltotal,
+      int64_t dlnow, int64_t ultotal, int64_t ulnow)> ProgressCallback;
+
+  HttpResponse Do(const HttpRequest& request);
+  HttpResponse Do(const HttpRequest& request, ProgressCallback progress);
+  HttpResponse Do(const HttpRequest& request, const std::string& save_path,
+      ProgressCallback progress);
+
+  /**
+   * 连接超时
+   */
+  HttpClient& SetConnectionTimeout(int ms);
+  /**
+   * 总超时
+   */
+  HttpClient& SetTimeout(int ms);
+
+  /**
+   * 速度低于bytes/s,持续seconds,中止执行
+   */
+  HttpClient& SetLowSpeedLimit(int bytes, int seconds);
+
+  void SetCAInfoFilePath(const std::string& caInfoFilePath);
+
+  void SetSSLVerify(bool verify);
+
+  /**
+   * 终止请求
+   */
+  void Abort();
+
+  void SetDebug(bool debug);
+
+private:
+  static ::size_t curl_response_write_callback(void *data, ::size_t size,
+      ::size_t nmemb, void *userdata);
+  static ::size_t header_callback(void *data, ::size_t size, ::size_t nmemb,
+      void *userdata);
+
+  static int curl_progress_callback(void *clientp, curl_off_t dltotal,
+      curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow);
+
+  static int debug_trace(CURL *handle, curl_infotype type, char *data, ::size_t size,
+      void *userp);
+
+private:
+  CURL* curl_;
+  int connection_timeout_;
+  int timeout_;
+  std::string ca_info_file_path_;
+  bool ssl_verify_;
+  bool aborted_;
+  ProgressCallback progress_callback_;
+  Mutex do_mutex_;
+
+  struct {
+    int bytes;
+    int seconds;
+  }low_speed_limit_;
+
+  bool debug_;
+};
+
+} /* namespace base */
+
+#endif /* JNI_HTTP_CLIENT_H_ */

+ 41 - 0
jni/base/http_request.cpp

@@ -0,0 +1,41 @@
+/*
+ * request.cpp
+ *
+ *  Created on: 2021年8月16日
+ *      Author: pengzc
+ */
+
+#include "http_request.h"
+
+namespace base {
+
+HttpRequest::HttpRequest(const std::string& method, const std::string& url,
+    const std::string& body) {
+  method_ = method;
+  url_ = url;
+  body_ = body;
+}
+
+HttpRequest::~HttpRequest() {
+}
+
+HttpRequest& HttpRequest::AppendHeader(const std::string& key,
+    const std::string& value) {
+  header[key] = value;
+  return *this;
+}
+
+HttpRequest& HttpRequest::ContentType(const std::string& content_type) {
+  header["Content-Type"] = content_type;
+  return *this;
+}
+
+HttpRequest& HttpRequest::AppendPart(const std::string& name,
+    const std::string& value) {
+  multiparts_[name] = value;
+  return *this;
+}
+
+} /* namespace base */
+
+

+ 96 - 0
jni/base/http_request.h

@@ -0,0 +1,96 @@
+/*
+ * request.h
+ *
+ *  Created on: 2021年8月16日
+ *      Author: pengzc
+ */
+
+#ifndef JNI_HTTP_REQUEST_H_
+#define JNI_HTTP_REQUEST_H_
+
+#include <string>
+#include <map>
+
+namespace base {
+
+class HttpClient;
+
+class HttpRequest {
+public:
+  /**
+   * GET / POST
+   */
+  HttpRequest(const std::string& method, const std::string& url,
+      const std::string& body);
+  virtual ~HttpRequest();
+
+public:
+   typedef struct {
+       double totalTime;
+       double nameLookupTime;
+       double connectTime;
+       double appConnectTime;
+       double preTransferTime;
+       double startTransferTime;
+       double redirectTime;
+       int redirectCount;
+     } RequestInfo;
+
+   typedef struct {
+     std::string baseUrl;
+     int timeout;
+     bool followRedirects;
+     int maxRedirects;
+     bool noSignal;
+     struct {
+       std::string username;
+       std::string password;
+     } basicAuth;
+
+     std::string certPath;
+     std::string certType;
+     std::string keyPath;
+     std::string keyPassword;
+     std::string customUserAgent;
+     std::string uriProxy;
+     RequestInfo lastRequest;
+   } Info;
+
+   typedef std::map<std::string, std::string> Multiparts;
+
+   // Instance configuration methods
+   // configure basic auth
+   void SetBasicAuth(const std::string& username,
+                     const std::string& password);
+
+   // append additional headers
+   HttpRequest& AppendHeader(const std::string& key,
+                     const std::string& value);
+   //Header Content-Type
+   HttpRequest& ContentType(const std::string& content_type);
+
+   //Multipart/form data
+   HttpRequest& AppendPart(const std::string& name, const std::string& value);
+
+private:
+   friend class HttpClient;
+
+   std::string method_;
+   std::string url_;
+   std::string body_;
+
+   typedef std::map<std::string, std::string> HeaderFields;
+   HeaderFields header;
+   bool followRedirects;
+   int maxRedirects;
+   struct {
+     std::string username;
+     std::string password;
+   } basicAuth;
+
+   Multiparts multiparts_;
+};
+
+} /* namespace base */
+
+#endif /* JNI_HTTP_REQUEST_H_ */

+ 63 - 0
jni/base/http_response.cpp

@@ -0,0 +1,63 @@
+/*
+ * responce.cpp
+ *
+ *  Created on: 2021年8月16日
+ *      Author: pengzc
+ */
+
+#include "http_response.h"
+#include "base/strings.hpp"
+
+namespace base {
+
+HttpResponse::HttpResponse() {
+  // TODO 自动生成的构造函数存根
+  status_code_ = 0;
+  error_code_ = 0;
+  dst_file_ = NULL;
+}
+
+HttpResponse::~HttpResponse() {
+  // TODO 自动生成的析构函数存根
+}
+
+int HttpResponse::StatusCode() {
+  return status_code_;
+}
+
+int HttpResponse::ErrorCode() {
+  return error_code_;
+}
+
+std::string HttpResponse::Body() {
+  return body_;
+}
+
+std::string HttpResponse::ErrorMessage() {
+  return error_message_;
+}
+
+#include "utils/Log.h"
+std::string HttpResponse::Header(const std::string& key) {
+  return header_[key];
+}
+
+std::string* HttpResponse::mutable_body() {
+  return &body_;
+}
+
+std::string HttpResponse::ToString() {
+  std::string str;
+         str += "HTTP Request Info\n";
+         str += base::format("\t total_time: %lf\n", total_time);
+         str += base::format("\t name_lookup_time: %lf\n", name_lookup_time);
+         str += base::format("\t connect_time: %lf\n", connect_time);
+         str += base::format("\t app_connect_time: %lf\n", app_connect_time);
+         str += base::format("\t pre_transfer_time: %lf\n", pre_transfer_time);
+         str += base::format("\t start_transfer_time: %lf\n", start_transfer_time);
+         str += base::format("\t redirect_time: %lf\n", redirect_time);
+         str += base::format("\t redirect_count: %d\n", redirect_count);
+  return str;
+}
+
+} /* namespace base */

+ 55 - 0
jni/base/http_response.h

@@ -0,0 +1,55 @@
+/*
+ * responce.h
+ *
+ *  Created on: 2021年8月16日
+ *      Author: pengzc
+ */
+
+#ifndef JNI_HTTP_RESPONSE_H_
+#define JNI_HTTP_RESPONSE_H_
+
+#include <string>
+#include <map>
+#include <iostream>
+#include <fstream>
+
+namespace base {
+
+class HttpClient;
+
+class HttpResponse {
+public:
+  HttpResponse();
+  virtual ~HttpResponse();
+
+  int StatusCode();
+  int ErrorCode();
+  std::string Body();
+  std::string ErrorMessage();
+  std::string Header(const std::string& key);
+  std::map<std::string, std::string> header_;
+
+  std::string* mutable_body();
+
+  std::string ToString();
+private:
+  friend class HttpClient;
+  std::string body_;
+  int status_code_;
+  int error_code_;
+  std::string error_message_;
+  FILE* dst_file_;
+
+  double total_time = 0;
+  double name_lookup_time = 0;
+  double connect_time = 0;
+  double app_connect_time = 0;
+  double pre_transfer_time = 0;
+  double start_transfer_time = 0;
+  double redirect_time = 0;
+  int redirect_count = 0;
+};
+
+} /* namespace base */
+
+#endif /* JNI_HTTP_RESPONSE_H_ */

+ 134 - 0
jni/base/input_event_reader.hpp

@@ -0,0 +1,134 @@
+#ifndef _FY_INPUT_EVENT_READER_HPP_
+#define _FY_INPUT_EVENT_READER_HPP_
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/select.h>
+#include <linux/input.h>
+#include <fcntl.h>
+
+#include <string>
+#include <vector>
+
+#include <fy/mutex.hpp>
+
+namespace fy {
+
+class input_event_reader {
+private:
+  struct input_source {
+    std::string name;
+    std::string path;
+    int fd;
+  };
+
+public:
+
+  explicit input_event_reader() {
+  }
+
+  virtual ~input_event_reader() {
+    lock_guard<fy::mutex> lock(mutex_);
+    for (std::vector<input_source>::iterator it = input_sources_.begin(); it != input_sources_.end(); ++it) {
+      if (it->fd >= 0) {
+        close(it->fd);
+      }
+    }
+  }
+
+  int add_input(const std::string& name, const std::string& input_path) {
+    lock_guard<fy::mutex> lock(mutex_);
+    int fd = open(input_path.c_str(), O_RDONLY);
+    if (fd < 0) {
+      return -1;
+    }
+    struct input_source source;
+    source.name = name;
+    source.path = input_path;
+    source.fd = fd;
+    input_sources_.push_back(source);
+    return 0;
+  }
+
+  void remove_input(const std::string& name) {
+    lock_guard<fy::mutex> lock(mutex_);
+    for (std::vector<input_source>::iterator it = input_sources_.begin(); it != input_sources_.end(); ++it) {
+      if (name.compare(it->name) == 0) {
+        if(it->fd >= 0) {
+          close(it->fd);
+        }
+        input_sources_.erase(it);
+        return;
+      }
+    }
+  }
+
+  /**
+   * On success > 0
+   * Timeout  0
+   * Failed < 0
+   */
+  int read(std::string* name, input_event* event, int timeout_millis) {
+    fd_set read_fds;
+    int max_fd = setup_fdset(&read_fds);
+    if (max_fd < 0) {
+      return -1;
+    }
+
+    struct timeval tv;
+    tv.tv_sec = timeout_millis / 1000;
+    tv.tv_usec = timeout_millis % 1000;
+    int ret = select(max_fd + 1, &read_fds, NULL, NULL, &tv);
+    if (ret < 0) {
+        //LOGD("error");
+        return -2;
+    } else if (ret == 0) {
+      //timeout
+      return 0;
+    } else {
+      for (std::vector<input_source>::iterator it = input_sources_.begin(); it != input_sources_.end(); ++it) {
+        if (it->fd < 0) {
+          continue;
+        }
+        *name = it->name;
+        if(FD_ISSET(it->fd, &read_fds)) {
+          int rs = ::read(it->fd, event, sizeof(input_event));
+          if (rs == sizeof(input_event)) {
+            return 1;
+          } else {
+            //LOGD("read exception");
+            return -3;
+          }
+        }
+      }
+    }
+    return 0;
+  }
+
+protected:
+  int setup_fdset(fd_set* set) {
+    FD_ZERO(set);
+    int max_fd = -1;
+    for (std::vector<input_source>::iterator it = input_sources_.begin(); it != input_sources_.end(); ++it) {
+      int fd = it->fd;
+      if (fd >= 0) {
+        FD_SET(fd, set);
+        if (fd > max_fd) {
+          max_fd = fd;
+        }
+      }
+    }
+    if (max_fd < 0) {
+      return -1;
+    }
+    return max_fd;
+  }
+
+private:
+  std::vector<input_source> input_sources_;
+  fy::mutex mutex_;
+};
+
+} /* namespace fy */
+
+#endif /* _FY_INPUT_EVENT_READER_HPP_ */

+ 158 - 0
jni/base/json_array.cpp

@@ -0,0 +1,158 @@
+#include "json_array.h"
+
+#include <fstream>
+#include <sstream>
+#include "rapidjson/stringbuffer.h"
+#include "rapidjson/allocators.h"
+#include "rapidjson/writer.h"
+
+#include "utils/Log.h"
+
+#define  JSONARRAY_CHECK_RANGE \
+   if (rapidjson::SizeType(index) >= doc_.Size()) { \
+     LOGE("%s index out of range", __FUNCTION__); \
+     RAPIDJSON_ASSERT(0); \
+   } \
+
+namespace base {
+
+JSONArray::JSONArray() {
+  doc_.SetArray();
+}
+
+JSONArray::~JSONArray() {
+}
+
+JSONArray::JSONArray(const rapidjson::Value::Array& array) {
+  doc_.SetArray();
+  for (rapidjson::SizeType i = 0; i < array.Size(); ++i) {
+    doc_.PushBack(rapidjson::Value(array[i], doc_.GetAllocator()).Move(),
+        doc_.GetAllocator());
+  }
+}
+
+JSONArray::JSONArray(const rapidjson::Value::ConstArray& array) {
+  doc_.SetArray();
+  for (rapidjson::SizeType i = 0; i < array.Size(); ++i) {
+    doc_.PushBack(rapidjson::Value(array[i], doc_.GetAllocator()).Move(),
+        doc_.GetAllocator());
+  }
+}
+
+JSONArray::JSONArray(JSONArray&& array) {
+  doc_.SetArray();
+  doc_.Swap(array.doc_);
+}
+
+int JSONArray::GetInt(int index) {
+  JSONARRAY_CHECK_RANGE;
+  return (doc_.Begin()[index]).GetInt();
+}
+
+uint32_t JSONArray::GetUint(int index) {
+  JSONARRAY_CHECK_RANGE;
+  return (doc_.Begin()[index]).GetUint();
+}
+
+std::string JSONArray::GetString(int index) {
+  JSONARRAY_CHECK_RANGE;
+  return (doc_.Begin()[index]).GetString();
+}
+
+int64_t JSONArray::GetInt64(int index) {
+  JSONARRAY_CHECK_RANGE;
+  return (doc_.Begin()[index]).GetInt64();
+}
+
+uint64_t JSONArray::GetUint64(int index) {
+  JSONARRAY_CHECK_RANGE;
+  return (doc_.Begin()[index]).GetUint64();
+}
+
+JSONArray JSONArray::GetArray(int index) {
+  JSONARRAY_CHECK_RANGE;
+  if (!doc_[index].IsArray()) {
+    JSONArray arr;
+    return arr;
+  }
+  return doc_[index].GetArray();
+}
+
+JSONObject JSONArray::GetObject(int index) const {
+  JSONARRAY_CHECK_RANGE;
+  if (!doc_.Begin()[index].IsObject()) {
+    JSONObject obj;
+    return obj;
+  }
+  return (doc_.Begin()[index]).GetObject();
+}
+
+JSONArray& JSONArray::Add(int32_t value) {
+  doc_.PushBack(value, doc_.GetAllocator());
+  return *this;
+}
+
+JSONArray& JSONArray::Add(uint32_t value) {
+  doc_.PushBack(value, doc_.GetAllocator());
+  return *this;
+}
+
+JSONArray& JSONArray::Add(int64_t value) {
+  doc_.PushBack(value, doc_.GetAllocator());
+  return *this;
+}
+
+JSONArray& JSONArray::Add(uint64_t value) {
+  doc_.PushBack(value, doc_.GetAllocator());
+  return *this;
+}
+
+JSONArray& JSONArray::Add(bool value) {
+  doc_.PushBack(value, doc_.GetAllocator());
+  return *this;
+}
+
+JSONArray& JSONArray::Add(const JSONArray& array) {
+  rapidjson::Value v;
+  v.CopyFrom(array.doc_, doc_.GetAllocator());
+  doc_.PushBack(v, doc_.GetAllocator());
+  return *this;
+}
+
+JSONArray& JSONArray::Add(const JSONObject& object) {
+  rapidjson::Value v;
+  v.CopyFrom(object.doc_, doc_.GetAllocator());
+  doc_.PushBack(v, doc_.GetAllocator());
+  return *this;
+}
+
+int JSONArray::Size() const {
+  return doc_.Size();
+}
+
+bool JSONArray::ParseArray(const std::string& json_str) {
+  doc_.Parse(json_str.c_str());
+  return !doc_.HasParseError() && doc_.IsArray();
+}
+
+bool JSONArray::ParseArrayFromFile(const std::string& file_path) {
+  std::ifstream ifs(file_path.c_str(), std::ios::in | std::ios::binary);
+  if (!ifs.is_open()) {
+    return false;
+  }
+  std::stringstream ss;
+  ss << ifs.rdbuf();
+  ifs.close();
+  return ParseArray(ss.str());
+}
+
+std::string JSONArray::ToString() const {
+  return rapidjson_to_string(doc_);
+}
+
+std::string JSONArray::ToPrettyString() const {
+  return rapidjson_to_pretty_string(doc_);
+}
+
+} /* namespace rapidjson */
+

+ 67 - 0
jni/base/json_array.h

@@ -0,0 +1,67 @@
+#ifndef _JSON_ARRAY_H_
+#define _JSON_ARRAY_H_
+
+#include "rapidjson/document.h"
+
+#include "json_object.h"
+
+namespace base {
+
+class JSONObject;
+class JSONArray {
+public:
+  JSONArray();
+  virtual ~JSONArray();
+
+  JSONArray(const rapidjson::Value::Array& array);
+  JSONArray(const rapidjson::Value::ConstArray& array);
+
+  JSONArray(JSONArray&& array);
+
+  int GetInt(int index);
+
+  uint32_t GetUint(int index);
+
+  std::string GetString(int index);
+
+  int64_t GetInt64(int index);
+
+  uint64_t GetUint64(int index);
+
+  JSONArray GetArray(int index);
+
+  JSONObject GetObject(int index) const ;
+
+  JSONArray& Add(int32_t value);
+  JSONArray& Add(uint32_t value);
+  JSONArray& Add(int64_t value);
+  JSONArray& Add(uint64_t value);
+  JSONArray& Add(bool value);
+  JSONArray& Add(const JSONArray& array);
+  JSONArray& Add(const JSONObject& object);
+
+  template <typename T>
+  JSONArray& Add(const T value) {
+    rapidjson::Value tmp(value, doc_.GetAllocator());
+    doc_.PushBack(tmp,
+        doc_.GetAllocator());
+    return *this;
+  }
+
+  int Size() const;
+
+  bool ParseArray(const std::string& json_str);
+
+  bool ParseArrayFromFile(const std::string& file_path);
+
+  std::string ToString() const;
+  std::string ToPrettyString() const;
+
+private:
+  friend class JSONObject;
+  rapidjson::Document doc_;
+};
+
+} /* namespace rapidjson */
+
+#endif

+ 236 - 0
jni/base/json_object.cpp

@@ -0,0 +1,236 @@
+#include "json_object.h"
+
+#include <fstream>
+#include <sstream>
+
+#include "rapidjson/stringbuffer.h"
+#include "rapidjson/allocators.h"
+#include "rapidjson/writer.h"
+#include "rapidjson/prettywriter.h"
+
+#include "utils/Log.h"
+
+namespace base {
+
+std::string rapidjson_to_string(const rapidjson::Document& doc) {
+  using namespace rapidjson;
+  StringBuffer buffer;
+  Writer<StringBuffer> writer(buffer);
+  doc.Accept(writer);
+  return buffer.GetString();
+}
+std::string rapidjson_to_pretty_string(const rapidjson::Document& doc) {
+  using namespace rapidjson;
+  StringBuffer buffer;
+  PrettyWriter<StringBuffer> writer(buffer);
+  doc.Accept(writer);
+  return buffer.GetString();
+}
+
+
+JSONObject::JSONObject() {
+  doc_.SetObject();
+}
+
+JSONObject::~JSONObject() {
+}
+
+
+JSONObject::JSONObject(const rapidjson::Value& value) {
+  doc_.SetObject();
+  doc_.CopyFrom(value, doc_.GetAllocator());
+}
+
+JSONObject::JSONObject(const rapidjson::Value::Object& obj) {
+  using namespace rapidjson;
+  doc_.SetObject();
+  for (Value::MemberIterator it = obj.MemberBegin(); it != obj.MemberEnd();
+      ++it) {
+    doc_.AddMember(Value(it->name, doc_.GetAllocator()).Move(),
+        Value(it->value, doc_.GetAllocator()).Move(), doc_.GetAllocator());
+  }
+}
+
+JSONObject::JSONObject(const rapidjson::Value::ConstObject& obj) {
+  using namespace rapidjson;
+  doc_.SetObject();
+  for (Value::ConstMemberIterator it = obj.MemberBegin(); it != obj.MemberEnd();
+      ++it) {
+    doc_.AddMember(Value(it->name, doc_.GetAllocator()).Move(),
+        Value(it->value, doc_.GetAllocator()).Move(), doc_.GetAllocator());
+  }
+}
+
+JSONObject::JSONObject(JSONObject&& obj) {
+  doc_.SetObject();
+  doc_.Swap(obj.doc_);
+}
+
+JSONObject::JSONObject(const JSONObject& obj) {
+  doc_.SetObject();
+  doc_.CopyFrom(obj.doc_, doc_.GetAllocator());
+}
+
+JSONObject& JSONObject::Put(const std::string& name, int32_t v) {
+  using namespace rapidjson;
+  doc_.AddMember(Value(name.c_str(), doc_.GetAllocator()).Move(),
+      Value().SetInt(v), doc_.GetAllocator());
+  return *this;
+}
+
+JSONObject& JSONObject::Put(const std::string& name, uint32_t v) {
+  using namespace rapidjson;
+  doc_.AddMember(Value(name.c_str(), doc_.GetAllocator()).Move(),
+      Value().SetUint(v), doc_.GetAllocator());
+  return *this;
+}
+
+JSONObject& JSONObject::Put(const std::string& name, int64_t v) {
+  using namespace rapidjson;
+  doc_.AddMember(Value(name.c_str(), doc_.GetAllocator()).Move(),
+      Value().SetInt64(v), doc_.GetAllocator());
+  return *this;
+}
+
+JSONObject& JSONObject::Put(const std::string& name, uint64_t v) {
+  using namespace rapidjson;
+  doc_.AddMember(Value(name.c_str(), doc_.GetAllocator()).Move(),
+      Value().SetUint64(v), doc_.GetAllocator());
+  return *this;
+}
+
+JSONObject& JSONObject::Put(const std::string& name, const std::string& v) {
+  using namespace rapidjson;
+  doc_.AddMember(Value(name.c_str(), doc_.GetAllocator()).Move(),
+      Value().SetString(v.c_str(), doc_.GetAllocator()), doc_.GetAllocator());
+  return *this;
+}
+
+JSONObject& JSONObject::Put(const std::string& name, const JSONObject& v) {
+  using namespace rapidjson;
+  doc_.AddMember(Value(name.c_str(), doc_.GetAllocator()).Move(),
+      Value(v.doc_, doc_.GetAllocator()).Move(), doc_.GetAllocator());
+  return *this;
+}
+
+JSONObject& JSONObject::Put(const std::string& name, const JSONArray& v) {
+  using namespace rapidjson;
+  doc_.AddMember(Value(name.c_str(), doc_.GetAllocator()).Move(),
+      Value(v.doc_, doc_.GetAllocator()).Move(), doc_.GetAllocator());
+  return *this;
+}
+
+bool JSONObject::ParseObject(const std::string& json_str) {
+  doc_.Parse(json_str.c_str());
+  return !doc_.HasParseError() && doc_.IsObject();
+}
+
+bool JSONObject::ParseObjectFromFile(const std::string& path) {
+  std::ifstream ifs(path.c_str(), std::ios::in | std::ios::binary);
+  if (!ifs.is_open()) {
+    return false;
+  }
+  std::stringstream ss;
+  ss << ifs.rdbuf();
+  ifs.close();
+  return ParseObject(ss.str());
+}
+
+std::string JSONObject::ToString() const {
+  return rapidjson_to_string(doc_);
+}
+
+std::string JSONObject::ToPrettyString() const {
+  return rapidjson_to_pretty_string(doc_);
+}
+
+/**
+ * if not found, throw std::string
+ */
+int JSONObject::GetInt(const std::string& name) {
+  if (doc_.HasMember(name.c_str())) {
+    return doc_[name.c_str()].GetInt();
+  }
+  throw name;
+}
+
+/**
+ * if not found, throw std::string
+ */
+uint32_t JSONObject::GetUint(const std::string& name) {
+  if (doc_.HasMember(name.c_str())) {
+    return doc_[name.c_str()].GetUint();
+  }
+  throw name;
+}
+
+uint32_t JSONObject::GetUint(const std::string& name, uint32_t default_value) {
+  if (doc_.HasMember(name.c_str())) {
+    return doc_[name.c_str()].GetUint();
+  }
+  return default_value;
+}
+
+int JSONObject::GetInt(const std::string& name, int default_value) {
+  if (doc_.HasMember(name.c_str()) && doc_[name].IsInt()) {
+    return doc_[name.c_str()].GetInt();
+  }
+  return default_value;
+}
+
+int64_t JSONObject::GetInt64(const std::string& name, int64_t default_value) {
+  if (doc_.HasMember(name.c_str())) {
+    return doc_[name.c_str()].GetInt64();
+  }
+  return default_value;
+}
+
+/**
+ * if not found, throw std::string
+ */
+std::string JSONObject::GetString(const std::string& name) {
+  if (doc_.HasMember(name.c_str())) {
+    return doc_[name.c_str()].GetString();
+  }
+  throw name;
+}
+
+std::string JSONObject::GetString(const std::string& name,
+    const std::string& default_value) {
+  if (doc_.HasMember(name.c_str()) && doc_[name].IsString()) {
+    return doc_[name.c_str()].GetString();
+  }
+  return default_value;
+}
+
+bool JSONObject::GetBool(const std::string& name, bool default_value) {
+  if (doc_.HasMember(name) && doc_[name].IsBool()) {
+    return doc_[name].GetBool();
+  }
+  return default_value;
+}
+
+/**
+ * if not found, return empty array
+ */
+JSONArray JSONObject::GetArray(const std::string& name) const {
+  if (doc_.HasMember(name.c_str()) && doc_[name.c_str()].IsArray()
+      && !doc_[name].IsNull()) {
+    return (doc_[name.c_str()].GetArray());
+  }
+  JSONArray arr;
+  return arr;
+}
+
+/**
+ * if not found, return empty object
+ */
+JSONObject JSONObject::GetObject(const std::string& name) {
+  if (doc_.HasMember(name) && doc_[name].IsObject() && !doc_[name].IsNull()) {
+    return doc_[name];
+  }
+  JSONObject obj;
+  return obj;
+}
+
+}

+ 86 - 0
jni/base/json_object.h

@@ -0,0 +1,86 @@
+#ifndef _JSON_OBJECT_H_
+#define _JSON_OBJECT_H_
+
+#include "json_array.h"
+
+namespace base {
+
+std::string rapidjson_to_string(const rapidjson::Document& doc);
+std::string rapidjson_to_pretty_string(const rapidjson::Document& doc);
+
+class JSONArray;
+class JSONObject {
+public:
+  JSONObject();
+  virtual ~JSONObject();
+  JSONObject(const rapidjson::Value& value);
+  JSONObject(const rapidjson::Value::Object& obj);
+  JSONObject(const rapidjson::Value::ConstObject& obj);
+  JSONObject(JSONObject&& obj);
+  JSONObject(const JSONObject& obj);
+
+  JSONObject& Put(const std::string& name, int32_t v);
+
+  JSONObject& Put(const std::string& name, uint32_t v);
+
+  JSONObject& Put(const std::string& name, int64_t v);
+
+  JSONObject& Put(const std::string& name, uint64_t v);
+
+  JSONObject& Put(const std::string& name, const std::string& v);
+
+  JSONObject& Put(const std::string& name, const JSONObject& v);
+  JSONObject& Put(const std::string& name, const JSONArray& v);
+
+  bool ParseObject(const std::string& json_str);
+
+  bool ParseObjectFromFile(const std::string& path);
+
+  std::string ToString() const;
+  std::string ToPrettyString() const;
+
+  /**
+   * if not found, throw std::string
+   */
+  int GetInt(const std::string& name);
+
+  /**
+   * if not found, throw std::string
+   */
+  uint32_t GetUint(const std::string& name);
+
+  uint32_t GetUint(const std::string& name, uint32_t default_value);
+
+  int GetInt(const std::string& name, int default_value);
+
+  int64_t GetInt64(const std::string& name, int64_t default_value);
+
+  /**
+   * if not found, throw std::string
+   */
+  std::string GetString(const std::string& name);
+
+  std::string GetString(const std::string& name,
+      const std::string& default_value);
+
+  bool GetBool(const std::string& name, bool default_value);
+
+  /**
+   * if not found, return empty array
+   */
+  JSONArray GetArray(const std::string& name) const;
+
+  /**
+   * if not found, return empty object
+   */
+  JSONObject GetObject(const std::string& name);
+
+private:
+  friend class JSONArray;
+  rapidjson::Document doc_;
+};
+
+}
+/* namespace json */
+
+#endif

+ 75 - 0
jni/base/key_tone.hpp

@@ -0,0 +1,75 @@
+#ifndef BASE_KEY_TONE_HPP
+#define BASE_KEY_TONE_HPP
+
+#include "handler.hpp"
+#include "macros.h"
+#include "media/ZKMediaPlayer.h"
+#include "manager/ConfigManager.h"
+#include "stream_player.h"
+
+namespace base {
+
+class KeyTone {
+  DISALLOW_COPY_AND_ASSIGN(KeyTone)
+  DECLARE_INSTANCE(KeyTone)
+private:
+  enum Messages {
+    kClick,
+  };
+public:
+  static void Trigger() {
+    if (!instance()->enable_) {
+      return;
+    }
+    instance()->handler_.remove_messages(kClick);
+    base::message<float> msg(kClick, instance()->click_volume_);
+    instance()->handler_.send_message(msg);
+  }
+
+  static void Announce(float volume, int delayed) {
+    base::message<float> msg(kClick, volume);
+    instance()->handler_.send_message_delayed(msg, delayed);
+  }
+
+  static void set_enable(bool enable) {
+    instance()->enable_ = enable;
+  }
+
+  static void set_volume(float volume) {
+    instance()->click_volume_ = volume;
+  }
+
+private:
+  KeyTone() {
+    handler_.set_message_handler(
+        [](const base::message<float>* msg, const void* user_data){
+      ((KeyTone*)user_data)->HandleMessage(msg);
+    }, this);
+    stream_player_ = new fy::StreamPlayer();
+    click_volume_ = 1.0;
+    stream_player_->SetVolume(click_volume_);
+
+    enable_ = true;
+  }
+
+  ~KeyTone() {
+    if (stream_player_) {
+      delete stream_player_;
+    }
+  }
+
+  void HandleMessage(const base::message<float>* msg) {
+    stream_player_->SetVolume(msg->obj);
+    stream_player_->Play(CONFIGMANAGER->getResFilePath("keytone.wav"));
+  }
+
+private:
+  base::handler<float> handler_;
+  fy::StreamPlayer* stream_player_;
+  bool enable_;
+  float click_volume_;
+};
+
+} /* namespace base */
+
+#endif

+ 68 - 0
jni/base/log.hpp

@@ -0,0 +1,68 @@
+#ifndef _FY_LOG_HPP_
+#define _FY_LOG_HPP_
+
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#include "thread.hpp"
+
+namespace fy {
+
+class logcat {
+public:
+  logcat(const std::string& file) {
+    file_ = NULL;
+    run_ = true;
+    file_ = fopen(file.c_str(), "ab");
+    if (file_ == NULL) {
+      LOGD("failed to open %s", file.c_str());
+      return;
+    }
+    fy::thread t(fy::logcat::logcat_thread, this);
+    t.detach();
+  }
+
+  ~logcat() {
+    run_ = false;
+    LOGD("sup logcat stoped");
+    if (file_) {
+      fclose(file_);
+    }
+  }
+
+public:
+  static void logcat_thread(void *arg) {
+    logcat* log = (logcat*)arg;
+    FILE * p = popen("logcat -v time", "r");
+    if (p) {
+      while (!feof(p) && log->run_) {
+        char buffer[1024] = { 0 };
+        char* line = fgets(buffer, sizeof(buffer), p);
+        if (feof(p) || ferror(p)) {
+          break;
+        }
+        if (line) {
+          fputs(line, log->file_);
+          fflush(log->file_);
+        }
+        static int lines = 0;
+        ++lines;
+//        if (lines % 5 == 0) {
+          sync();
+//        }
+      }
+      fclose(p);
+    } else {
+      LOGD("open failed %d", errno);
+    }
+  }
+
+private:
+  FILE* file_;
+  bool run_;
+};
+
+
+} /* namespace fy */
+
+#endif /* _FY_LOG_HPP_ */

+ 87 - 0
jni/base/log/redirectcoutstreambuf.h

@@ -0,0 +1,87 @@
+#ifndef FLY_LOG_REDIRECTCOUTSTREAMBUF_H_
+#define FLY_LOG_REDIRECTCOUTSTREAMBUF_H_
+
+/**
+ * 重定向std::cout 到 Android Log
+ *
+ * 使用方法:
+ * #include <sup/log/redirectcoutstreambuf.h
+ * fly::log::RedirectCoutStreamBuf::Redirect("TAG");
+ *
+ */
+#include <memory.h>
+#include <iostream>
+#include <streambuf>
+
+#ifdef ANDROID
+#include <android/log.h>
+#endif
+
+namespace fy {
+namespace log {
+
+class RedirectCoutStreamBuf: public std::streambuf {
+  enum {
+    BUFFER_SIZE = 2047,
+  };
+
+public:
+  RedirectCoutStreamBuf(const char* tag) {
+    buffer_[BUFFER_SIZE] = '\0';
+    setp(buffer_, buffer_ + BUFFER_SIZE - 1);
+    memset(tag_, 0, sizeof(tag_));
+    memcpy(tag_, tag, strlen(tag));
+  }
+
+  ~RedirectCoutStreamBuf() {
+    sync();
+  }
+
+  static void Redirect(const char* tag) {
+    static RedirectCoutStreamBuf singleton(tag);
+    std::cout.rdbuf(&singleton);
+  }
+
+protected:
+  virtual int_type overflow(int_type c) {
+    if (c != EOF) {
+      *pptr() = c;
+      pbump(1);
+    }
+    flush_buffer();
+    return c;
+  }
+
+  virtual int sync() {
+    flush_buffer();
+    return 0;
+  }
+
+private:
+  int flush_buffer() {
+    int len = int(pptr() - pbase());
+    if (len <= 0)
+      return 0;
+
+    if (len <= BUFFER_SIZE)
+      buffer_[len] = '\0';
+
+#ifdef ANDROID
+    android_LogPriority t = ANDROID_LOG_INFO;
+    __android_log_write(t, tag_, buffer_);
+#else
+    printf("%s", buffer_);
+#endif
+
+    pbump(-len);
+    return len;
+  }
+
+private:
+  char buffer_[BUFFER_SIZE + 1];
+  char tag_[32];
+};
+}
+}
+
+#endif /* FLY_LOG_REDIRECTCOUTSTREAMBUF_H_ */

+ 37 - 0
jni/base/macros.h

@@ -0,0 +1,37 @@
+#ifndef _FY_MACRO_H_
+#define _FY_MACRO_H_
+#include <stddef.h>
+
+#define DISALLOW_COPY_AND_ASSIGN(classname) \
+private:                                   \
+    classname(const classname &);             \
+    classname &operator=(const classname &);
+
+
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(classname) \
+private:                                         \
+    classname();                                 \
+    DISALLOW_COPY_AND_ASSIGN(classname);
+
+
+#define DECLARE_SINGLETON(classname)        \
+public:                                    \
+    static classname *instance() {            \
+    static classname singleton;              \
+    return &singleton;                       \
+}                                         \
+DISALLOW_IMPLICIT_CONSTRUCTORS(classname) \
+    private:
+
+
+#define DECLARE_INSTANCE(classname)        \
+public:                                    \
+    static classname *instance() {            \
+    static classname singleton;              \
+    return &singleton;                       \
+}                                         \
+    private:
+
+#endif /* _FY_MACRO_H_ */
+
+

+ 42 - 0
jni/base/mutex.hpp

@@ -0,0 +1,42 @@
+#ifndef _FY_MUTEX_H_
+#define _FY_MUTEX_H_
+
+#include <pthread.h>
+
+namespace fy {
+
+class mutex {
+public:
+  mutex() {
+    pthread_mutex_init(&mutex_, NULL);
+  }
+  ~mutex() {
+    pthread_mutex_destroy(&mutex_);
+  }
+
+  void lock() {
+    pthread_mutex_lock(&mutex_);
+  }
+  void unlock() {
+    pthread_mutex_unlock(&mutex_);
+  }
+  int trylock() {
+    return pthread_mutex_trylock(&mutex_);
+  }
+
+private:
+  pthread_mutex_t mutex_;
+};
+
+template <typename T>
+class lock_guard {
+public:
+  lock_guard(T& mutex):mutex_(mutex) {mutex_.lock();}
+  ~lock_guard() {mutex_.unlock();}
+private:
+  T& mutex_;
+};
+
+} /* namespace fy */
+
+#endif

+ 539 - 0
jni/base/network.cpp

@@ -0,0 +1,539 @@
+/*
+ * network.cpp
+ *
+ *  Created on: 2022年3月4日
+ *      Author: pengzc
+ */
+
+#include "network.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <poll.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+
+#include "utils/Log.h"
+
+namespace base {
+
+/**
+ * 设置非阻塞模式
+ */
+static int SetNonBlock(int fd) {
+  int flags = fcntl(fd, F_GETFL, 0);
+  if (flags < 0) {
+    LOGE("Get flags error:%s", strerror(errno));
+    return -1;
+  }
+  flags |= O_NONBLOCK;
+  if (fcntl(fd, F_SETFL, flags) < 0) {
+    LOGE("Set flags error:%s", strerror(errno));
+    return -1;
+  }
+  return 0;
+}
+
+/**
+ * -1 error
+ * 0 timeout
+ * >0 get event
+ */
+static int Poll(int fd, int events, int timeout_millis, int* revents) {
+  int ret = -1;
+  struct pollfd pfd;
+  memset(&pfd, 0, int(sizeof(pfd)));
+  pfd.fd = fd;
+  pfd.events = events;
+  // retry again for EINTR
+  for (int i = 0; i < 2; i++) {
+    ret = ::poll(&pfd, 1, timeout_millis);
+    if (-1 == ret && EINTR == errno)
+      continue;
+    break;
+  }
+  if (ret >= 0) {
+    *revents = pfd.revents;
+  }
+  return ret;
+}
+
+static int NonBlockConnect(int fd, const struct sockaddr* ai_addr,
+    socklen_t ai_addrlen, int timeout_millis) {
+  /*设置套接字为非阻塞*/
+  if (SetNonBlock(fd) != 0) {
+    return SOCKET_ERROR;
+  }
+  /*阻塞情况下linux系统默认超时时间为75s*/
+  int ret = ::connect(fd, ai_addr, ai_addrlen);
+  if (ret == 0) {
+    return ret;
+  }
+  if (errno != EINPROGRESS) {
+    LOGE("connect failure, %s(%d)", strerror(errno), errno);
+    return SOCKET_ERROR;
+  }
+  //LOGD("Doing connection.\n");
+  /*正在处理连接*/
+  int revents = 0;
+  ret = Poll(fd, POLLIN | POLLOUT | POLLHUP | POLLERR | POLLNVAL,
+      timeout_millis, &revents);
+  if (ret < 0) {
+    LOGE("poll failure, %s(%d)", strerror(errno), errno);
+    return SOCKET_ERROR;
+  }
+  if (ret == 0) {
+    return SOCKET_TIMEOUT;
+  }
+
+  if (((revents & POLLOUT) != 0) && ((revents & POLLIN) == 0)) {
+    return SOCKET_SUCCESS;
+  }
+  if ((revents & POLLOUT) != 0 && (revents & POLLIN) != 0) {
+    int err = 0;
+    int errlen = sizeof(err);
+    if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, (socklen_t*)&errlen)
+        == -1) {
+      LOGE("getsockopt failure, %s", strerror(errno));
+      return SOCKET_ERROR;
+    }
+    if (err) {
+      errno = err;
+      LOGE("connect failure, %s(%d)", strerror(errno), errno);
+      return SOCKET_ERROR;
+    }
+  }
+  return SOCKET_ERROR;
+}
+
+static int Send(int sock_fd, const uint8_t* buffer, size_t buflen) {
+  if (buflen <= 0) {
+    return 0;
+  }
+  if (buffer == NULL) {
+    return 0;
+  }
+  size_t tmp;
+  size_t total = buflen;
+  const unsigned char *p = buffer;
+  while (true) {
+    tmp = send(sock_fd, p, total, 0);
+    if (tmp < 0) {
+      // 当send收到信号时,可以继续写,但这里返回-1.
+      if (errno == EINTR) {
+        usleep(1000 * 100);
+        continue;
+      }
+      // 当socket是非阻塞时,如返回此错误,表示写缓冲队列已满,
+      // 在这里做延时后再重试.
+      if (errno == EAGAIN) {
+        usleep(1000 * 100);
+        continue;
+      }
+      return -1;
+    }
+
+    if ((size_t) tmp == total) {
+//        LOGD("send success");
+      return buflen;
+    }
+
+    total -= tmp;
+    p += tmp;
+  }
+  return tmp;
+}
+
+Socket::Socket() {
+  socket_ = -1;
+}
+
+Socket::~Socket() {
+}
+
+int Socket::Connect(const std::string& host, int port, int timeout_millis) {
+  if (socket_ >= 0) {
+    LOGE("already connect");
+    return SOCKET_ERROR;
+  }
+  struct addrinfo host_info;
+  struct addrinfo * host_info_list = NULL;
+  memset(&host_info, 0, int(sizeof(host_info)));
+  host_info.ai_family = AF_UNSPEC;
+  host_info.ai_socktype = SOCK_STREAM;
+
+  char port_str[32] = {0};
+  snprintf(port_str, int(sizeof(port_str)), "%d", port);
+  int ret = getaddrinfo(host.c_str(), port_str, &host_info,
+      &host_info_list);
+  if (ret != 0) {
+    LOGE("host could not be resolved");
+    return SOCKET_GET_ADDRESS_INFO;
+  }
+  int sock = socket(host_info_list->ai_family, host_info_list->ai_socktype,
+      host_info_list->ai_protocol);
+  if (sock == -1) {
+    LOGE("could not open socket, %s(%d)", strerror(errno), errno);
+    freeaddrinfo(host_info_list);
+    return SOCKET_INVALID;
+  }
+
+  ret = NonBlockConnect(sock, host_info_list->ai_addr,
+      host_info_list->ai_addrlen, timeout_millis);
+
+  if (ret != 0) {
+    freeaddrinfo(host_info_list);
+    close(sock);
+    return ret;
+  }
+  socket_ = sock;
+  freeaddrinfo(host_info_list);
+  return 0;
+}
+
+int Socket::Write(uint8_t* data, int data_len) {
+  if (socket_ < 0) {
+    return SOCKET_INVALID;
+  }
+  return Send(socket_, data, data_len);
+}
+
+int Socket::Read(uint8_t* buffer, int buffer_len, int timeout_millis) {
+  if (socket_ < 0) {
+    //没有连接
+    return SOCKET_INVALID;
+  }
+
+  int revents = 0;
+  int ret = Poll(socket_, POLLIN | POLLHUP | POLLERR | POLLNVAL, timeout_millis, &revents);
+  if (ret < 0) {
+    return SOCKET_ERROR;
+  }
+  if (ret == 0) {
+    return SOCKET_TIMEOUT;
+  }
+  int recv_bytes = recv(socket_, buffer, buffer_len, 0);
+  if (recv_bytes == 0) {
+    //连接已关闭
+    //LOGD("recv 0, close it");
+    Close();
+    return 0;
+  } else if (recv_bytes < 0) {
+    //添加错误处理
+    if ((errno == EINTR) || (errno == EWOULDBLOCK) || (errno == EAGAIN)) {
+      //继续recv
+      return SOCKET_TIMEOUT;
+    } else {
+      LOGE("recv: %s(%d)", strerror(errno), errno);
+      Close();
+      return SOCKET_ERROR;
+    }
+  }
+  return recv_bytes;
+}
+
+int Socket::Close() {
+  if (socket_ >= 0) {
+    close(socket_);
+    socket_ = -1;
+  }
+  return 0;
+}
+
+InetAddress Socket::inet_address() const {
+  return address_;
+}
+
+//ServerSocket
+
+ServerSocket::ServerSocket(int port) {
+  server_socket_ = socket(PF_INET, SOCK_STREAM, 0);
+  if (server_socket_ < 0) {
+    LOGE("socket failure, %s(%d)", strerror(errno), errno);
+    return;
+  }
+
+  int on = 1;
+  if (setsockopt(server_socket_, SOL_SOCKET, SO_REUSEADDR, &on,
+      socklen_t(sizeof(on))) != 0) {
+     LOGE("setsockopt failure, %s(%d)", strerror(errno), errno);
+     goto failure;
+  }
+  memset(&server_addr_, 0, int(sizeof(server_addr_)));
+  server_addr_.sin_family = AF_INET;
+  server_addr_.sin_port = htons(port);
+  server_addr_.sin_addr.s_addr = htonl(INADDR_ANY);
+  if (bind(server_socket_, (struct sockaddr*) &server_addr_,
+      socklen_t(sizeof(server_addr_))) < 0) {
+    LOGE("bind failure, %s(%d)", strerror(errno), errno);
+    goto failure;
+  }
+  if (listen(server_socket_, 64) < 0) {
+    LOGE("listen failure, %s(%d)", strerror(errno), errno);
+    goto failure;
+  }
+  return;
+failure:
+  if (server_socket_ >= 0) {
+    close(server_socket_);
+    server_socket_ = -1;
+  }
+}
+
+ServerSocket::~ServerSocket() {
+  if (server_socket_ >= 0) {
+    close(server_socket_);
+    server_socket_ = -1;
+  }
+}
+
+int ServerSocket::Accept(Socket* socket) {
+  if (server_socket_ < 0) {
+    return SOCKET_INVALID;
+  }
+  if (socket == NULL) {
+    LOGE("argument socket must be not null");
+    return SOCKET_INVALID;
+  }
+  socklen_t addr_len = socklen_t(sizeof(socket->address_.address_));
+  int client = accept(server_socket_,
+      (struct sockaddr*) &socket->address_.address_, &addr_len);
+  if (client < 0) {
+    LOGD("accept failure, %s(%d)", strerror(errno), errno);
+    return SOCKET_ERROR;
+  }
+  socket->socket_ = client;
+  return client;
+}
+
+InetAddress::InetAddress() {
+  memset(&address_, 0, int(sizeof(address_)));
+}
+
+InetAddress::InetAddress(const std::string& host, int port) {
+  memset(&address_, 0, int(sizeof(address_)));
+  address_.sin_family = AF_INET;
+  address_.sin_port = htons(port);
+  address_.sin_addr.s_addr = inet_addr(host.c_str());
+}
+
+std::string InetAddress::ipv4() const {
+  struct sockaddr_in in = {0};
+  if (0 == memcmp(&address_, &in, int(sizeof(in)))) {
+    //未初始化的地址返回空
+    return "";
+  }
+  return inet_ntoa(address_.sin_addr);
+}
+
+DatagramSocket::DatagramSocket() {
+  socket_ = socket(AF_INET, SOCK_DGRAM, 0);
+  if (socket_ < 0) {
+    LOGE("socket failure, %s(%d)", strerror(errno), errno);
+  }
+}
+
+DatagramSocket::DatagramSocket(int port) {
+  socket_ = socket(AF_INET, SOCK_DGRAM, 0);
+  if (socket_ < 0) {
+    LOGE("socket failure, %s(%d)", strerror(errno), errno);
+    return;
+  }
+  struct sockaddr_in ser_addr;
+  memset(&ser_addr, 0, int(sizeof(ser_addr)));
+  ser_addr.sin_family = AF_INET;
+  ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+  ser_addr.sin_port = htons(port);
+  int ret = bind(socket_, (struct sockaddr*) &ser_addr,
+      socklen_t(sizeof(ser_addr)));
+  if (ret < 0) {
+    LOGE("bind failure, %s(%d)", strerror(errno), errno);
+    close(socket_);
+    socket_ = -1;
+  }
+}
+
+DatagramSocket::~DatagramSocket() {
+}
+
+int DatagramSocket::SendTo(const InetAddress& address, const uint8_t* data,
+    int len) {
+  if (socket_ < 0) {
+    return SOCKET_INVALID;
+  }
+  return sendto(socket_, data, len, 0, (sockaddr*) &address.address_,
+      socklen_t(sizeof(address.address_)));
+}
+
+int DatagramSocket::Receive(InetAddress* address, uint8_t* buffer,
+    int buffer_length, int timeout_millis) {
+  if (socket_ < 0) {
+    return SOCKET_INVALID;
+  }
+  int revents = 0;
+  int ret = Poll(socket_, POLLIN, timeout_millis, &revents);
+  if (ret < 0) {
+    return SOCKET_ERROR;
+  }
+  if (ret == 0) {
+    return SOCKET_TIMEOUT;
+  }
+  sockaddr* addr = NULL;
+  socklen_t addr_len = 0;
+  if (address != NULL) {
+    addr = (sockaddr*) &address->address_;
+    addr_len = sizeof(address->address_);
+  }
+  ret = recvfrom(socket_, buffer, buffer_length, 0, addr, &addr_len);
+  if (ret == 0) {
+    //连接已关闭
+    Close();
+    return 0;
+  } else if (ret < 0) {
+    if ((errno == EINTR) || (errno == EWOULDBLOCK) || (errno == EAGAIN)) {
+      //继续recv
+      return SOCKET_TIMEOUT;
+    } else {
+      LOGE("recv: %s(%d)", strerror(errno), errno);
+      Close();
+      return SOCKET_ERROR;
+    }
+  }
+  return ret;
+}
+
+int DatagramSocket::Close() {
+  if (socket_ >= 0) {
+    close(socket_);
+    socket_ = -1;
+  }
+  return 0;
+}
+
+
+#if 0  //测试程序段
+  std::thread server_thread([](){
+    net::ServerSocket server(8080);
+    while(true) {
+      net::Socket so;
+      LOGE("服务端 等待连接");
+      int ret = server.Accept(&so);
+      if (ret < 0) {
+        LOGE("Accept failure %d", ret);
+        break;
+      }
+      const char* msg = "hello";
+      uint8_t buf[1024] = {0};
+      ret = so.Read(buf, int(sizeof(buf)), 2000);
+      LOGE("服务端 读取 %d %s", ret, buf);
+
+      ret = so.Write((uint8_t*)msg, strlen(msg));
+      LOGE("服务端 发送 %d %s", ret, ret == strlen(msg) ? "成功" : "失败");
+      so.Close();
+    }
+  });
+  server_thread.detach();
+
+  int test_count = 100000;
+  usleep(1000 * 1000);
+  while(test_count--) {
+    LOGD("test count %d", test_count);
+    net::Socket so;
+    //net::Conn* conn = net::Dial("tcp", "14.215.177.38:80");
+//    int ret = so.Connect("14.215.177.38", 80, 3000);
+    int ret = so.Connect("127.0.0.1", 8080, 3000);
+//    int ret = so.Connect("www.baidu.com", 80, 3000);
+    LOGD("连接 %d", ret);
+    if (ret == 0)
+    {
+      uint8_t buf[2048] = {0};
+      const char* req = "GET / HTTP/1.1\r\nConnection: close\r\n\r\n";
+      //发送
+      ret = so.Write((uint8_t*)req, strlen(req));
+      LOGD("客户端 写 %d", ret);
+      while (true) {
+        //读取,超时1000毫秒
+        int n = so.Read(buf, int(sizeof(buf)) - 1, 1000);
+        if (n > 0) {
+          buf[n] = 0;
+          LOGD("客户端 读取 %d字节: %s", n, buf);
+        } else if (n == 0) {
+          LOGD("客户端 连接正常断开");
+          break;
+        } else {
+          if (n == net::SOCKET_TIMEOUT) {
+            LOGD("客户端 读取超时, 继续读");
+            continue;
+          } else {
+            LOGE("客户端 出错 %d", n);
+            break;
+          }
+        }
+      }
+      //关闭连接
+      so.Close();
+      //释放内存
+    }
+  }
+#endif
+
+//测试UDP
+#if 0
+  {
+    std::thread server_thread([](){
+      net::DatagramSocket server(8080);
+      while(true) {
+        LOGE("服务端 等待接收");
+        net::InetAddress from_address;
+        uint8_t buffer[1024] = {0};
+        int ret = server.Receive(&from_address, buffer, int(sizeof(buffer)), 2000);
+
+        if (ret == net::SOCKET_TIMEOUT) {
+          LOGD("服务端接收超时");
+          continue;
+        }
+        if (ret < 0) {
+          LOGE("服务端接收出错 %d", ret);
+          break;
+        }
+        LOGE("服务端 读取 来自 %s %d %s", from_address.ipv4().c_str(), ret, buffer);
+
+        const char* msg = "hello";
+        ret = server.SendTo(from_address, (uint8_t*)msg, int(strlen(msg)));
+        LOGE("服务端 发送 %d %s", ret, ret == strlen(msg) ? "成功" : "失败");
+      }
+    });
+    server_thread.detach();
+  }
+  usleep(1000 * 1000);
+  {
+    //UDP客户端
+    net::InetAddress address("127.0.0.1", 8080);
+    net::DatagramSocket so;
+    while (true) {
+      const char* msg = "I am from client";
+      int ret = so.SendTo(address, (uint8_t*)msg, int(strlen(msg)));
+      LOGE("客户端 发送 %d %s", ret, ret == strlen(msg) ? "成功" : "失败");
+
+      uint8_t buffer[128] = {0};
+      ret = so.Receive(&address, buffer, int(sizeof(buffer)), 2000);
+      if (ret == net::SOCKET_TIMEOUT) {
+        LOGE("客户端 接收超时");
+        continue;
+      }
+      if (ret < 0) {
+        LOGE("客户端 接收失败");
+        break;
+      }
+      LOGE("客户端 接收 来自 %s %d  %s", address.ipv4().c_str(), ret, buffer);
+    }
+  }
+
+#endif
+
+
+} /* namespace base */
+

+ 116 - 0
jni/base/network.h

@@ -0,0 +1,116 @@
+/*
+ * network.h
+ *
+ *  Created on: 2022年1月17日
+ *      Author: pengzc
+ */
+
+#ifndef JNI_BASE_NETWORK_H_
+#define JNI_BASE_NETWORK_H_
+
+#include <stdint.h>
+#include <string>
+#include <netinet/in.h>
+
+namespace base {
+
+enum SocketConstant {
+  SOCKET_SUCCESS = 0,
+
+  SOCKET_ERROR             = -1,
+
+  SOCKET_TIMEOUT           = -10001,
+  SOCKET_INVALID           = -10002,
+  SOCKET_GET_ADDRESS_INFO  = -10003,
+
+};
+
+class InetAddress {
+public:
+  InetAddress();
+  InetAddress(const std::string& host, int port);
+
+  std::string ipv4() const;
+private:
+
+private:
+  friend class DatagramSocket;
+  friend class Socket;
+  friend class ServerSocket;
+  struct sockaddr_in address_;
+};
+
+class Socket {
+public:
+  Socket();
+  virtual ~Socket();
+
+  /**
+   * 0 成功,非0失败
+   */
+  int Connect(const std::string &host, int port, int timeout_millis);
+  /**
+   * >0 已发送的字节数
+   * <=0 失败
+   */
+  int Write(uint8_t* data, int data_len);
+  /**
+   * < 0 失败
+   * 0 已关闭
+   * > 0 读取的字节数
+   */
+  int Read(uint8_t* buffer, int buffer_len, int timeout_millis);
+
+  /**
+   * 不再使用后,必须主动关闭,释放资源
+   */
+  int Close();
+
+  /**
+   * 对方网络地址
+   */
+  InetAddress inet_address() const;
+private:
+  friend class ServerSocket;
+  int socket_;
+  InetAddress address_;
+};
+
+class ServerSocket {
+public:
+  explicit ServerSocket(int port);
+  virtual ~ServerSocket();
+
+  /**
+   * 阻塞,等待客户端连接
+   * >=0 有客户端连接
+   * < 0 出错
+   */
+  int Accept(Socket* socket);
+private:
+  int server_socket_;
+  struct sockaddr_in server_addr_;
+};
+
+class DatagramSocket {
+public:
+  DatagramSocket();
+  DatagramSocket(int port);
+  virtual ~DatagramSocket();
+
+  int SendTo(const InetAddress& address, const uint8_t* data, int len);
+
+  int Receive(InetAddress* address, uint8_t* buffer, int buffer_length,
+      int timeout_millis);
+
+  /**
+   * 不再使用后,必须主动关闭,释放资源
+   */
+  int Close();
+private:
+  int socket_;
+};
+
+} /* namespace base */
+
+#endif /* JNI_BASE_NETWORK_H_ */

+ 105 - 0
jni/base/numbers.hpp

@@ -0,0 +1,105 @@
+/*
+ * numbers.hpp
+ *
+ *  Created on: 2021年4月7日
+ *      Author: pengzc
+ */
+
+#ifndef _FY_NUMBERS_HPP_
+#define _FY_NUMBERS_HPP_
+
+#include <string.h>
+#include <stdint.h>
+#include <math.h>
+
+#include <string>
+
+namespace fy {
+
+// https://github.com/zhao520a1a/NumToCN/blob/master/src/NumToCn.java
+
+/**
+ * 以分为单位,将数字转换为中文大写
+ */
+std::string number_to_currency(int64_t cent) {
+  const char* CN_NUMBER[] = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" };
+  const char* CN_UNIT[] = { "分", "角", "圆", "拾", "佰", "仟", "万", "拾", "佰", "仟",
+      "亿", "拾", "佰", "仟", "兆", "拾", "佰", "仟", "顺" };
+
+  const char* CN_NEGATIVE = "负";
+  const char* CN_FULL = "整";
+  const char* CN_ZERO_FULL = "零圆整";
+
+  std::string currency;
+
+  //若输入为0,输出零圆整;
+  if (cent == 0) {
+    return CN_ZERO_FULL;
+  }
+
+  int64_t number = abs(cent);
+  int numIndex = 0; //记录数字的个数;
+  bool getZero = false;
+  /*
+   * 思路:要先判断一下小数部分的具体情况;究其根本是因为:小数部分和整数部分在处理“0”的问题上略有不同;避免出现如图1所示的情况;
+   */
+  //得到小数部分(小数点后两位);
+  int64_t scale = number % 100;
+  if (scale == 0) { //若小数部分为"00"时的情况;骚年,不要忘了在最后追加特殊字符:整
+    numIndex += 2;
+    getZero = true;
+    number /= 100;  // 从number去掉为0数;
+    currency.append(CN_FULL);
+  } else if (scale % 10 == 0) { //若小数部分为"*0"时的情况;
+    numIndex += 1;
+    getZero = true;
+    number /= 10; // 从number去掉为0数;
+  }
+
+  //排除上述两种小数部分的特殊情况,则对小数和整数的处理就是一样一样一样地了!
+  while (true) {
+    //循环结束条件;
+    if (number <= 0) {
+      break;
+    }
+
+    //每次通过取余来得到最后一位数;
+    int numUnit = (int) (number % 10);
+    if (numUnit != 0) {
+      currency.insert(0, CN_UNIT[numIndex]);  //先添加单位
+      currency.insert(0, CN_NUMBER[numUnit]); //在添加根据数字值来对应数组中的中文表述;
+      getZero = false; //表明当前数不是0;
+    } else {
+      //意思是它的上一次的数不是零,那么打印出零;
+      if (!getZero) {
+        currency.insert(0, CN_NUMBER[numUnit]);
+      }
+      //若角分位为零,那么打印零;
+      if (numIndex == 2) {
+        if (number > 0) {
+          currency.insert(0, CN_UNIT[numIndex]);
+        }
+      } else if ((numIndex - 2) % 4 == 0 && number % 1000 != 0) {
+        //第一个条件是为了每隔4位,打印“圆,万,亿”;第二个条件是为了避免出现如图3的情况;
+        currency.insert(0, CN_UNIT[numIndex]);
+      }
+      getZero = true; //将其置为true,那么如果下一位还是0,也不会再打印一遍'零';避免出现图2的情况;
+    }
+
+    // 从number每次都去掉最后一个数
+    number = number / 10;
+    numIndex++;
+  }
+
+  // 为负数,就在最前面追加特殊字符:负
+  if (cent < 0) {
+    currency.insert(0, CN_NEGATIVE);
+  }
+
+  return currency;
+}
+
+} /* namespace fy */
+
+
+#endif /* JNI_NUMBERS_HPP_ */

+ 290 - 0
jni/base/os.hpp

@@ -0,0 +1,290 @@
+#ifndef _FY_OS_H_
+#define _FY_OS_H_
+
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <stdio.h>
+#include <sys/reboot.h>
+#include <errno.h>
+#include <string.h>
+
+#include <string>
+#include <vector>
+#include <fstream>
+#include <sstream>
+#include <stdint.h>
+
+#include "strings.hpp"
+#include "entry/EasyUIContext.h"
+
+namespace base {
+
+enum endians {
+  endian_big,
+  endian_little,
+};
+
+/**
+ * 小端返回true,大端false
+ */
+inline bool is_little_endian() {
+  union {
+    int a;
+    char b;
+  } c;
+  c.a = 1;
+  return (c.b == 1);
+}
+
+template<typename T>
+inline void swap(T* a, T* b) {
+  *a = (*a) ^ (*b);
+  *b = (*a) ^ (*b);
+  *a = (*a) ^ (*b);
+}
+
+template<typename T>
+inline void reverse_endian(T* v) {
+  typedef unsigned char byte;
+  byte* b = (byte*) v;
+  for (int i = 0; i < (int)(sizeof(T)) / 2; ++i) {
+    swap(&(b[i]), &(b[sizeof(T) - 1 - i]));
+  }
+}
+
+template<typename T>
+inline T from_endian(T val, bool le) {
+  static bool e = is_little_endian();
+  if (e != le) {
+    reverse_endian(&val);
+    return val;
+  }
+  return val;
+}
+
+inline ::size_t to_uint16(const char* begin, endians endian) {
+  if (endian_big == endian) {
+    return (::size_t(begin[0]) << 8) | ::size_t(begin[1]);
+  } else {
+    return (::size_t(begin[1]) << 8) | ::size_t(begin[0]);
+  }
+}
+
+inline ::size_t to_big_u16(const char* begin) {
+  return to_uint16(begin, endian_big);
+}
+
+inline ::size_t to_little_u16(const char* begin) {
+  return to_uint16(begin, endian_little);
+}
+
+inline uint32_t to_big_u32(const char* begin) {
+  return (::size_t(begin[0]) << 24)
+      | (::size_t(begin[1]) << 16)
+      | (::size_t(begin[2]) << 8)
+      | (::size_t(begin[3]));
+}
+
+inline std::string system(const std::string &command) {
+  std::string result;
+  FILE *p = popen(command.c_str(), "r");
+  if (p) {
+    while (!feof(p)) {
+      char buffer[1024] = { 0 };
+      char *line = fgets(buffer, sizeof(buffer), p);
+      if (feof(p) || ferror(p)) {
+        break;
+      }
+      if (line) {
+        result += buffer;
+      }
+    }
+    fclose(p);
+  } else {
+    char buf[256] = {0};
+    snprintf(buf, (::size_t)sizeof(buf), "open failed ,errno=%d", errno);
+    return buf;
+  }
+  return result;
+}
+
+inline void reboot() {
+  ::reboot(RB_AUTOBOOT);
+}
+
+
+class statfs {
+public:
+  explicit statfs(const char* mount_point_path) {
+      memset(&stat_, 0, sizeof(stat_));
+      if ((error_ = ::statfs(mount_point_path, &stat_)) != 0) {
+        error_ = errno;
+      }
+  }
+  uint64_t block_count() {
+    return stat_.f_blocks;
+  }
+
+  uint64_t block_size() {
+    return stat_.f_bsize;
+  }
+
+  uint64_t free_blocks() {
+    return stat_.f_bfree;
+  }
+
+  uint64_t total_bytes() {
+    return stat_.f_blocks * stat_.f_bsize;
+  }
+
+  uint64_t available_bytes() {
+    return stat_.f_bavail * stat_.f_bsize;
+  }
+
+  // 0 ok, other error
+  int error() {
+    return error_;
+  }
+
+private:
+  struct ::statfs stat_;
+  int error_;
+};
+
+
+namespace path {
+
+//取路径前缀
+inline std::string prefix(const std::string &path) {
+  size_t pos = path.find_last_of(".");
+  if (pos == std::string::npos) {
+    return path;
+  }
+  return path.substr(0, pos);
+}
+
+//取文件后缀
+inline std::string suffix(const std::string &path) {
+  size_t pos = path.find_last_of(".");
+  if (pos == std::string::npos) {
+    return path;
+  }
+  if ((path.size() - 1) == pos) {
+    return "";
+  }
+  return path.substr(pos + 1);
+}
+
+inline std::string join(const std::string &a, const std::string &b) {
+  if (a.empty()) {
+    return b;
+  }
+  if (a[a.size() - 1] == '/') {
+    return a + b;
+  }
+  return a + "/" + b;
+}
+
+inline std::string dir(const std::string &path) {
+  ::size_t pos = path.find_last_of("/");
+  if (pos == 0) {
+    return "/";
+  }
+  if (pos != std::string::npos) {
+    return path.substr(0, pos);
+  }
+  return "";
+}
+
+inline std::string base(const std::string &path) {
+  ::size_t pos = path.find_last_of("/");
+  if (pos != std::string::npos) {
+    return path.substr(pos + 1);
+  }
+  return path;
+}
+
+inline std::vector<std::string> ls(const std::string path, const std::string &sscanf_format, bool recursive) {
+  // dir/*.cpp
+  std::vector<std::string> ret;
+  DIR *d;
+  struct dirent *entry;
+  if ((d = opendir(path.c_str())) == NULL) {
+    //can't open dir
+    return ret;
+  }
+  while ((entry = readdir(d)) != NULL) {
+    if ((strcmp(".", entry->d_name) == 0) || (strcmp("..", entry->d_name) == 0)) {
+      continue;
+    }
+
+    if ((entry->d_type == DT_DIR) && recursive) {
+      std::vector<std::string> sub = ls(join(path, entry->d_name), sscanf_format, recursive);
+      ret.insert(ret.end(), sub.begin(), sub.end());
+    } else {
+      std::string str = join(path, entry->d_name);
+      ret.push_back(str);
+    }
+  }
+  closedir(d);
+  return ret;
+}
+
+inline std::vector<std::string> available_serial_port() {
+  std::vector<std::string> v;
+  auto list = ls("/dev", "", false);
+  for (auto i : list) {
+    if (i.find("ttyS") != std::string::npos) {
+      v.push_back(std::string("/dev/") + i);
+    }
+  }
+  return v;
+}
+
+} // namespace path
+
+inline std::string _get_conf_str(const std::string& all,
+    const std::string& key) {
+  std::string::size_type start = all.find(key);
+  if (start == std::string::npos) {
+    return "";
+  }
+  std::string::size_type end_line = all.find("\n", start + key.size());
+  if (end_line == std::string::npos) {
+    return "";
+  }
+  return all.substr(std::string::size_type(start + key.size()),
+      std::string::size_type(end_line - start - key.size() - 1));
+}
+
+inline bool get_wpa_ssid_psk(std::string* ssid, std::string* psk) {
+  std::ifstream ifs("/data/misc/wifi/wpa_supplicant.conf",
+                    std::ios::in | std::ios::binary);
+  std::stringstream ss;
+  ss << ifs.rdbuf();
+  std::string content(ss.str());
+  ifs.close();
+
+  *ssid = _get_conf_str(content, "\tssid=\"");
+  *psk = _get_conf_str(content, "\tpsk=\"");
+  return ssid->size() > 0 || psk->size() > 0;
+}
+
+class screensaver_guard {
+public:
+  screensaver_guard() {
+    enable_ = EASYUICONTEXT->isScreensaverEnable();
+    EASYUICONTEXT->setScreensaverEnable(false);
+  }
+
+  ~screensaver_guard() {
+    EASYUICONTEXT->setScreensaverEnable(enable_);
+  }
+private:
+  bool enable_;
+};
+
+} // namespace fy
+
+#endif /* _FY_OS_H_ */

+ 150 - 0
jni/base/preference.hpp

@@ -0,0 +1,150 @@
+/*
+ * preference.h
+ *
+ *  Created on: 2021年4月16日
+ *      Author: pengzc
+ */
+
+#ifndef _FY_PREFERENCE_HPP_
+#define _FY_PREFERENCE_HPP_
+
+#include <unistd.h>
+
+#include <string>
+#include <sstream>
+#include <iostream>
+#include <fstream>
+
+#include <json/Json.h>
+#include <system/Thread.h>
+#include <utils/Log.h>
+
+#define FY_APPLICATION_PREFERENCES_PATH "/data/application_preferences"
+
+namespace base {
+
+class preference {
+public:
+  virtual ~preference() {
+  }
+
+  static void put(const std::string& name, const std::string &value) {
+    instance().write_json(name, value);
+  }
+
+  static void put(const std::string& name, const char* value) {
+    instance().write_json(name, value);
+  }
+
+  static void put(const std::string& name, const int value) {
+    instance().write_json(name, value);
+  }
+  static void put(const std::string& name, const bool value) {
+    instance().write_json(name, value);
+  }
+
+  static std::string get_string(const std::string &name, const std::string &def) {
+    Mutex::Autolock lock(instance().mutex_);
+    if (!instance().json_.isMember(name)) {
+      return def;
+    }
+    if (!instance().json_[name].isString()) {
+      return def;
+    }
+    return instance().json_[name].asString();
+  }
+  static int get_int(const std::string &name, const int def) {
+    Mutex::Autolock lock(instance().mutex_);
+    if (!instance().json_.isMember(name)) {
+      return def;
+    }
+    if (!instance().json_[name].isInt()) {
+      return def;
+    }
+    return instance().json_[name].asInt();
+  }
+  static bool get_bool(const std::string &name, const bool def) {
+    Mutex::Autolock lock(instance().mutex_);
+    if (!instance().json_.isMember(name)) {
+      return def;
+    }
+    if (!instance().json_[name].isBool()) {
+      return def;
+    }
+    return instance().json_[name].asBool();
+  }
+
+  static void remove(const std::string &name) {
+    instance().remove_key(name);
+  }
+
+  static void clear() {
+    instance().remove_all();
+  }
+
+private:
+  preference() {
+    std::ifstream ifs(FY_APPLICATION_PREFERENCES_PATH, std::ios::in | std::ios::binary);
+    if (!ifs.is_open()) {
+      //兼容
+      ifs.open("/data/preferences.json", std::ios::in | std::ios::binary);
+    }
+    std::stringstream  ss;
+    ss << ifs.rdbuf();
+    std::string file_content(ss.str());
+    if (file_content.empty()) {
+      return;
+    }
+    ifs.close();
+    Json::Reader reader;
+    if (!reader.parse(file_content.c_str(), file_content.c_str() + file_content.length(), json_, false)) {
+      LOGE("%s parse failed", __PRETTY_FUNCTION__);
+    }
+  }
+  static preference& instance() {
+    static preference singleton;
+    return singleton;
+  }
+
+private:
+  template<class T>
+  void write_json(const std::string &name, T value) {
+    Mutex::Autolock lock(mutex_);
+    if (json_.isMember(name) && (json_[name].compare(value) == 0)) {
+      return;
+    }
+    json_[name] = value;
+    write_json(json_);
+  }
+
+  void write_json(const Json::Value &json) {
+    std::ofstream ofs(FY_APPLICATION_PREFERENCES_PATH, std::ios::out | std::ios::binary);
+    if (!ofs.is_open()) {
+      return;
+    }
+    std::string str = json_.toStyledString();
+    ofs.write(str.c_str(), str.length());
+    ofs.flush();
+    ofs.close();
+    sync();
+  }
+  void remove_key(const std::string &name) {
+    Mutex::Autolock lock(mutex_);
+    json_.removeMember(name);
+    write_json(json_);
+  }
+
+  void remove_all() {
+    Mutex::Autolock lock(mutex_);
+    json_.clear();
+    write_json(json_);
+  }
+
+private:
+  Json::Value json_;
+  Mutex mutex_;
+};
+
+} /* namespace fy */
+
+#endif /* _FY_PREFERENCE_HPP_ */

+ 154 - 0
jni/base/prefs.hpp

@@ -0,0 +1,154 @@
+/*
+ * preference.h
+ *
+ *  Created on: 2021年4月16日
+ *      Author: pengzc
+ */
+
+#ifndef _FY_PREFERENCE_HPP_
+#define _FY_PREFERENCE_HPP_
+
+#include <unistd.h>
+
+#include <string>
+#include <sstream>
+#include <iostream>
+#include <fstream>
+
+#include <json/Json.h>
+#include <system/Thread.h>
+#include <utils/Log.h>
+
+#define FY_APPLICATION_PREFERENCES_PATH "/data/prefs.json"
+
+namespace base {
+
+class prefs {
+public:
+  virtual ~prefs() {
+  }
+
+  static void put(const std::string& name, const std::string &value) {
+    instance().write_json(name, value);
+  }
+
+  static void put(const std::string& name, const char* value) {
+    instance().write_json(name, value);
+  }
+
+  static void put(const std::string& name, const int value) {
+    instance().write_json(name, value);
+  }
+  static void put(const std::string& name, const bool value) {
+    instance().write_json(name, value);
+  }
+
+  static std::string get_string(const std::string &name, const std::string &def) {
+    Mutex::Autolock lock(instance().mutex_);
+    if (!instance().json_.isMember(name)) {
+      return def;
+    }
+    if (!instance().json_[name].isString()) {
+      return def;
+    }
+    return instance().json_[name].asString();
+  }
+  static int get_int(const std::string &name, const int def) {
+    Mutex::Autolock lock(instance().mutex_);
+    if (!instance().json_.isMember(name)) {
+      return def;
+    }
+    if (!instance().json_[name].isInt()) {
+      return def;
+    }
+    return instance().json_[name].asInt();
+  }
+  static bool get_bool(const std::string &name, const bool def) {
+    Mutex::Autolock lock(instance().mutex_);
+    if (!instance().json_.isMember(name)) {
+      return def;
+    }
+    if (!instance().json_[name].isBool()) {
+      return def;
+    }
+    return instance().json_[name].asBool();
+  }
+
+  static void remove(const std::string &name) {
+    instance().remove_key(name);
+  }
+
+  static void clear() {
+    instance().remove_all();
+  }
+
+private:
+  prefs() {
+    LOGD("prefs 1");
+    std::ifstream ifs(FY_APPLICATION_PREFERENCES_PATH, std::ios::in | std::ios::binary);
+    if (!ifs.is_open()) {
+      //兼容
+      ifs.open("/data/preferences.json", std::ios::in | std::ios::binary);
+    }
+    std::stringstream  ss;
+    ss << ifs.rdbuf();
+    std::string file_content(ss.str());
+    if (file_content.empty()) {
+      return;
+    }
+    ifs.close();
+    LOGD("prefs 2");
+
+    Json::Reader reader;
+    if (!reader.parse(file_content.c_str(), file_content.c_str() + file_content.length(), json_, false)) {
+      LOGE("%s parse failed", __PRETTY_FUNCTION__);
+    }
+    LOGD("prefs 3");
+  }
+  static prefs& instance() {
+    static prefs singleton;
+    return singleton;
+  }
+
+private:
+  template<class T>
+  void write_json(const std::string &name, T value) {
+    Mutex::Autolock lock(mutex_);
+    if (json_.isMember(name) && (json_[name].compare(value) == 0)) {
+      return;
+    }
+    json_[name] = value;
+    write_json(json_);
+  }
+
+  void write_json(const Json::Value &json) {
+    std::ofstream ofs(FY_APPLICATION_PREFERENCES_PATH, std::ios::out | std::ios::binary);
+    if (!ofs.is_open()) {
+      return;
+    }
+    std::string str = json_.toStyledString();
+    ofs.write(str.c_str(), str.length());
+    ofs.flush();
+    ofs.close();
+    sync();
+  }
+  void remove_key(const std::string &name) {
+    Mutex::Autolock lock(mutex_);
+    json_.removeMember(name);
+    write_json(json_);
+  }
+
+  void remove_all() {
+    Mutex::Autolock lock(mutex_);
+    json_.clear();
+    write_json(json_);
+  }
+
+private:
+  Json::Value json_;
+  Mutex mutex_;
+};
+
+} /* namespace fy */
+
+#endif /* _FY_PREFERENCE_HPP_ */

+ 284 - 0
jni/base/rapidjson/allocators.h

@@ -0,0 +1,284 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ALLOCATORS_H_
+#define RAPIDJSON_ALLOCATORS_H_
+
+#include "rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// Allocator
+
+/*! \class rapidjson::Allocator
+    \brief Concept for allocating, resizing and freeing memory block.
+    
+    Note that Malloc() and Realloc() are non-static but Free() is static.
+    
+    So if an allocator need to support Free(), it needs to put its pointer in 
+    the header of memory block.
+
+\code
+concept Allocator {
+    static const bool kNeedFree;    //!< Whether this allocator needs to call Free().
+
+    // Allocate a memory block.
+    // \param size of the memory block in bytes.
+    // \returns pointer to the memory block.
+    void* Malloc(size_t size);
+
+    // Resize a memory block.
+    // \param originalPtr The pointer to current memory block. Null pointer is permitted.
+    // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
+    // \param newSize the new size in bytes.
+    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
+
+    // Free a memory block.
+    // \param pointer to the memory block. Null pointer is permitted.
+    static void Free(void *ptr);
+};
+\endcode
+*/
+
+
+/*! \def RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
+    \ingroup RAPIDJSON_CONFIG
+    \brief User-defined kDefaultChunkCapacity definition.
+
+    User can define this as any \c size that is a power of 2.
+*/
+
+#ifndef RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
+#define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024)
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CrtAllocator
+
+//! C-runtime library allocator.
+/*! This class is just wrapper for standard C library memory routines.
+    \note implements Allocator concept
+*/
+class CrtAllocator {
+public:
+    static const bool kNeedFree = true;
+    void* Malloc(size_t size) { 
+        if (size) //  behavior of malloc(0) is implementation defined.
+            return std::malloc(size);
+        else
+            return NULL; // standardize to returning NULL.
+    }
+    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
+        (void)originalSize;
+        if (newSize == 0) {
+            std::free(originalPtr);
+            return NULL;
+        }
+        return std::realloc(originalPtr, newSize);
+    }
+    static void Free(void *ptr) { std::free(ptr); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// MemoryPoolAllocator
+
+//! Default memory allocator used by the parser and DOM.
+/*! This allocator allocate memory blocks from pre-allocated memory chunks. 
+
+    It does not free memory blocks. And Realloc() only allocate new memory.
+
+    The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
+
+    User may also supply a buffer as the first chunk.
+
+    If the user-buffer is full then additional chunks are allocated by BaseAllocator.
+
+    The user-buffer is not deallocated by this allocator.
+
+    \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
+    \note implements Allocator concept
+*/
+template <typename BaseAllocator = CrtAllocator>
+class MemoryPoolAllocator {
+public:
+    static const bool kNeedFree = false;    //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
+
+    //! Constructor with chunkSize.
+    /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
+        \param baseAllocator The allocator for allocating memory chunks.
+    */
+    MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : 
+        chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+    {
+    }
+
+    //! Constructor with user-supplied buffer.
+    /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
+
+        The user buffer will not be deallocated when this allocator is destructed.
+
+        \param buffer User supplied buffer.
+        \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
+        \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
+        \param baseAllocator The allocator for allocating memory chunks.
+    */
+    MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
+        chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+    {
+        RAPIDJSON_ASSERT(buffer != 0);
+        RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
+        chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
+        chunkHead_->capacity = size - sizeof(ChunkHeader);
+        chunkHead_->size = 0;
+        chunkHead_->next = 0;
+    }
+
+    //! Destructor.
+    /*! This deallocates all memory chunks, excluding the user-supplied buffer.
+    */
+    ~MemoryPoolAllocator() {
+        Clear();
+        RAPIDJSON_DELETE(ownBaseAllocator_);
+    }
+
+    //! Deallocates all memory chunks, excluding the user-supplied buffer.
+    void Clear() {
+        while (chunkHead_ && chunkHead_ != userBuffer_) {
+            ChunkHeader* next = chunkHead_->next;
+            baseAllocator_->Free(chunkHead_);
+            chunkHead_ = next;
+        }
+        if (chunkHead_ && chunkHead_ == userBuffer_)
+            chunkHead_->size = 0; // Clear user buffer
+    }
+
+    //! Computes the total capacity of allocated memory chunks.
+    /*! \return total capacity in bytes.
+    */
+    size_t Capacity() const {
+        size_t capacity = 0;
+        for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+            capacity += c->capacity;
+        return capacity;
+    }
+
+    //! Computes the memory blocks allocated.
+    /*! \return total used bytes.
+    */
+    size_t Size() const {
+        size_t size = 0;
+        for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+            size += c->size;
+        return size;
+    }
+
+    //! Allocates a memory block. (concept Allocator)
+    void* Malloc(size_t size) {
+        if (!size)
+            return NULL;
+
+        size = RAPIDJSON_ALIGN(size);
+        if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
+            if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
+                return NULL;
+
+        void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
+        chunkHead_->size += size;
+        return buffer;
+    }
+
+    //! Resizes a memory block (concept Allocator)
+    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
+        if (originalPtr == 0)
+            return Malloc(newSize);
+
+        if (newSize == 0)
+            return NULL;
+
+        originalSize = RAPIDJSON_ALIGN(originalSize);
+        newSize = RAPIDJSON_ALIGN(newSize);
+
+        // Do not shrink if new size is smaller than original
+        if (originalSize >= newSize)
+            return originalPtr;
+
+        // Simply expand it if it is the last allocation and there is sufficient space
+        if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
+            size_t increment = static_cast<size_t>(newSize - originalSize);
+            if (chunkHead_->size + increment <= chunkHead_->capacity) {
+                chunkHead_->size += increment;
+                return originalPtr;
+            }
+        }
+
+        // Realloc process: allocate and copy memory, do not free original buffer.
+        if (void* newBuffer = Malloc(newSize)) {
+            if (originalSize)
+                std::memcpy(newBuffer, originalPtr, originalSize);
+            return newBuffer;
+        }
+        else
+            return NULL;
+    }
+
+    //! Frees a memory block (concept Allocator)
+    static void Free(void *ptr) { (void)ptr; } // Do nothing
+
+private:
+    //! Copy constructor is not permitted.
+    MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
+    //! Copy assignment operator is not permitted.
+    MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
+
+    //! Creates a new chunk.
+    /*! \param capacity Capacity of the chunk in bytes.
+        \return true if success.
+    */
+    bool AddChunk(size_t capacity) {
+        if (!baseAllocator_)
+            ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)();
+        if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
+            chunk->capacity = capacity;
+            chunk->size = 0;
+            chunk->next = chunkHead_;
+            chunkHead_ =  chunk;
+            return true;
+        }
+        else
+            return false;
+    }
+
+    static const int kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
+
+    //! Chunk header for perpending to each chunk.
+    /*! Chunks are stored as a singly linked list.
+    */
+    struct ChunkHeader {
+        size_t capacity;    //!< Capacity of the chunk in bytes (excluding the header itself).
+        size_t size;        //!< Current size of allocated memory in bytes.
+        ChunkHeader *next;  //!< Next chunk in the linked list.
+    };
+
+    ChunkHeader *chunkHead_;    //!< Head of the chunk linked-list. Only the head chunk serves allocation.
+    size_t chunk_capacity_;     //!< The minimum capacity of chunk when they are allocated.
+    void *userBuffer_;          //!< User supplied buffer.
+    BaseAllocator* baseAllocator_;  //!< base allocator for allocating memory chunks.
+    BaseAllocator* ownBaseAllocator_;   //!< base allocator created by this object.
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_ENCODINGS_H_

+ 78 - 0
jni/base/rapidjson/cursorstreamwrapper.h

@@ -0,0 +1,78 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_
+#define RAPIDJSON_CURSORSTREAMWRAPPER_H_
+
+#include "stream.h"
+
+#if defined(__GNUC__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER <= 1800
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4702)  // unreachable code
+RAPIDJSON_DIAG_OFF(4512)  // assignment operator could not be generated
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+
+//! Cursor stream wrapper for counting line and column number if error exists.
+/*!
+    \tparam InputStream     Any stream that implements Stream Concept
+*/
+template <typename InputStream, typename Encoding = UTF8<> >
+class CursorStreamWrapper : public GenericStreamWrapper<InputStream, Encoding> {
+public:
+    typedef typename Encoding::Ch Ch;
+
+    CursorStreamWrapper(InputStream& is):
+        GenericStreamWrapper<InputStream, Encoding>(is), line_(1), col_(0) {}
+
+    // counting line and column number
+    Ch Take() {
+        Ch ch = this->is_.Take();
+        if(ch == '\n') {
+            line_ ++;
+            col_ = 0;
+        } else {
+            col_ ++;
+        }
+        return ch;
+    }
+
+    //! Get the error line number, if error exists.
+    size_t GetLine() const { return line_; }
+    //! Get the error column number, if error exists.
+    size_t GetColumn() const { return col_; }
+
+private:
+    size_t line_;   //!< Current Line
+    size_t col_;    //!< Current Column
+};
+
+#if defined(_MSC_VER) && _MSC_VER <= 1800
+RAPIDJSON_DIAG_POP
+#endif
+
+#if defined(__GNUC__)
+RAPIDJSON_DIAG_POP
+#endif
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_

File diff suppressed because it is too large
+ 2682 - 0
jni/base/rapidjson/document.h


+ 299 - 0
jni/base/rapidjson/encodedstream.h

@@ -0,0 +1,299 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ENCODEDSTREAM_H_
+#define RAPIDJSON_ENCODEDSTREAM_H_
+
+#include "stream.h"
+#include "memorystream.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Input byte stream wrapper with a statically bound encoding.
+/*!
+    \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
+    \tparam InputByteStream Type of input byte stream. For example, FileReadStream.
+*/
+template <typename Encoding, typename InputByteStream>
+class EncodedInputStream {
+    RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+public:
+    typedef typename Encoding::Ch Ch;
+
+    EncodedInputStream(InputByteStream& is) : is_(is) { 
+        current_ = Encoding::TakeBOM(is_);
+    }
+
+    Ch Peek() const { return current_; }
+    Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }
+    size_t Tell() const { return is_.Tell(); }
+
+    // Not implemented
+    void Put(Ch) { RAPIDJSON_ASSERT(false); }
+    void Flush() { RAPIDJSON_ASSERT(false); } 
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+    EncodedInputStream(const EncodedInputStream&);
+    EncodedInputStream& operator=(const EncodedInputStream&);
+
+    InputByteStream& is_;
+    Ch current_;
+};
+
+//! Specialized for UTF8 MemoryStream.
+template <>
+class EncodedInputStream<UTF8<>, MemoryStream> {
+public:
+    typedef UTF8<>::Ch Ch;
+
+    EncodedInputStream(MemoryStream& is) : is_(is) {
+        if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take();
+        if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take();
+        if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take();
+    }
+    Ch Peek() const { return is_.Peek(); }
+    Ch Take() { return is_.Take(); }
+    size_t Tell() const { return is_.Tell(); }
+
+    // Not implemented
+    void Put(Ch) {}
+    void Flush() {} 
+    Ch* PutBegin() { return 0; }
+    size_t PutEnd(Ch*) { return 0; }
+
+    MemoryStream& is_;
+
+private:
+    EncodedInputStream(const EncodedInputStream&);
+    EncodedInputStream& operator=(const EncodedInputStream&);
+};
+
+//! Output byte stream wrapper with statically bound encoding.
+/*!
+    \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
+    \tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.
+*/
+template <typename Encoding, typename OutputByteStream>
+class EncodedOutputStream {
+    RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+public:
+    typedef typename Encoding::Ch Ch;
+
+    EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { 
+        if (putBOM)
+            Encoding::PutBOM(os_);
+    }
+
+    void Put(Ch c) { Encoding::Put(os_, c);  }
+    void Flush() { os_.Flush(); }
+
+    // Not implemented
+    Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
+    Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
+    size_t Tell() const { RAPIDJSON_ASSERT(false);  return 0; }
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+    EncodedOutputStream(const EncodedOutputStream&);
+    EncodedOutputStream& operator=(const EncodedOutputStream&);
+
+    OutputByteStream& os_;
+};
+
+#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
+
+//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
+/*!
+    \tparam CharType Type of character for reading.
+    \tparam InputByteStream type of input byte stream to be wrapped.
+*/
+template <typename CharType, typename InputByteStream>
+class AutoUTFInputStream {
+    RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+public:
+    typedef CharType Ch;
+
+    //! Constructor.
+    /*!
+        \param is input stream to be wrapped.
+        \param type UTF encoding type if it is not detected from the stream.
+    */
+    AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
+        RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);        
+        DetectType();
+        static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
+        takeFunc_ = f[type_];
+        current_ = takeFunc_(*is_);
+    }
+
+    UTFType GetType() const { return type_; }
+    bool HasBOM() const { return hasBOM_; }
+
+    Ch Peek() const { return current_; }
+    Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
+    size_t Tell() const { return is_->Tell(); }
+
+    // Not implemented
+    void Put(Ch) { RAPIDJSON_ASSERT(false); }
+    void Flush() { RAPIDJSON_ASSERT(false); } 
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+    AutoUTFInputStream(const AutoUTFInputStream&);
+    AutoUTFInputStream& operator=(const AutoUTFInputStream&);
+
+    // Detect encoding type with BOM or RFC 4627
+    void DetectType() {
+        // BOM (Byte Order Mark):
+        // 00 00 FE FF  UTF-32BE
+        // FF FE 00 00  UTF-32LE
+        // FE FF        UTF-16BE
+        // FF FE        UTF-16LE
+        // EF BB BF     UTF-8
+
+        const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4());
+        if (!c)
+            return;
+
+        unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
+        hasBOM_ = false;
+        if (bom == 0xFFFE0000)                  { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
+        else if (bom == 0x0000FEFF)             { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
+        else if ((bom & 0xFFFF) == 0xFFFE)      { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take();                           }
+        else if ((bom & 0xFFFF) == 0xFEFF)      { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take();                           }
+        else if ((bom & 0xFFFFFF) == 0xBFBBEF)  { type_ = kUTF8;    hasBOM_ = true; is_->Take(); is_->Take(); is_->Take();              }
+
+        // RFC 4627: Section 3
+        // "Since the first two characters of a JSON text will always be ASCII
+        // characters [RFC0020], it is possible to determine whether an octet
+        // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
+        // at the pattern of nulls in the first four octets."
+        // 00 00 00 xx  UTF-32BE
+        // 00 xx 00 xx  UTF-16BE
+        // xx 00 00 00  UTF-32LE
+        // xx 00 xx 00  UTF-16LE
+        // xx xx xx xx  UTF-8
+
+        if (!hasBOM_) {
+            int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
+            switch (pattern) {
+            case 0x08: type_ = kUTF32BE; break;
+            case 0x0A: type_ = kUTF16BE; break;
+            case 0x01: type_ = kUTF32LE; break;
+            case 0x05: type_ = kUTF16LE; break;
+            case 0x0F: type_ = kUTF8;    break;
+            default: break; // Use type defined by user.
+            }
+        }
+
+        // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
+        if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
+        if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
+    }
+
+    typedef Ch (*TakeFunc)(InputByteStream& is);
+    InputByteStream* is_;
+    UTFType type_;
+    Ch current_;
+    TakeFunc takeFunc_;
+    bool hasBOM_;
+};
+
+//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
+/*!
+    \tparam CharType Type of character for writing.
+    \tparam OutputByteStream type of output byte stream to be wrapped.
+*/
+template <typename CharType, typename OutputByteStream>
+class AutoUTFOutputStream {
+    RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+public:
+    typedef CharType Ch;
+
+    //! Constructor.
+    /*!
+        \param os output stream to be wrapped.
+        \param type UTF encoding type.
+        \param putBOM Whether to write BOM at the beginning of the stream.
+    */
+    AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
+        RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
+
+        // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
+        if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
+        if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
+
+        static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
+        putFunc_ = f[type_];
+
+        if (putBOM)
+            PutBOM();
+    }
+
+    UTFType GetType() const { return type_; }
+
+    void Put(Ch c) { putFunc_(*os_, c); }
+    void Flush() { os_->Flush(); } 
+
+    // Not implemented
+    Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
+    Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
+    size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+    AutoUTFOutputStream(const AutoUTFOutputStream&);
+    AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
+
+    void PutBOM() { 
+        typedef void (*PutBOMFunc)(OutputByteStream&);
+        static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
+        f[type_](*os_);
+    }
+
+    typedef void (*PutFunc)(OutputByteStream&, Ch);
+
+    OutputByteStream* os_;
+    UTFType type_;
+    PutFunc putFunc_;
+};
+
+#undef RAPIDJSON_ENCODINGS_FUNC
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_FILESTREAM_H_

+ 716 - 0
jni/base/rapidjson/encodings.h

@@ -0,0 +1,716 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ENCODINGS_H_
+#define RAPIDJSON_ENCODINGS_H_
+
+#include "rapidjson.h"
+
+#if defined(_MSC_VER) && !defined(__clang__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
+RAPIDJSON_DIAG_OFF(4702)  // unreachable code
+#elif defined(__GNUC__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+RAPIDJSON_DIAG_OFF(overflow)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// Encoding
+
+/*! \class rapidjson::Encoding
+    \brief Concept for encoding of Unicode characters.
+
+\code
+concept Encoding {
+    typename Ch;    //! Type of character. A "character" is actually a code unit in unicode's definition.
+
+    enum { supportUnicode = 1 }; // or 0 if not supporting unicode
+
+    //! \brief Encode a Unicode codepoint to an output stream.
+    //! \param os Output stream.
+    //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
+    template<typename OutputStream>
+    static void Encode(OutputStream& os, unsigned codepoint);
+
+    //! \brief Decode a Unicode codepoint from an input stream.
+    //! \param is Input stream.
+    //! \param codepoint Output of the unicode codepoint.
+    //! \return true if a valid codepoint can be decoded from the stream.
+    template <typename InputStream>
+    static bool Decode(InputStream& is, unsigned* codepoint);
+
+    //! \brief Validate one Unicode codepoint from an encoded stream.
+    //! \param is Input stream to obtain codepoint.
+    //! \param os Output for copying one codepoint.
+    //! \return true if it is valid.
+    //! \note This function just validating and copying the codepoint without actually decode it.
+    template <typename InputStream, typename OutputStream>
+    static bool Validate(InputStream& is, OutputStream& os);
+
+    // The following functions are deal with byte streams.
+
+    //! Take a character from input byte stream, skip BOM if exist.
+    template <typename InputByteStream>
+    static CharType TakeBOM(InputByteStream& is);
+
+    //! Take a character from input byte stream.
+    template <typename InputByteStream>
+    static Ch Take(InputByteStream& is);
+
+    //! Put BOM to output byte stream.
+    template <typename OutputByteStream>
+    static void PutBOM(OutputByteStream& os);
+
+    //! Put a character to output byte stream.
+    template <typename OutputByteStream>
+    static void Put(OutputByteStream& os, Ch c);
+};
+\endcode
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF8
+
+//! UTF-8 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-8
+    http://tools.ietf.org/html/rfc3629
+    \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
+    \note implements Encoding concept
+*/
+template<typename CharType = char>
+struct UTF8 {
+    typedef CharType Ch;
+
+    enum { supportUnicode = 1 };
+
+    template<typename OutputStream>
+    static void Encode(OutputStream& os, unsigned codepoint) {
+        if (codepoint <= 0x7F) 
+            os.Put(static_cast<Ch>(codepoint & 0xFF));
+        else if (codepoint <= 0x7FF) {
+            os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
+            os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
+        }
+        else if (codepoint <= 0xFFFF) {
+            os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
+            os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+            os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+        }
+        else {
+            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+            os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
+            os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
+            os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+            os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+        }
+    }
+
+    template<typename OutputStream>
+    static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+        if (codepoint <= 0x7F) 
+            PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
+        else if (codepoint <= 0x7FF) {
+            PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
+            PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
+        }
+        else if (codepoint <= 0xFFFF) {
+            PutUnsafe(os, static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
+            PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+            PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+        }
+        else {
+            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+            PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
+            PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
+            PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+            PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+        }
+    }
+
+    template <typename InputStream>
+    static bool Decode(InputStream& is, unsigned* codepoint) {
+#define RAPIDJSON_COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
+#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
+#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70)
+        typename InputStream::Ch c = is.Take();
+        if (!(c & 0x80)) {
+            *codepoint = static_cast<unsigned char>(c);
+            return true;
+        }
+
+        unsigned char type = GetRange(static_cast<unsigned char>(c));
+        if (type >= 32) {
+            *codepoint = 0;
+        } else {
+            *codepoint = (0xFFu >> type) & static_cast<unsigned char>(c);
+        }
+        bool result = true;
+        switch (type) {
+        case 2: RAPIDJSON_TAIL(); return result;
+        case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
+        case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result;
+        case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
+        case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
+        case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result;
+        case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
+        default: return false;
+        }
+#undef RAPIDJSON_COPY
+#undef RAPIDJSON_TRANS
+#undef RAPIDJSON_TAIL
+    }
+
+    template <typename InputStream, typename OutputStream>
+    static bool Validate(InputStream& is, OutputStream& os) {
+#define RAPIDJSON_COPY() os.Put(c = is.Take())
+#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
+#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70)
+        Ch c;
+        RAPIDJSON_COPY();
+        if (!(c & 0x80))
+            return true;
+
+        bool result = true;
+        switch (GetRange(static_cast<unsigned char>(c))) {
+        case 2: RAPIDJSON_TAIL(); return result;
+        case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
+        case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result;
+        case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
+        case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
+        case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result;
+        case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
+        default: return false;
+        }
+#undef RAPIDJSON_COPY
+#undef RAPIDJSON_TRANS
+#undef RAPIDJSON_TAIL
+    }
+
+    static unsigned char GetRange(unsigned char c) {
+        // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
+        // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
+        static const unsigned char type[] = {
+            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+            0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+            0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+            0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+            0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+            8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+            10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
+        };
+        return type[c];
+    }
+
+    template <typename InputByteStream>
+    static CharType TakeBOM(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        typename InputByteStream::Ch c = Take(is);
+        if (static_cast<unsigned char>(c) != 0xEFu) return c;
+        c = is.Take();
+        if (static_cast<unsigned char>(c) != 0xBBu) return c;
+        c = is.Take();
+        if (static_cast<unsigned char>(c) != 0xBFu) return c;
+        c = is.Take();
+        return c;
+    }
+
+    template <typename InputByteStream>
+    static Ch Take(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        return static_cast<Ch>(is.Take());
+    }
+
+    template <typename OutputByteStream>
+    static void PutBOM(OutputByteStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xEFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu));
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xBFu));
+    }
+
+    template <typename OutputByteStream>
+    static void Put(OutputByteStream& os, Ch c) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>(c));
+    }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF16
+
+//! UTF-16 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-16
+    http://tools.ietf.org/html/rfc2781
+    \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
+    \note implements Encoding concept
+
+    \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
+    For streaming, use UTF16LE and UTF16BE, which handle endianness.
+*/
+template<typename CharType = wchar_t>
+struct UTF16 {
+    typedef CharType Ch;
+    RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
+
+    enum { supportUnicode = 1 };
+
+    template<typename OutputStream>
+    static void Encode(OutputStream& os, unsigned codepoint) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
+        if (codepoint <= 0xFFFF) {
+            RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair 
+            os.Put(static_cast<typename OutputStream::Ch>(codepoint));
+        }
+        else {
+            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+            unsigned v = codepoint - 0x10000;
+            os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
+            os.Put(static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));
+        }
+    }
+
+
+    template<typename OutputStream>
+    static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
+        if (codepoint <= 0xFFFF) {
+            RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair 
+            PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint));
+        }
+        else {
+            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+            unsigned v = codepoint - 0x10000;
+            PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
+            PutUnsafe(os, static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));
+        }
+    }
+
+    template <typename InputStream>
+    static bool Decode(InputStream& is, unsigned* codepoint) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
+        typename InputStream::Ch c = is.Take();
+        if (c < 0xD800 || c > 0xDFFF) {
+            *codepoint = static_cast<unsigned>(c);
+            return true;
+        }
+        else if (c <= 0xDBFF) {
+            *codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10;
+            c = is.Take();
+            *codepoint |= (static_cast<unsigned>(c) & 0x3FF);
+            *codepoint += 0x10000;
+            return c >= 0xDC00 && c <= 0xDFFF;
+        }
+        return false;
+    }
+
+    template <typename InputStream, typename OutputStream>
+    static bool Validate(InputStream& is, OutputStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
+        typename InputStream::Ch c;
+        os.Put(static_cast<typename OutputStream::Ch>(c = is.Take()));
+        if (c < 0xD800 || c > 0xDFFF)
+            return true;
+        else if (c <= 0xDBFF) {
+            os.Put(c = is.Take());
+            return c >= 0xDC00 && c <= 0xDFFF;
+        }
+        return false;
+    }
+};
+
+//! UTF-16 little endian encoding.
+template<typename CharType = wchar_t>
+struct UTF16LE : UTF16<CharType> {
+    template <typename InputByteStream>
+    static CharType TakeBOM(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        CharType c = Take(is);
+        return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
+    }
+
+    template <typename InputByteStream>
+    static CharType Take(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        unsigned c = static_cast<uint8_t>(is.Take());
+        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
+        return static_cast<CharType>(c);
+    }
+
+    template <typename OutputByteStream>
+    static void PutBOM(OutputByteStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
+    }
+
+    template <typename OutputByteStream>
+    static void Put(OutputByteStream& os, CharType c) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
+    }
+};
+
+//! UTF-16 big endian encoding.
+template<typename CharType = wchar_t>
+struct UTF16BE : UTF16<CharType> {
+    template <typename InputByteStream>
+    static CharType TakeBOM(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        CharType c = Take(is);
+        return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
+    }
+
+    template <typename InputByteStream>
+    static CharType Take(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
+        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
+        return static_cast<CharType>(c);
+    }
+
+    template <typename OutputByteStream>
+    static void PutBOM(OutputByteStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
+    }
+
+    template <typename OutputByteStream>
+    static void Put(OutputByteStream& os, CharType c) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
+    }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF32
+
+//! UTF-32 encoding. 
+/*! http://en.wikipedia.org/wiki/UTF-32
+    \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
+    \note implements Encoding concept
+
+    \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
+    For streaming, use UTF32LE and UTF32BE, which handle endianness.
+*/
+template<typename CharType = unsigned>
+struct UTF32 {
+    typedef CharType Ch;
+    RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
+
+    enum { supportUnicode = 1 };
+
+    template<typename OutputStream>
+    static void Encode(OutputStream& os, unsigned codepoint) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
+        RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+        os.Put(codepoint);
+    }
+
+    template<typename OutputStream>
+    static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
+        RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+        PutUnsafe(os, codepoint);
+    }
+
+    template <typename InputStream>
+    static bool Decode(InputStream& is, unsigned* codepoint) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
+        Ch c = is.Take();
+        *codepoint = c;
+        return c <= 0x10FFFF;
+    }
+
+    template <typename InputStream, typename OutputStream>
+    static bool Validate(InputStream& is, OutputStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
+        Ch c;
+        os.Put(c = is.Take());
+        return c <= 0x10FFFF;
+    }
+};
+
+//! UTF-32 little endian enocoding.
+template<typename CharType = unsigned>
+struct UTF32LE : UTF32<CharType> {
+    template <typename InputByteStream>
+    static CharType TakeBOM(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        CharType c = Take(is);
+        return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
+    }
+
+    template <typename InputByteStream>
+    static CharType Take(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        unsigned c = static_cast<uint8_t>(is.Take());
+        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
+        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
+        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
+        return static_cast<CharType>(c);
+    }
+
+    template <typename OutputByteStream>
+    static void PutBOM(OutputByteStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
+        os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
+        os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
+    }
+
+    template <typename OutputByteStream>
+    static void Put(OutputByteStream& os, CharType c) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
+    }
+};
+
+//! UTF-32 big endian encoding.
+template<typename CharType = unsigned>
+struct UTF32BE : UTF32<CharType> {
+    template <typename InputByteStream>
+    static CharType TakeBOM(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        CharType c = Take(is);
+        return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c; 
+    }
+
+    template <typename InputByteStream>
+    static CharType Take(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
+        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
+        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
+        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
+        return static_cast<CharType>(c);
+    }
+
+    template <typename OutputByteStream>
+    static void PutBOM(OutputByteStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
+        os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
+    }
+
+    template <typename OutputByteStream>
+    static void Put(OutputByteStream& os, CharType c) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
+    }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// ASCII
+
+//! ASCII encoding.
+/*! http://en.wikipedia.org/wiki/ASCII
+    \tparam CharType Code unit for storing 7-bit ASCII data. Default is char.
+    \note implements Encoding concept
+*/
+template<typename CharType = char>
+struct ASCII {
+    typedef CharType Ch;
+
+    enum { supportUnicode = 0 };
+
+    template<typename OutputStream>
+    static void Encode(OutputStream& os, unsigned codepoint) {
+        RAPIDJSON_ASSERT(codepoint <= 0x7F);
+        os.Put(static_cast<Ch>(codepoint & 0xFF));
+    }
+
+    template<typename OutputStream>
+    static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+        RAPIDJSON_ASSERT(codepoint <= 0x7F);
+        PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
+    }
+
+    template <typename InputStream>
+    static bool Decode(InputStream& is, unsigned* codepoint) {
+        uint8_t c = static_cast<uint8_t>(is.Take());
+        *codepoint = c;
+        return c <= 0X7F;
+    }
+
+    template <typename InputStream, typename OutputStream>
+    static bool Validate(InputStream& is, OutputStream& os) {
+        uint8_t c = static_cast<uint8_t>(is.Take());
+        os.Put(static_cast<typename OutputStream::Ch>(c));
+        return c <= 0x7F;
+    }
+
+    template <typename InputByteStream>
+    static CharType TakeBOM(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        uint8_t c = static_cast<uint8_t>(Take(is));
+        return static_cast<Ch>(c);
+    }
+
+    template <typename InputByteStream>
+    static Ch Take(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        return static_cast<Ch>(is.Take());
+    }
+
+    template <typename OutputByteStream>
+    static void PutBOM(OutputByteStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        (void)os;
+    }
+
+    template <typename OutputByteStream>
+    static void Put(OutputByteStream& os, Ch c) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>(c));
+    }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// AutoUTF
+
+//! Runtime-specified UTF encoding type of a stream.
+enum UTFType {
+    kUTF8 = 0,      //!< UTF-8.
+    kUTF16LE = 1,   //!< UTF-16 little endian.
+    kUTF16BE = 2,   //!< UTF-16 big endian.
+    kUTF32LE = 3,   //!< UTF-32 little endian.
+    kUTF32BE = 4    //!< UTF-32 big endian.
+};
+
+//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
+/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
+*/
+template<typename CharType>
+struct AutoUTF {
+    typedef CharType Ch;
+
+    enum { supportUnicode = 1 };
+
+#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
+
+    template<typename OutputStream>
+    static RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) {
+        typedef void (*EncodeFunc)(OutputStream&, unsigned);
+        static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
+        (*f[os.GetType()])(os, codepoint);
+    }
+
+    template<typename OutputStream>
+    static RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+        typedef void (*EncodeFunc)(OutputStream&, unsigned);
+        static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) };
+        (*f[os.GetType()])(os, codepoint);
+    }
+
+    template <typename InputStream>
+    static RAPIDJSON_FORCEINLINE bool Decode(InputStream& is, unsigned* codepoint) {
+        typedef bool (*DecodeFunc)(InputStream&, unsigned*);
+        static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
+        return (*f[is.GetType()])(is, codepoint);
+    }
+
+    template <typename InputStream, typename OutputStream>
+    static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
+        typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
+        static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
+        return (*f[is.GetType()])(is, os);
+    }
+
+#undef RAPIDJSON_ENCODINGS_FUNC
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Transcoder
+
+//! Encoding conversion.
+template<typename SourceEncoding, typename TargetEncoding>
+struct Transcoder {
+    //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
+    template<typename InputStream, typename OutputStream>
+    static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {
+        unsigned codepoint;
+        if (!SourceEncoding::Decode(is, &codepoint))
+            return false;
+        TargetEncoding::Encode(os, codepoint);
+        return true;
+    }
+
+    template<typename InputStream, typename OutputStream>
+    static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
+        unsigned codepoint;
+        if (!SourceEncoding::Decode(is, &codepoint))
+            return false;
+        TargetEncoding::EncodeUnsafe(os, codepoint);
+        return true;
+    }
+
+    //! Validate one Unicode codepoint from an encoded stream.
+    template<typename InputStream, typename OutputStream>
+    static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
+        return Transcode(is, os);   // Since source/target encoding is different, must transcode.
+    }
+};
+
+// Forward declaration.
+template<typename Stream>
+inline void PutUnsafe(Stream& stream, typename Stream::Ch c);
+
+//! Specialization of Transcoder with same source and target encoding.
+template<typename Encoding>
+struct Transcoder<Encoding, Encoding> {
+    template<typename InputStream, typename OutputStream>
+    static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {
+        os.Put(is.Take());  // Just copy one code unit. This semantic is different from primary template class.
+        return true;
+    }
+    
+    template<typename InputStream, typename OutputStream>
+    static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
+        PutUnsafe(os, is.Take());  // Just copy one code unit. This semantic is different from primary template class.
+        return true;
+    }
+    
+    template<typename InputStream, typename OutputStream>
+    static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
+        return Encoding::Validate(is, os);  // source/target encoding are the same
+    }
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__GNUC__) || (defined(_MSC_VER) && !defined(__clang__))
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_ENCODINGS_H_

+ 74 - 0
jni/base/rapidjson/error/en.h

@@ -0,0 +1,74 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ERROR_EN_H_
+#define RAPIDJSON_ERROR_EN_H_
+
+#include "error.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(switch-enum)
+RAPIDJSON_DIAG_OFF(covered-switch-default)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Maps error code of parsing into error message.
+/*!
+    \ingroup RAPIDJSON_ERRORS
+    \param parseErrorCode Error code obtained in parsing.
+    \return the error message.
+    \note User can make a copy of this function for localization.
+        Using switch-case is safer for future modification of error codes.
+*/
+inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
+    switch (parseErrorCode) {
+        case kParseErrorNone:                           return RAPIDJSON_ERROR_STRING("No error.");
+
+        case kParseErrorDocumentEmpty:                  return RAPIDJSON_ERROR_STRING("The document is empty.");
+        case kParseErrorDocumentRootNotSingular:        return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values.");
+    
+        case kParseErrorValueInvalid:                   return RAPIDJSON_ERROR_STRING("Invalid value.");
+    
+        case kParseErrorObjectMissName:                 return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
+        case kParseErrorObjectMissColon:                return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
+        case kParseErrorObjectMissCommaOrCurlyBracket:  return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
+    
+        case kParseErrorArrayMissCommaOrSquareBracket:  return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
+
+        case kParseErrorStringUnicodeEscapeInvalidHex:  return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
+        case kParseErrorStringUnicodeSurrogateInvalid:  return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
+        case kParseErrorStringEscapeInvalid:            return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
+        case kParseErrorStringMissQuotationMark:        return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
+        case kParseErrorStringInvalidEncoding:          return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
+
+        case kParseErrorNumberTooBig:                   return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
+        case kParseErrorNumberMissFraction:             return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
+        case kParseErrorNumberMissExponent:             return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
+
+        case kParseErrorTermination:                    return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
+        case kParseErrorUnspecificSyntaxError:          return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
+
+        default:                                        return RAPIDJSON_ERROR_STRING("Unknown error.");
+    }
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_ERROR_EN_H_

+ 161 - 0
jni/base/rapidjson/error/error.h

@@ -0,0 +1,161 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ERROR_ERROR_H_
+#define RAPIDJSON_ERROR_ERROR_H_
+
+#include "../rapidjson.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+/*! \file error.h */
+
+/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ERROR_CHARTYPE
+
+//! Character type of error messages.
+/*! \ingroup RAPIDJSON_ERRORS
+    The default character type is \c char.
+    On Windows, user can define this macro as \c TCHAR for supporting both
+    unicode/non-unicode settings.
+*/
+#ifndef RAPIDJSON_ERROR_CHARTYPE
+#define RAPIDJSON_ERROR_CHARTYPE char
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ERROR_STRING
+
+//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
+/*! \ingroup RAPIDJSON_ERRORS
+    By default this conversion macro does nothing.
+    On Windows, user can define this macro as \c _T(x) for supporting both
+    unicode/non-unicode settings.
+*/
+#ifndef RAPIDJSON_ERROR_STRING
+#define RAPIDJSON_ERROR_STRING(x) x
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseErrorCode
+
+//! Error code of parsing.
+/*! \ingroup RAPIDJSON_ERRORS
+    \see GenericReader::Parse, GenericReader::GetParseErrorCode
+*/
+enum ParseErrorCode {
+    kParseErrorNone = 0,                        //!< No error.
+
+    kParseErrorDocumentEmpty,                   //!< The document is empty.
+    kParseErrorDocumentRootNotSingular,         //!< The document root must not follow by other values.
+
+    kParseErrorValueInvalid,                    //!< Invalid value.
+
+    kParseErrorObjectMissName,                  //!< Missing a name for object member.
+    kParseErrorObjectMissColon,                 //!< Missing a colon after a name of object member.
+    kParseErrorObjectMissCommaOrCurlyBracket,   //!< Missing a comma or '}' after an object member.
+
+    kParseErrorArrayMissCommaOrSquareBracket,   //!< Missing a comma or ']' after an array element.
+
+    kParseErrorStringUnicodeEscapeInvalidHex,   //!< Incorrect hex digit after \\u escape in string.
+    kParseErrorStringUnicodeSurrogateInvalid,   //!< The surrogate pair in string is invalid.
+    kParseErrorStringEscapeInvalid,             //!< Invalid escape character in string.
+    kParseErrorStringMissQuotationMark,         //!< Missing a closing quotation mark in string.
+    kParseErrorStringInvalidEncoding,           //!< Invalid encoding in string.
+
+    kParseErrorNumberTooBig,                    //!< Number too big to be stored in double.
+    kParseErrorNumberMissFraction,              //!< Miss fraction part in number.
+    kParseErrorNumberMissExponent,              //!< Miss exponent in number.
+
+    kParseErrorTermination,                     //!< Parsing was terminated.
+    kParseErrorUnspecificSyntaxError            //!< Unspecific syntax error.
+};
+
+//! Result of parsing (wraps ParseErrorCode)
+/*!
+    \ingroup RAPIDJSON_ERRORS
+    \code
+        Document doc;
+        ParseResult ok = doc.Parse("[42]");
+        if (!ok) {
+            fprintf(stderr, "JSON parse error: %s (%u)",
+                    GetParseError_En(ok.Code()), ok.Offset());
+            exit(EXIT_FAILURE);
+        }
+    \endcode
+    \see GenericReader::Parse, GenericDocument::Parse
+*/
+struct ParseResult {
+    //!! Unspecified boolean type
+    typedef bool (ParseResult::*BooleanType)() const;
+public:
+    //! Default constructor, no error.
+    ParseResult() : code_(kParseErrorNone), offset_(0) {}
+    //! Constructor to set an error.
+    ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
+
+    //! Get the error code.
+    ParseErrorCode Code() const { return code_; }
+    //! Get the error offset, if \ref IsError(), 0 otherwise.
+    size_t Offset() const { return offset_; }
+
+    //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError().
+    operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; }
+    //! Whether the result is an error.
+    bool IsError() const { return code_ != kParseErrorNone; }
+
+    bool operator==(const ParseResult& that) const { return code_ == that.code_; }
+    bool operator==(ParseErrorCode code) const { return code_ == code; }
+    friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
+
+    bool operator!=(const ParseResult& that) const { return !(*this == that); }
+    bool operator!=(ParseErrorCode code) const { return !(*this == code); }
+    friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; }
+
+    //! Reset error code.
+    void Clear() { Set(kParseErrorNone); }
+    //! Update error code and offset.
+    void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }
+
+private:
+    ParseErrorCode code_;
+    size_t offset_;
+};
+
+//! Function pointer type of GetParseError().
+/*! \ingroup RAPIDJSON_ERRORS
+
+    This is the prototype for \c GetParseError_X(), where \c X is a locale.
+    User can dynamically change locale in runtime, e.g.:
+\code
+    GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
+    const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
+\endcode
+*/
+typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_ERROR_ERROR_H_

+ 99 - 0
jni/base/rapidjson/filereadstream.h

@@ -0,0 +1,99 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_FILEREADSTREAM_H_
+#define RAPIDJSON_FILEREADSTREAM_H_
+
+#include "stream.h"
+#include <cstdio>
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(unreachable-code)
+RAPIDJSON_DIAG_OFF(missing-noreturn)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! File byte stream for input using fread().
+/*!
+    \note implements Stream concept
+*/
+class FileReadStream {
+public:
+    typedef char Ch;    //!< Character type (byte).
+
+    //! Constructor.
+    /*!
+        \param fp File pointer opened for read.
+        \param buffer user-supplied buffer.
+        \param bufferSize size of buffer in bytes. Must >=4 bytes.
+    */
+    FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 
+        RAPIDJSON_ASSERT(fp_ != 0);
+        RAPIDJSON_ASSERT(bufferSize >= 4);
+        Read();
+    }
+
+    Ch Peek() const { return *current_; }
+    Ch Take() { Ch c = *current_; Read(); return c; }
+    size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
+
+    // Not implemented
+    void Put(Ch) { RAPIDJSON_ASSERT(false); }
+    void Flush() { RAPIDJSON_ASSERT(false); } 
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+    // For encoding detection only.
+    const Ch* Peek4() const {
+        return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;
+    }
+
+private:
+    void Read() {
+        if (current_ < bufferLast_)
+            ++current_;
+        else if (!eof_) {
+            count_ += readCount_;
+            readCount_ = std::fread(buffer_, 1, bufferSize_, fp_);
+            bufferLast_ = buffer_ + readCount_ - 1;
+            current_ = buffer_;
+
+            if (readCount_ < bufferSize_) {
+                buffer_[readCount_] = '\0';
+                ++bufferLast_;
+                eof_ = true;
+            }
+        }
+    }
+
+    std::FILE* fp_;
+    Ch *buffer_;
+    size_t bufferSize_;
+    Ch *bufferLast_;
+    Ch *current_;
+    size_t readCount_;
+    size_t count_;  //!< Number of characters read
+    bool eof_;
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_FILESTREAM_H_

+ 104 - 0
jni/base/rapidjson/filewritestream.h

@@ -0,0 +1,104 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_FILEWRITESTREAM_H_
+#define RAPIDJSON_FILEWRITESTREAM_H_
+
+#include "stream.h"
+#include <cstdio>
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(unreachable-code)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Wrapper of C file stream for output using fwrite().
+/*!
+    \note implements Stream concept
+*/
+class FileWriteStream {
+public:
+    typedef char Ch;    //!< Character type. Only support char.
+
+    FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { 
+        RAPIDJSON_ASSERT(fp_ != 0);
+    }
+
+    void Put(char c) { 
+        if (current_ >= bufferEnd_)
+            Flush();
+
+        *current_++ = c;
+    }
+
+    void PutN(char c, size_t n) {
+        size_t avail = static_cast<size_t>(bufferEnd_ - current_);
+        while (n > avail) {
+            std::memset(current_, c, avail);
+            current_ += avail;
+            Flush();
+            n -= avail;
+            avail = static_cast<size_t>(bufferEnd_ - current_);
+        }
+
+        if (n > 0) {
+            std::memset(current_, c, n);
+            current_ += n;
+        }
+    }
+
+    void Flush() {
+        if (current_ != buffer_) {
+            size_t result = std::fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
+            if (result < static_cast<size_t>(current_ - buffer_)) {
+                // failure deliberately ignored at this time
+                // added to avoid warn_unused_result build errors
+            }
+            current_ = buffer_;
+        }
+    }
+
+    // Not implemented
+    char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
+    char Take() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
+    char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+    // Prohibit copy constructor & assignment operator.
+    FileWriteStream(const FileWriteStream&);
+    FileWriteStream& operator=(const FileWriteStream&);
+
+    std::FILE* fp_;
+    char *buffer_;
+    char *bufferEnd_;
+    char *current_;
+};
+
+//! Implement specialized version of PutN() with memset() for better performance.
+template<>
+inline void PutN(FileWriteStream& stream, char c, size_t n) {
+    stream.PutN(c, n);
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_FILESTREAM_H_

+ 151 - 0
jni/base/rapidjson/fwd.h

@@ -0,0 +1,151 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_FWD_H_
+#define RAPIDJSON_FWD_H_
+
+#include "rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+// encodings.h
+
+template<typename CharType> struct UTF8;
+template<typename CharType> struct UTF16;
+template<typename CharType> struct UTF16BE;
+template<typename CharType> struct UTF16LE;
+template<typename CharType> struct UTF32;
+template<typename CharType> struct UTF32BE;
+template<typename CharType> struct UTF32LE;
+template<typename CharType> struct ASCII;
+template<typename CharType> struct AutoUTF;
+
+template<typename SourceEncoding, typename TargetEncoding>
+struct Transcoder;
+
+// allocators.h
+
+class CrtAllocator;
+
+template <typename BaseAllocator>
+class MemoryPoolAllocator;
+
+// stream.h
+
+template <typename Encoding>
+struct GenericStringStream;
+
+typedef GenericStringStream<UTF8<char> > StringStream;
+
+template <typename Encoding>
+struct GenericInsituStringStream;
+
+typedef GenericInsituStringStream<UTF8<char> > InsituStringStream;
+
+// stringbuffer.h
+
+template <typename Encoding, typename Allocator>
+class GenericStringBuffer;
+
+typedef GenericStringBuffer<UTF8<char>, CrtAllocator> StringBuffer;
+
+// filereadstream.h
+
+class FileReadStream;
+
+// filewritestream.h
+
+class FileWriteStream;
+
+// memorybuffer.h
+
+template <typename Allocator>
+struct GenericMemoryBuffer;
+
+typedef GenericMemoryBuffer<CrtAllocator> MemoryBuffer;
+
+// memorystream.h
+
+struct MemoryStream;
+
+// reader.h
+
+template<typename Encoding, typename Derived>
+struct BaseReaderHandler;
+
+template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator>
+class GenericReader;
+
+typedef GenericReader<UTF8<char>, UTF8<char>, CrtAllocator> Reader;
+
+// writer.h
+
+template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
+class Writer;
+
+// prettywriter.h
+
+template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
+class PrettyWriter;
+
+// document.h
+
+template <typename Encoding, typename Allocator> 
+class GenericMember;
+
+template <bool Const, typename Encoding, typename Allocator>
+class GenericMemberIterator;
+
+template<typename CharType>
+struct GenericStringRef;
+
+template <typename Encoding, typename Allocator> 
+class GenericValue;
+
+typedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Value;
+
+template <typename Encoding, typename Allocator, typename StackAllocator>
+class GenericDocument;
+
+typedef GenericDocument<UTF8<char>, MemoryPoolAllocator<CrtAllocator>, CrtAllocator> Document;
+
+// pointer.h
+
+template <typename ValueType, typename Allocator>
+class GenericPointer;
+
+typedef GenericPointer<Value, CrtAllocator> Pointer;
+
+// schema.h
+
+template <typename SchemaDocumentType>
+class IGenericRemoteSchemaDocumentProvider;
+
+template <typename ValueT, typename Allocator>
+class GenericSchemaDocument;
+
+typedef GenericSchemaDocument<Value, CrtAllocator> SchemaDocument;
+typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
+
+template <
+    typename SchemaDocumentType,
+    typename OutputHandler,
+    typename StateAllocator>
+class GenericSchemaValidator;
+
+typedef GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<char>, void>, CrtAllocator> SchemaValidator;
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_RAPIDJSONFWD_H_

+ 290 - 0
jni/base/rapidjson/internal/biginteger.h

@@ -0,0 +1,290 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_BIGINTEGER_H_
+#define RAPIDJSON_BIGINTEGER_H_
+
+#include "../rapidjson.h"
+
+#if defined(_MSC_VER) && !__INTEL_COMPILER && defined(_M_AMD64)
+#include <intrin.h> // for _umul128
+#pragma intrinsic(_umul128)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+class BigInteger {
+public:
+    typedef uint64_t Type;
+
+    BigInteger(const BigInteger& rhs) : count_(rhs.count_) {
+        std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
+    }
+
+    explicit BigInteger(uint64_t u) : count_(1) {
+        digits_[0] = u;
+    }
+
+    BigInteger(const char* decimals, size_t length) : count_(1) {
+        RAPIDJSON_ASSERT(length > 0);
+        digits_[0] = 0;
+        size_t i = 0;
+        const size_t kMaxDigitPerIteration = 19;  // 2^64 = 18446744073709551616 > 10^19
+        while (length >= kMaxDigitPerIteration) {
+            AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
+            length -= kMaxDigitPerIteration;
+            i += kMaxDigitPerIteration;
+        }
+
+        if (length > 0)
+            AppendDecimal64(decimals + i, decimals + i + length);
+    }
+    
+    BigInteger& operator=(const BigInteger &rhs)
+    {
+        if (this != &rhs) {
+            count_ = rhs.count_;
+            std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
+        }
+        return *this;
+    }
+    
+    BigInteger& operator=(uint64_t u) {
+        digits_[0] = u;            
+        count_ = 1;
+        return *this;
+    }
+
+    BigInteger& operator+=(uint64_t u) {
+        Type backup = digits_[0];
+        digits_[0] += u;
+        for (size_t i = 0; i < count_ - 1; i++) {
+            if (digits_[i] >= backup)
+                return *this; // no carry
+            backup = digits_[i + 1];
+            digits_[i + 1] += 1;
+        }
+
+        // Last carry
+        if (digits_[count_ - 1] < backup)
+            PushBack(1);
+
+        return *this;
+    }
+
+    BigInteger& operator*=(uint64_t u) {
+        if (u == 0) return *this = 0;
+        if (u == 1) return *this;
+        if (*this == 1) return *this = u;
+
+        uint64_t k = 0;
+        for (size_t i = 0; i < count_; i++) {
+            uint64_t hi;
+            digits_[i] = MulAdd64(digits_[i], u, k, &hi);
+            k = hi;
+        }
+        
+        if (k > 0)
+            PushBack(k);
+
+        return *this;
+    }
+
+    BigInteger& operator*=(uint32_t u) {
+        if (u == 0) return *this = 0;
+        if (u == 1) return *this;
+        if (*this == 1) return *this = u;
+
+        uint64_t k = 0;
+        for (size_t i = 0; i < count_; i++) {
+            const uint64_t c = digits_[i] >> 32;
+            const uint64_t d = digits_[i] & 0xFFFFFFFF;
+            const uint64_t uc = u * c;
+            const uint64_t ud = u * d;
+            const uint64_t p0 = ud + k;
+            const uint64_t p1 = uc + (p0 >> 32);
+            digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
+            k = p1 >> 32;
+        }
+        
+        if (k > 0)
+            PushBack(k);
+
+        return *this;
+    }
+
+    BigInteger& operator<<=(size_t shift) {
+        if (IsZero() || shift == 0) return *this;
+
+        size_t offset = shift / kTypeBit;
+        size_t interShift = shift % kTypeBit;
+        RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
+
+        if (interShift == 0) {
+            std::memmove(digits_ + offset, digits_, count_ * sizeof(Type));
+            count_ += offset;
+        }
+        else {
+            digits_[count_] = 0;
+            for (size_t i = count_; i > 0; i--)
+                digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
+            digits_[offset] = digits_[0] << interShift;
+            count_ += offset;
+            if (digits_[count_])
+                count_++;
+        }
+
+        std::memset(digits_, 0, offset * sizeof(Type));
+
+        return *this;
+    }
+
+    bool operator==(const BigInteger& rhs) const {
+        return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
+    }
+
+    bool operator==(const Type rhs) const {
+        return count_ == 1 && digits_[0] == rhs;
+    }
+
+    BigInteger& MultiplyPow5(unsigned exp) {
+        static const uint32_t kPow5[12] = {
+            5,
+            5 * 5,
+            5 * 5 * 5,
+            5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
+        };
+        if (exp == 0) return *this;
+        for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
+        for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13
+        if (exp > 0)                 *this *= kPow5[exp - 1];
+        return *this;
+    }
+
+    // Compute absolute difference of this and rhs.
+    // Assume this != rhs
+    bool Difference(const BigInteger& rhs, BigInteger* out) const {
+        int cmp = Compare(rhs);
+        RAPIDJSON_ASSERT(cmp != 0);
+        const BigInteger *a, *b;  // Makes a > b
+        bool ret;
+        if (cmp < 0) { a = &rhs; b = this; ret = true; }
+        else         { a = this; b = &rhs; ret = false; }
+
+        Type borrow = 0;
+        for (size_t i = 0; i < a->count_; i++) {
+            Type d = a->digits_[i] - borrow;
+            if (i < b->count_)
+                d -= b->digits_[i];
+            borrow = (d > a->digits_[i]) ? 1 : 0;
+            out->digits_[i] = d;
+            if (d != 0)
+                out->count_ = i + 1;
+        }
+
+        return ret;
+    }
+
+    int Compare(const BigInteger& rhs) const {
+        if (count_ != rhs.count_)
+            return count_ < rhs.count_ ? -1 : 1;
+
+        for (size_t i = count_; i-- > 0;)
+            if (digits_[i] != rhs.digits_[i])
+                return digits_[i] < rhs.digits_[i] ? -1 : 1;
+
+        return 0;
+    }
+
+    size_t GetCount() const { return count_; }
+    Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; }
+    bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
+
+private:
+    void AppendDecimal64(const char* begin, const char* end) {
+        uint64_t u = ParseUint64(begin, end);
+        if (IsZero())
+            *this = u;
+        else {
+            unsigned exp = static_cast<unsigned>(end - begin);
+            (MultiplyPow5(exp) <<= exp) += u;   // *this = *this * 10^exp + u
+        }
+    }
+
+    void PushBack(Type digit) {
+        RAPIDJSON_ASSERT(count_ < kCapacity);
+        digits_[count_++] = digit;
+    }
+
+    static uint64_t ParseUint64(const char* begin, const char* end) {
+        uint64_t r = 0;
+        for (const char* p = begin; p != end; ++p) {
+            RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
+            r = r * 10u + static_cast<unsigned>(*p - '0');
+        }
+        return r;
+    }
+
+    // Assume a * b + k < 2^128
+    static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+        uint64_t low = _umul128(a, b, outHigh) + k;
+        if (low < k)
+            (*outHigh)++;
+        return low;
+#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
+        __extension__ typedef unsigned __int128 uint128;
+        uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
+        p += k;
+        *outHigh = static_cast<uint64_t>(p >> 64);
+        return static_cast<uint64_t>(p);
+#else
+        const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
+        uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
+        x1 += (x0 >> 32); // can't give carry
+        x1 += x2;
+        if (x1 < x2)
+            x3 += (static_cast<uint64_t>(1) << 32);
+        uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
+        uint64_t hi = x3 + (x1 >> 32);
+
+        lo += k;
+        if (lo < k)
+            hi++;
+        *outHigh = hi;
+        return lo;
+#endif
+    }
+
+    static const size_t kBitCount = 3328;  // 64bit * 54 > 10^1000
+    static const size_t kCapacity = kBitCount / sizeof(Type);
+    static const size_t kTypeBit = sizeof(Type) * 8;
+
+    Type digits_[kCapacity];
+    size_t count_;
+};
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_BIGINTEGER_H_

+ 271 - 0
jni/base/rapidjson/internal/diyfp.h

@@ -0,0 +1,271 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
+// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
+// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
+
+#ifndef RAPIDJSON_DIYFP_H_
+#define RAPIDJSON_DIYFP_H_
+
+#include "../rapidjson.h"
+#include <limits>
+
+#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER)
+#include <intrin.h>
+#pragma intrinsic(_BitScanReverse64)
+#pragma intrinsic(_umul128)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+struct DiyFp {
+    DiyFp() : f(), e() {}
+
+    DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
+
+    explicit DiyFp(double d) {
+        union {
+            double d;
+            uint64_t u64;
+        } u = { d };
+
+        int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
+        uint64_t significand = (u.u64 & kDpSignificandMask);
+        if (biased_e != 0) {
+            f = significand + kDpHiddenBit;
+            e = biased_e - kDpExponentBias;
+        }
+        else {
+            f = significand;
+            e = kDpMinExponent + 1;
+        }
+    }
+
+    DiyFp operator-(const DiyFp& rhs) const {
+        return DiyFp(f - rhs.f, e);
+    }
+
+    DiyFp operator*(const DiyFp& rhs) const {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+        uint64_t h;
+        uint64_t l = _umul128(f, rhs.f, &h);
+        if (l & (uint64_t(1) << 63)) // rounding
+            h++;
+        return DiyFp(h, e + rhs.e + 64);
+#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
+        __extension__ typedef unsigned __int128 uint128;
+        uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
+        uint64_t h = static_cast<uint64_t>(p >> 64);
+        uint64_t l = static_cast<uint64_t>(p);
+        if (l & (uint64_t(1) << 63)) // rounding
+            h++;
+        return DiyFp(h, e + rhs.e + 64);
+#else
+        const uint64_t M32 = 0xFFFFFFFF;
+        const uint64_t a = f >> 32;
+        const uint64_t b = f & M32;
+        const uint64_t c = rhs.f >> 32;
+        const uint64_t d = rhs.f & M32;
+        const uint64_t ac = a * c;
+        const uint64_t bc = b * c;
+        const uint64_t ad = a * d;
+        const uint64_t bd = b * d;
+        uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
+        tmp += 1U << 31;  /// mult_round
+        return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
+#endif
+    }
+
+    DiyFp Normalize() const {
+        RAPIDJSON_ASSERT(f != 0); // https://stackoverflow.com/a/26809183/291737
+#if defined(_MSC_VER) && defined(_M_AMD64)
+        unsigned long index;
+        _BitScanReverse64(&index, f);
+        return DiyFp(f << (63 - index), e - (63 - index));
+#elif defined(__GNUC__) && __GNUC__ >= 4
+        int s = __builtin_clzll(f);
+        return DiyFp(f << s, e - s);
+#else
+        DiyFp res = *this;
+        while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
+            res.f <<= 1;
+            res.e--;
+        }
+        return res;
+#endif
+    }
+
+    DiyFp NormalizeBoundary() const {
+        DiyFp res = *this;
+        while (!(res.f & (kDpHiddenBit << 1))) {
+            res.f <<= 1;
+            res.e--;
+        }
+        res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
+        res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
+        return res;
+    }
+
+    void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
+        DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
+        DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
+        mi.f <<= mi.e - pl.e;
+        mi.e = pl.e;
+        *plus = pl;
+        *minus = mi;
+    }
+
+    double ToDouble() const {
+        union {
+            double d;
+            uint64_t u64;
+        }u;
+        RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask);
+        if (e < kDpDenormalExponent) {
+            // Underflow.
+            return 0.0;
+        }
+        if (e >= kDpMaxExponent) {
+            // Overflow.
+            return std::numeric_limits<double>::infinity();
+        }
+        const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
+            static_cast<uint64_t>(e + kDpExponentBias);
+        u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
+        return u.d;
+    }
+
+    static const int kDiySignificandSize = 64;
+    static const int kDpSignificandSize = 52;
+    static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
+    static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
+    static const int kDpMinExponent = -kDpExponentBias;
+    static const int kDpDenormalExponent = -kDpExponentBias + 1;
+    static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
+    static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
+    static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
+
+    uint64_t f;
+    int e;
+};
+
+inline DiyFp GetCachedPowerByIndex(size_t index) {
+    // 10^-348, 10^-340, ..., 10^340
+    static const uint64_t kCachedPowers_F[] = {
+        RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
+        RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
+        RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
+        RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
+        RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
+        RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
+        RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
+        RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
+        RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
+        RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
+        RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
+        RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
+        RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
+        RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
+        RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
+        RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
+        RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
+        RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
+        RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
+        RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
+        RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
+        RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
+        RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
+        RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
+        RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
+        RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
+        RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
+        RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
+        RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
+        RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
+        RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
+        RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
+        RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
+        RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
+        RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
+        RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
+        RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
+        RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
+        RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
+        RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
+        RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
+        RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
+        RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
+        RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
+    };
+    static const int16_t kCachedPowers_E[] = {
+        -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007,  -980,
+        -954,  -927,  -901,  -874,  -847,  -821,  -794,  -768,  -741,  -715,
+        -688,  -661,  -635,  -608,  -582,  -555,  -529,  -502,  -475,  -449,
+        -422,  -396,  -369,  -343,  -316,  -289,  -263,  -236,  -210,  -183,
+        -157,  -130,  -103,   -77,   -50,   -24,     3,    30,    56,    83,
+        109,   136,   162,   189,   216,   242,   269,   295,   322,   348,
+        375,   402,   428,   455,   481,   508,   534,   561,   588,   614,
+        641,   667,   694,   720,   747,   774,   800,   827,   853,   880,
+        907,   933,   960,   986,  1013,  1039,  1066
+    };
+    RAPIDJSON_ASSERT(index < 87);
+    return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
+}
+
+inline DiyFp GetCachedPower(int e, int* K) {
+
+    //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
+    double dk = (-61 - e) * 0.30102999566398114 + 347;  // dk must be positive, so can do ceiling in positive
+    int k = static_cast<int>(dk);
+    if (dk - k > 0.0)
+        k++;
+
+    unsigned index = static_cast<unsigned>((k >> 3) + 1);
+    *K = -(-348 + static_cast<int>(index << 3));    // decimal exponent no need lookup table
+
+    return GetCachedPowerByIndex(index);
+}
+
+inline DiyFp GetCachedPower10(int exp, int *outExp) {
+    RAPIDJSON_ASSERT(exp >= -348);
+    unsigned index = static_cast<unsigned>(exp + 348) / 8u;
+    *outExp = -348 + static_cast<int>(index) * 8;
+    return GetCachedPowerByIndex(index);
+}
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_DIYFP_H_

+ 245 - 0
jni/base/rapidjson/internal/dtoa.h

@@ -0,0 +1,245 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
+// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
+// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
+
+#ifndef RAPIDJSON_DTOA_
+#define RAPIDJSON_DTOA_
+
+#include "itoa.h" // GetDigitsLut()
+#include "diyfp.h"
+#include "ieee754.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124
+#endif
+
+inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
+    while (rest < wp_w && delta - rest >= ten_kappa &&
+           (rest + ten_kappa < wp_w ||  /// closer
+            wp_w - rest > rest + ten_kappa - wp_w)) {
+        buffer[len - 1]--;
+        rest += ten_kappa;
+    }
+}
+
+inline int CountDecimalDigit32(uint32_t n) {
+    // Simple pure C++ implementation was faster than __builtin_clz version in this situation.
+    if (n < 10) return 1;
+    if (n < 100) return 2;
+    if (n < 1000) return 3;
+    if (n < 10000) return 4;
+    if (n < 100000) return 5;
+    if (n < 1000000) return 6;
+    if (n < 10000000) return 7;
+    if (n < 100000000) return 8;
+    // Will not reach 10 digits in DigitGen()
+    //if (n < 1000000000) return 9;
+    //return 10;
+    return 9;
+}
+
+inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
+    static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
+    const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
+    const DiyFp wp_w = Mp - W;
+    uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
+    uint64_t p2 = Mp.f & (one.f - 1);
+    int kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
+    *len = 0;
+
+    while (kappa > 0) {
+        uint32_t d = 0;
+        switch (kappa) {
+            case  9: d = p1 /  100000000; p1 %=  100000000; break;
+            case  8: d = p1 /   10000000; p1 %=   10000000; break;
+            case  7: d = p1 /    1000000; p1 %=    1000000; break;
+            case  6: d = p1 /     100000; p1 %=     100000; break;
+            case  5: d = p1 /      10000; p1 %=      10000; break;
+            case  4: d = p1 /       1000; p1 %=       1000; break;
+            case  3: d = p1 /        100; p1 %=        100; break;
+            case  2: d = p1 /         10; p1 %=         10; break;
+            case  1: d = p1;              p1 =           0; break;
+            default:;
+        }
+        if (d || *len)
+            buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
+        kappa--;
+        uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
+        if (tmp <= delta) {
+            *K += kappa;
+            GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
+            return;
+        }
+    }
+
+    // kappa = 0
+    for (;;) {
+        p2 *= 10;
+        delta *= 10;
+        char d = static_cast<char>(p2 >> -one.e);
+        if (d || *len)
+            buffer[(*len)++] = static_cast<char>('0' + d);
+        p2 &= one.f - 1;
+        kappa--;
+        if (p2 < delta) {
+            *K += kappa;
+            int index = -kappa;
+            GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0));
+            return;
+        }
+    }
+}
+
+inline void Grisu2(double value, char* buffer, int* length, int* K) {
+    const DiyFp v(value);
+    DiyFp w_m, w_p;
+    v.NormalizedBoundaries(&w_m, &w_p);
+
+    const DiyFp c_mk = GetCachedPower(w_p.e, K);
+    const DiyFp W = v.Normalize() * c_mk;
+    DiyFp Wp = w_p * c_mk;
+    DiyFp Wm = w_m * c_mk;
+    Wm.f++;
+    Wp.f--;
+    DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
+}
+
+inline char* WriteExponent(int K, char* buffer) {
+    if (K < 0) {
+        *buffer++ = '-';
+        K = -K;
+    }
+
+    if (K >= 100) {
+        *buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
+        K %= 100;
+        const char* d = GetDigitsLut() + K * 2;
+        *buffer++ = d[0];
+        *buffer++ = d[1];
+    }
+    else if (K >= 10) {
+        const char* d = GetDigitsLut() + K * 2;
+        *buffer++ = d[0];
+        *buffer++ = d[1];
+    }
+    else
+        *buffer++ = static_cast<char>('0' + static_cast<char>(K));
+
+    return buffer;
+}
+
+inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
+    const int kk = length + k;  // 10^(kk-1) <= v < 10^kk
+
+    if (0 <= k && kk <= 21) {
+        // 1234e7 -> 12340000000
+        for (int i = length; i < kk; i++)
+            buffer[i] = '0';
+        buffer[kk] = '.';
+        buffer[kk + 1] = '0';
+        return &buffer[kk + 2];
+    }
+    else if (0 < kk && kk <= 21) {
+        // 1234e-2 -> 12.34
+        std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
+        buffer[kk] = '.';
+        if (0 > k + maxDecimalPlaces) {
+            // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
+            // Remove extra trailing zeros (at least one) after truncation.
+            for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)
+                if (buffer[i] != '0')
+                    return &buffer[i + 1];
+            return &buffer[kk + 2]; // Reserve one zero
+        }
+        else
+            return &buffer[length + 1];
+    }
+    else if (-6 < kk && kk <= 0) {
+        // 1234e-6 -> 0.001234
+        const int offset = 2 - kk;
+        std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
+        buffer[0] = '0';
+        buffer[1] = '.';
+        for (int i = 2; i < offset; i++)
+            buffer[i] = '0';
+        if (length - kk > maxDecimalPlaces) {
+            // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
+            // Remove extra trailing zeros (at least one) after truncation.
+            for (int i = maxDecimalPlaces + 1; i > 2; i--)
+                if (buffer[i] != '0')
+                    return &buffer[i + 1];
+            return &buffer[3]; // Reserve one zero
+        }
+        else
+            return &buffer[length + offset];
+    }
+    else if (kk < -maxDecimalPlaces) {
+        // Truncate to zero
+        buffer[0] = '0';
+        buffer[1] = '.';
+        buffer[2] = '0';
+        return &buffer[3];
+    }
+    else if (length == 1) {
+        // 1e30
+        buffer[1] = 'e';
+        return WriteExponent(kk - 1, &buffer[2]);
+    }
+    else {
+        // 1234e30 -> 1.234e33
+        std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
+        buffer[1] = '.';
+        buffer[length + 1] = 'e';
+        return WriteExponent(kk - 1, &buffer[0 + length + 2]);
+    }
+}
+
+inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) {
+    RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
+    Double d(value);
+    if (d.IsZero()) {
+        if (d.Sign())
+            *buffer++ = '-';     // -0.0, Issue #289
+        buffer[0] = '0';
+        buffer[1] = '.';
+        buffer[2] = '0';
+        return &buffer[3];
+    }
+    else {
+        if (value < 0) {
+            *buffer++ = '-';
+            value = -value;
+        }
+        int length, K;
+        Grisu2(value, buffer, &length, &K);
+        return Prettify(buffer, length, K, maxDecimalPlaces);
+    }
+}
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_DTOA_

+ 78 - 0
jni/base/rapidjson/internal/ieee754.h

@@ -0,0 +1,78 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_IEEE754_
+#define RAPIDJSON_IEEE754_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+class Double {
+public:
+    Double() {}
+    Double(double d) : d_(d) {}
+    Double(uint64_t u) : u_(u) {}
+
+    double Value() const { return d_; }
+    uint64_t Uint64Value() const { return u_; }
+
+    double NextPositiveDouble() const {
+        RAPIDJSON_ASSERT(!Sign());
+        return Double(u_ + 1).Value();
+    }
+
+    bool Sign() const { return (u_ & kSignMask) != 0; }
+    uint64_t Significand() const { return u_ & kSignificandMask; }
+    int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }
+
+    bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
+    bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
+    bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; }
+    bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
+    bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
+
+    uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
+    int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
+    uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
+
+    static int EffectiveSignificandSize(int order) {
+        if (order >= -1021)
+            return 53;
+        else if (order <= -1074)
+            return 0;
+        else
+            return order + 1074;
+    }
+
+private:
+    static const int kSignificandSize = 52;
+    static const int kExponentBias = 0x3FF;
+    static const int kDenormalExponent = 1 - kExponentBias;
+    static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
+    static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
+    static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
+    static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
+
+    union {
+        double d_;
+        uint64_t u_;
+    };
+};
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_IEEE754_

+ 308 - 0
jni/base/rapidjson/internal/itoa.h

@@ -0,0 +1,308 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ITOA_
+#define RAPIDJSON_ITOA_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+inline const char* GetDigitsLut() {
+    static const char cDigitsLut[200] = {
+        '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',
+        '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',
+        '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',
+        '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',
+        '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',
+        '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',
+        '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',
+        '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',
+        '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',
+        '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'
+    };
+    return cDigitsLut;
+}
+
+inline char* u32toa(uint32_t value, char* buffer) {
+    RAPIDJSON_ASSERT(buffer != 0);
+
+    const char* cDigitsLut = GetDigitsLut();
+
+    if (value < 10000) {
+        const uint32_t d1 = (value / 100) << 1;
+        const uint32_t d2 = (value % 100) << 1;
+
+        if (value >= 1000)
+            *buffer++ = cDigitsLut[d1];
+        if (value >= 100)
+            *buffer++ = cDigitsLut[d1 + 1];
+        if (value >= 10)
+            *buffer++ = cDigitsLut[d2];
+        *buffer++ = cDigitsLut[d2 + 1];
+    }
+    else if (value < 100000000) {
+        // value = bbbbcccc
+        const uint32_t b = value / 10000;
+        const uint32_t c = value % 10000;
+
+        const uint32_t d1 = (b / 100) << 1;
+        const uint32_t d2 = (b % 100) << 1;
+
+        const uint32_t d3 = (c / 100) << 1;
+        const uint32_t d4 = (c % 100) << 1;
+
+        if (value >= 10000000)
+            *buffer++ = cDigitsLut[d1];
+        if (value >= 1000000)
+            *buffer++ = cDigitsLut[d1 + 1];
+        if (value >= 100000)
+            *buffer++ = cDigitsLut[d2];
+        *buffer++ = cDigitsLut[d2 + 1];
+
+        *buffer++ = cDigitsLut[d3];
+        *buffer++ = cDigitsLut[d3 + 1];
+        *buffer++ = cDigitsLut[d4];
+        *buffer++ = cDigitsLut[d4 + 1];
+    }
+    else {
+        // value = aabbbbcccc in decimal
+
+        const uint32_t a = value / 100000000; // 1 to 42
+        value %= 100000000;
+
+        if (a >= 10) {
+            const unsigned i = a << 1;
+            *buffer++ = cDigitsLut[i];
+            *buffer++ = cDigitsLut[i + 1];
+        }
+        else
+            *buffer++ = static_cast<char>('0' + static_cast<char>(a));
+
+        const uint32_t b = value / 10000; // 0 to 9999
+        const uint32_t c = value % 10000; // 0 to 9999
+
+        const uint32_t d1 = (b / 100) << 1;
+        const uint32_t d2 = (b % 100) << 1;
+
+        const uint32_t d3 = (c / 100) << 1;
+        const uint32_t d4 = (c % 100) << 1;
+
+        *buffer++ = cDigitsLut[d1];
+        *buffer++ = cDigitsLut[d1 + 1];
+        *buffer++ = cDigitsLut[d2];
+        *buffer++ = cDigitsLut[d2 + 1];
+        *buffer++ = cDigitsLut[d3];
+        *buffer++ = cDigitsLut[d3 + 1];
+        *buffer++ = cDigitsLut[d4];
+        *buffer++ = cDigitsLut[d4 + 1];
+    }
+    return buffer;
+}
+
+inline char* i32toa(int32_t value, char* buffer) {
+    RAPIDJSON_ASSERT(buffer != 0);
+    uint32_t u = static_cast<uint32_t>(value);
+    if (value < 0) {
+        *buffer++ = '-';
+        u = ~u + 1;
+    }
+
+    return u32toa(u, buffer);
+}
+
+inline char* u64toa(uint64_t value, char* buffer) {
+    RAPIDJSON_ASSERT(buffer != 0);
+    const char* cDigitsLut = GetDigitsLut();
+    const uint64_t  kTen8 = 100000000;
+    const uint64_t  kTen9 = kTen8 * 10;
+    const uint64_t kTen10 = kTen8 * 100;
+    const uint64_t kTen11 = kTen8 * 1000;
+    const uint64_t kTen12 = kTen8 * 10000;
+    const uint64_t kTen13 = kTen8 * 100000;
+    const uint64_t kTen14 = kTen8 * 1000000;
+    const uint64_t kTen15 = kTen8 * 10000000;
+    const uint64_t kTen16 = kTen8 * kTen8;
+
+    if (value < kTen8) {
+        uint32_t v = static_cast<uint32_t>(value);
+        if (v < 10000) {
+            const uint32_t d1 = (v / 100) << 1;
+            const uint32_t d2 = (v % 100) << 1;
+
+            if (v >= 1000)
+                *buffer++ = cDigitsLut[d1];
+            if (v >= 100)
+                *buffer++ = cDigitsLut[d1 + 1];
+            if (v >= 10)
+                *buffer++ = cDigitsLut[d2];
+            *buffer++ = cDigitsLut[d2 + 1];
+        }
+        else {
+            // value = bbbbcccc
+            const uint32_t b = v / 10000;
+            const uint32_t c = v % 10000;
+
+            const uint32_t d1 = (b / 100) << 1;
+            const uint32_t d2 = (b % 100) << 1;
+
+            const uint32_t d3 = (c / 100) << 1;
+            const uint32_t d4 = (c % 100) << 1;
+
+            if (value >= 10000000)
+                *buffer++ = cDigitsLut[d1];
+            if (value >= 1000000)
+                *buffer++ = cDigitsLut[d1 + 1];
+            if (value >= 100000)
+                *buffer++ = cDigitsLut[d2];
+            *buffer++ = cDigitsLut[d2 + 1];
+
+            *buffer++ = cDigitsLut[d3];
+            *buffer++ = cDigitsLut[d3 + 1];
+            *buffer++ = cDigitsLut[d4];
+            *buffer++ = cDigitsLut[d4 + 1];
+        }
+    }
+    else if (value < kTen16) {
+        const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
+        const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
+
+        const uint32_t b0 = v0 / 10000;
+        const uint32_t c0 = v0 % 10000;
+
+        const uint32_t d1 = (b0 / 100) << 1;
+        const uint32_t d2 = (b0 % 100) << 1;
+
+        const uint32_t d3 = (c0 / 100) << 1;
+        const uint32_t d4 = (c0 % 100) << 1;
+
+        const uint32_t b1 = v1 / 10000;
+        const uint32_t c1 = v1 % 10000;
+
+        const uint32_t d5 = (b1 / 100) << 1;
+        const uint32_t d6 = (b1 % 100) << 1;
+
+        const uint32_t d7 = (c1 / 100) << 1;
+        const uint32_t d8 = (c1 % 100) << 1;
+
+        if (value >= kTen15)
+            *buffer++ = cDigitsLut[d1];
+        if (value >= kTen14)
+            *buffer++ = cDigitsLut[d1 + 1];
+        if (value >= kTen13)
+            *buffer++ = cDigitsLut[d2];
+        if (value >= kTen12)
+            *buffer++ = cDigitsLut[d2 + 1];
+        if (value >= kTen11)
+            *buffer++ = cDigitsLut[d3];
+        if (value >= kTen10)
+            *buffer++ = cDigitsLut[d3 + 1];
+        if (value >= kTen9)
+            *buffer++ = cDigitsLut[d4];
+
+        *buffer++ = cDigitsLut[d4 + 1];
+        *buffer++ = cDigitsLut[d5];
+        *buffer++ = cDigitsLut[d5 + 1];
+        *buffer++ = cDigitsLut[d6];
+        *buffer++ = cDigitsLut[d6 + 1];
+        *buffer++ = cDigitsLut[d7];
+        *buffer++ = cDigitsLut[d7 + 1];
+        *buffer++ = cDigitsLut[d8];
+        *buffer++ = cDigitsLut[d8 + 1];
+    }
+    else {
+        const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
+        value %= kTen16;
+
+        if (a < 10)
+            *buffer++ = static_cast<char>('0' + static_cast<char>(a));
+        else if (a < 100) {
+            const uint32_t i = a << 1;
+            *buffer++ = cDigitsLut[i];
+            *buffer++ = cDigitsLut[i + 1];
+        }
+        else if (a < 1000) {
+            *buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
+
+            const uint32_t i = (a % 100) << 1;
+            *buffer++ = cDigitsLut[i];
+            *buffer++ = cDigitsLut[i + 1];
+        }
+        else {
+            const uint32_t i = (a / 100) << 1;
+            const uint32_t j = (a % 100) << 1;
+            *buffer++ = cDigitsLut[i];
+            *buffer++ = cDigitsLut[i + 1];
+            *buffer++ = cDigitsLut[j];
+            *buffer++ = cDigitsLut[j + 1];
+        }
+
+        const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
+        const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
+
+        const uint32_t b0 = v0 / 10000;
+        const uint32_t c0 = v0 % 10000;
+
+        const uint32_t d1 = (b0 / 100) << 1;
+        const uint32_t d2 = (b0 % 100) << 1;
+
+        const uint32_t d3 = (c0 / 100) << 1;
+        const uint32_t d4 = (c0 % 100) << 1;
+
+        const uint32_t b1 = v1 / 10000;
+        const uint32_t c1 = v1 % 10000;
+
+        const uint32_t d5 = (b1 / 100) << 1;
+        const uint32_t d6 = (b1 % 100) << 1;
+
+        const uint32_t d7 = (c1 / 100) << 1;
+        const uint32_t d8 = (c1 % 100) << 1;
+
+        *buffer++ = cDigitsLut[d1];
+        *buffer++ = cDigitsLut[d1 + 1];
+        *buffer++ = cDigitsLut[d2];
+        *buffer++ = cDigitsLut[d2 + 1];
+        *buffer++ = cDigitsLut[d3];
+        *buffer++ = cDigitsLut[d3 + 1];
+        *buffer++ = cDigitsLut[d4];
+        *buffer++ = cDigitsLut[d4 + 1];
+        *buffer++ = cDigitsLut[d5];
+        *buffer++ = cDigitsLut[d5 + 1];
+        *buffer++ = cDigitsLut[d6];
+        *buffer++ = cDigitsLut[d6 + 1];
+        *buffer++ = cDigitsLut[d7];
+        *buffer++ = cDigitsLut[d7 + 1];
+        *buffer++ = cDigitsLut[d8];
+        *buffer++ = cDigitsLut[d8 + 1];
+    }
+
+    return buffer;
+}
+
+inline char* i64toa(int64_t value, char* buffer) {
+    RAPIDJSON_ASSERT(buffer != 0);
+    uint64_t u = static_cast<uint64_t>(value);
+    if (value < 0) {
+        *buffer++ = '-';
+        u = ~u + 1;
+    }
+
+    return u64toa(u, buffer);
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_ITOA_

+ 186 - 0
jni/base/rapidjson/internal/meta.h

@@ -0,0 +1,186 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_META_H_
+#define RAPIDJSON_INTERNAL_META_H_
+
+#include "../rapidjson.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#if defined(_MSC_VER) && !defined(__clang__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(6334)
+#endif
+
+#if RAPIDJSON_HAS_CXX11_TYPETRAITS
+#include <type_traits>
+#endif
+
+//@cond RAPIDJSON_INTERNAL
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
+template <typename T> struct Void { typedef void Type; };
+
+///////////////////////////////////////////////////////////////////////////////
+// BoolType, TrueType, FalseType
+//
+template <bool Cond> struct BoolType {
+    static const bool Value = Cond;
+    typedef BoolType Type;
+};
+typedef BoolType<true> TrueType;
+typedef BoolType<false> FalseType;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
+//
+
+template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
+template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
+template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
+template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
+
+template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
+template <> struct AndExprCond<true, true> : TrueType {};
+template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
+template <> struct OrExprCond<false, false> : FalseType {};
+
+template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
+template <typename C> struct NotExpr  : SelectIf<C,FalseType,TrueType>::Type {};
+template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
+template <typename C1, typename C2> struct OrExpr  : OrExprCond<C1::Value, C2::Value>::Type {};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// AddConst, MaybeAddConst, RemoveConst
+template <typename T> struct AddConst { typedef const T Type; };
+template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
+template <typename T> struct RemoveConst { typedef T Type; };
+template <typename T> struct RemoveConst<const T> { typedef T Type; };
+
+
+///////////////////////////////////////////////////////////////////////////////
+// IsSame, IsConst, IsMoreConst, IsPointer
+//
+template <typename T, typename U> struct IsSame : FalseType {};
+template <typename T> struct IsSame<T, T> : TrueType {};
+
+template <typename T> struct IsConst : FalseType {};
+template <typename T> struct IsConst<const T> : TrueType {};
+
+template <typename CT, typename T>
+struct IsMoreConst
+    : AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
+              BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
+
+template <typename T> struct IsPointer : FalseType {};
+template <typename T> struct IsPointer<T*> : TrueType {};
+
+///////////////////////////////////////////////////////////////////////////////
+// IsBaseOf
+//
+#if RAPIDJSON_HAS_CXX11_TYPETRAITS
+
+template <typename B, typename D> struct IsBaseOf
+    : BoolType< ::std::is_base_of<B,D>::value> {};
+
+#else // simplified version adopted from Boost
+
+template<typename B, typename D> struct IsBaseOfImpl {
+    RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
+    RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
+
+    typedef char (&Yes)[1];
+    typedef char (&No) [2];
+
+    template <typename T>
+    static Yes Check(const D*, T);
+    static No  Check(const B*, int);
+
+    struct Host {
+        operator const B*() const;
+        operator const D*();
+    };
+
+    enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
+};
+
+template <typename B, typename D> struct IsBaseOf
+    : OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
+
+#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
+
+
+//////////////////////////////////////////////////////////////////////////
+// EnableIf / DisableIf
+//
+template <bool Condition, typename T = void> struct EnableIfCond  { typedef T Type; };
+template <typename T> struct EnableIfCond<false, T> { /* empty */ };
+
+template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
+template <typename T> struct DisableIfCond<true, T> { /* empty */ };
+
+template <typename Condition, typename T = void>
+struct EnableIf : EnableIfCond<Condition::Value, T> {};
+
+template <typename Condition, typename T = void>
+struct DisableIf : DisableIfCond<Condition::Value, T> {};
+
+// SFINAE helpers
+struct SfinaeTag {};
+template <typename T> struct RemoveSfinaeTag;
+template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
+
+#define RAPIDJSON_REMOVEFPTR_(type) \
+    typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
+        < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
+
+#define RAPIDJSON_ENABLEIF(cond) \
+    typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
+        <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
+
+#define RAPIDJSON_DISABLEIF(cond) \
+    typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
+        <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
+
+#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
+    typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
+        <RAPIDJSON_REMOVEFPTR_(cond), \
+         RAPIDJSON_REMOVEFPTR_(returntype)>::Type
+
+#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
+    typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
+        <RAPIDJSON_REMOVEFPTR_(cond), \
+         RAPIDJSON_REMOVEFPTR_(returntype)>::Type
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+//@endcond
+
+#if defined(_MSC_VER) && !defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_INTERNAL_META_H_

+ 55 - 0
jni/base/rapidjson/internal/pow10.h

@@ -0,0 +1,55 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_POW10_
+#define RAPIDJSON_POW10_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+//! Computes integer powers of 10 in double (10.0^n).
+/*! This function uses lookup table for fast and accurate results.
+    \param n non-negative exponent. Must <= 308.
+    \return 10.0^n
+*/
+inline double Pow10(int n) {
+    static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
+        1e+0,  
+        1e+1,  1e+2,  1e+3,  1e+4,  1e+5,  1e+6,  1e+7,  1e+8,  1e+9,  1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 
+        1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
+        1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
+        1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
+        1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
+        1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
+        1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
+        1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
+        1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
+        1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
+        1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
+        1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
+        1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
+        1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
+        1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
+        1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
+    };
+    RAPIDJSON_ASSERT(n >= 0 && n <= 308);
+    return e[n];
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_POW10_

+ 740 - 0
jni/base/rapidjson/internal/regex.h

@@ -0,0 +1,740 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_REGEX_H_
+#define RAPIDJSON_INTERNAL_REGEX_H_
+
+#include "../allocators.h"
+#include "../stream.h"
+#include "stack.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(switch-enum)
+RAPIDJSON_DIAG_OFF(implicit-fallthrough)
+#elif defined(_MSC_VER)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#if __GNUC__ >= 7
+RAPIDJSON_DIAG_OFF(implicit-fallthrough)
+#endif
+#endif
+
+#ifndef RAPIDJSON_REGEX_VERBOSE
+#define RAPIDJSON_REGEX_VERBOSE 0
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+///////////////////////////////////////////////////////////////////////////////
+// DecodedStream
+
+template <typename SourceStream, typename Encoding>
+class DecodedStream {
+public:
+    DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
+    unsigned Peek() { return codepoint_; }
+    unsigned Take() {
+        unsigned c = codepoint_;
+        if (c) // No further decoding when '\0'
+            Decode();
+        return c;
+    }
+
+private:
+    void Decode() {
+        if (!Encoding::Decode(ss_, &codepoint_))
+            codepoint_ = 0;
+    }
+
+    SourceStream& ss_;
+    unsigned codepoint_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericRegex
+
+static const SizeType kRegexInvalidState = ~SizeType(0);  //!< Represents an invalid index in GenericRegex::State::out, out1
+static const SizeType kRegexInvalidRange = ~SizeType(0);
+
+template <typename Encoding, typename Allocator>
+class GenericRegexSearch;
+
+//! Regular expression engine with subset of ECMAscript grammar.
+/*!
+    Supported regular expression syntax:
+    - \c ab     Concatenation
+    - \c a|b    Alternation
+    - \c a?     Zero or one
+    - \c a*     Zero or more
+    - \c a+     One or more
+    - \c a{3}   Exactly 3 times
+    - \c a{3,}  At least 3 times
+    - \c a{3,5} 3 to 5 times
+    - \c (ab)   Grouping
+    - \c ^a     At the beginning
+    - \c a$     At the end
+    - \c .      Any character
+    - \c [abc]  Character classes
+    - \c [a-c]  Character class range
+    - \c [a-z0-9_] Character class combination
+    - \c [^abc] Negated character classes
+    - \c [^a-c] Negated character class range
+    - \c [\b]   Backspace (U+0008)
+    - \c \\| \\\\ ...  Escape characters
+    - \c \\f Form feed (U+000C)
+    - \c \\n Line feed (U+000A)
+    - \c \\r Carriage return (U+000D)
+    - \c \\t Tab (U+0009)
+    - \c \\v Vertical tab (U+000B)
+
+    \note This is a Thompson NFA engine, implemented with reference to 
+        Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).", 
+        https://swtch.com/~rsc/regexp/regexp1.html 
+*/
+template <typename Encoding, typename Allocator = CrtAllocator>
+class GenericRegex {
+public:
+    typedef Encoding EncodingType;
+    typedef typename Encoding::Ch Ch;
+    template <typename, typename> friend class GenericRegexSearch;
+
+    GenericRegex(const Ch* source, Allocator* allocator = 0) : 
+        ownAllocator_(allocator ? 0 : RAPIDJSON_NEW(Allocator)()), allocator_(allocator ? allocator : ownAllocator_), 
+        states_(allocator_, 256), ranges_(allocator_, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), 
+        anchorBegin_(), anchorEnd_()
+    {
+        GenericStringStream<Encoding> ss(source);
+        DecodedStream<GenericStringStream<Encoding>, Encoding> ds(ss);
+        Parse(ds);
+    }
+
+    ~GenericRegex()
+    {
+        RAPIDJSON_DELETE(ownAllocator_);
+    }
+
+    bool IsValid() const {
+        return root_ != kRegexInvalidState;
+    }
+
+private:
+    enum Operator {
+        kZeroOrOne,
+        kZeroOrMore,
+        kOneOrMore,
+        kConcatenation,
+        kAlternation,
+        kLeftParenthesis
+    };
+
+    static const unsigned kAnyCharacterClass = 0xFFFFFFFF;   //!< For '.'
+    static const unsigned kRangeCharacterClass = 0xFFFFFFFE;
+    static const unsigned kRangeNegationFlag = 0x80000000;
+
+    struct Range {
+        unsigned start; // 
+        unsigned end;
+        SizeType next;
+    };
+
+    struct State {
+        SizeType out;     //!< Equals to kInvalid for matching state
+        SizeType out1;    //!< Equals to non-kInvalid for split
+        SizeType rangeStart;
+        unsigned codepoint;
+    };
+
+    struct Frag {
+        Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {}
+        SizeType start;
+        SizeType out; //!< link-list of all output states
+        SizeType minIndex;
+    };
+
+    State& GetState(SizeType index) {
+        RAPIDJSON_ASSERT(index < stateCount_);
+        return states_.template Bottom<State>()[index];
+    }
+
+    const State& GetState(SizeType index) const {
+        RAPIDJSON_ASSERT(index < stateCount_);
+        return states_.template Bottom<State>()[index];
+    }
+
+    Range& GetRange(SizeType index) {
+        RAPIDJSON_ASSERT(index < rangeCount_);
+        return ranges_.template Bottom<Range>()[index];
+    }
+
+    const Range& GetRange(SizeType index) const {
+        RAPIDJSON_ASSERT(index < rangeCount_);
+        return ranges_.template Bottom<Range>()[index];
+    }
+
+    template <typename InputStream>
+    void Parse(DecodedStream<InputStream, Encoding>& ds) {
+        Stack<Allocator> operandStack(allocator_, 256);    // Frag
+        Stack<Allocator> operatorStack(allocator_, 256);   // Operator
+        Stack<Allocator> atomCountStack(allocator_, 256);  // unsigned (Atom per parenthesis)
+
+        *atomCountStack.template Push<unsigned>() = 0;
+
+        unsigned codepoint;
+        while (ds.Peek() != 0) {
+            switch (codepoint = ds.Take()) {
+                case '^':
+                    anchorBegin_ = true;
+                    break;
+
+                case '$':
+                    anchorEnd_ = true;
+                    break;
+
+                case '|':
+                    while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation)
+                        if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
+                            return;
+                    *operatorStack.template Push<Operator>() = kAlternation;
+                    *atomCountStack.template Top<unsigned>() = 0;
+                    break;
+
+                case '(':
+                    *operatorStack.template Push<Operator>() = kLeftParenthesis;
+                    *atomCountStack.template Push<unsigned>() = 0;
+                    break;
+
+                case ')':
+                    while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis)
+                        if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
+                            return;
+                    if (operatorStack.Empty())
+                        return;
+                    operatorStack.template Pop<Operator>(1);
+                    atomCountStack.template Pop<unsigned>(1);
+                    ImplicitConcatenation(atomCountStack, operatorStack);
+                    break;
+
+                case '?':
+                    if (!Eval(operandStack, kZeroOrOne))
+                        return;
+                    break;
+
+                case '*':
+                    if (!Eval(operandStack, kZeroOrMore))
+                        return;
+                    break;
+
+                case '+':
+                    if (!Eval(operandStack, kOneOrMore))
+                        return;
+                    break;
+
+                case '{':
+                    {
+                        unsigned n, m;
+                        if (!ParseUnsigned(ds, &n))
+                            return;
+
+                        if (ds.Peek() == ',') {
+                            ds.Take();
+                            if (ds.Peek() == '}')
+                                m = kInfinityQuantifier;
+                            else if (!ParseUnsigned(ds, &m) || m < n)
+                                return;
+                        }
+                        else
+                            m = n;
+
+                        if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')
+                            return;
+                        ds.Take();
+                    }
+                    break;
+
+                case '.':
+                    PushOperand(operandStack, kAnyCharacterClass);
+                    ImplicitConcatenation(atomCountStack, operatorStack);
+                    break;
+
+                case '[':
+                    {
+                        SizeType range;
+                        if (!ParseRange(ds, &range))
+                            return;
+                        SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);
+                        GetState(s).rangeStart = range;
+                        *operandStack.template Push<Frag>() = Frag(s, s, s);
+                    }
+                    ImplicitConcatenation(atomCountStack, operatorStack);
+                    break;
+
+                case '\\': // Escape character
+                    if (!CharacterEscape(ds, &codepoint))
+                        return; // Unsupported escape character
+                    // fall through to default
+
+                default: // Pattern character
+                    PushOperand(operandStack, codepoint);
+                    ImplicitConcatenation(atomCountStack, operatorStack);
+            }
+        }
+
+        while (!operatorStack.Empty())
+            if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
+                return;
+
+        // Link the operand to matching state.
+        if (operandStack.GetSize() == sizeof(Frag)) {
+            Frag* e = operandStack.template Pop<Frag>(1);
+            Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));
+            root_ = e->start;
+
+#if RAPIDJSON_REGEX_VERBOSE
+            printf("root: %d\n", root_);
+            for (SizeType i = 0; i < stateCount_ ; i++) {
+                State& s = GetState(i);
+                printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint);
+            }
+            printf("\n");
+#endif
+        }
+    }
+
+    SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
+        State* s = states_.template Push<State>();
+        s->out = out;
+        s->out1 = out1;
+        s->codepoint = codepoint;
+        s->rangeStart = kRegexInvalidRange;
+        return stateCount_++;
+    }
+
+    void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint) {
+        SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);
+        *operandStack.template Push<Frag>() = Frag(s, s, s);
+    }
+
+    void ImplicitConcatenation(Stack<Allocator>& atomCountStack, Stack<Allocator>& operatorStack) {
+        if (*atomCountStack.template Top<unsigned>())
+            *operatorStack.template Push<Operator>() = kConcatenation;
+        (*atomCountStack.template Top<unsigned>())++;
+    }
+
+    SizeType Append(SizeType l1, SizeType l2) {
+        SizeType old = l1;
+        while (GetState(l1).out != kRegexInvalidState)
+            l1 = GetState(l1).out;
+        GetState(l1).out = l2;
+        return old;
+    }
+
+    void Patch(SizeType l, SizeType s) {
+        for (SizeType next; l != kRegexInvalidState; l = next) {
+            next = GetState(l).out;
+            GetState(l).out = s;
+        }
+    }
+
+    bool Eval(Stack<Allocator>& operandStack, Operator op) {
+        switch (op) {
+            case kConcatenation:
+                RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2);
+                {
+                    Frag e2 = *operandStack.template Pop<Frag>(1);
+                    Frag e1 = *operandStack.template Pop<Frag>(1);
+                    Patch(e1.out, e2.start);
+                    *operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));
+                }
+                return true;
+
+            case kAlternation:
+                if (operandStack.GetSize() >= sizeof(Frag) * 2) {
+                    Frag e2 = *operandStack.template Pop<Frag>(1);
+                    Frag e1 = *operandStack.template Pop<Frag>(1);
+                    SizeType s = NewState(e1.start, e2.start, 0);
+                    *operandStack.template Push<Frag>() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex));
+                    return true;
+                }
+                return false;
+
+            case kZeroOrOne:
+                if (operandStack.GetSize() >= sizeof(Frag)) {
+                    Frag e = *operandStack.template Pop<Frag>(1);
+                    SizeType s = NewState(kRegexInvalidState, e.start, 0);
+                    *operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex);
+                    return true;
+                }
+                return false;
+
+            case kZeroOrMore:
+                if (operandStack.GetSize() >= sizeof(Frag)) {
+                    Frag e = *operandStack.template Pop<Frag>(1);
+                    SizeType s = NewState(kRegexInvalidState, e.start, 0);
+                    Patch(e.out, s);
+                    *operandStack.template Push<Frag>() = Frag(s, s, e.minIndex);
+                    return true;
+                }
+                return false;
+
+            case kOneOrMore:
+                if (operandStack.GetSize() >= sizeof(Frag)) {
+                    Frag e = *operandStack.template Pop<Frag>(1);
+                    SizeType s = NewState(kRegexInvalidState, e.start, 0);
+                    Patch(e.out, s);
+                    *operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);
+                    return true;
+                }
+                return false;
+
+            default: 
+                // syntax error (e.g. unclosed kLeftParenthesis)
+                return false;
+        }
+    }
+
+    bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) {
+        RAPIDJSON_ASSERT(n <= m);
+        RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag));
+
+        if (n == 0) {
+            if (m == 0)                             // a{0} not support
+                return false;
+            else if (m == kInfinityQuantifier)
+                Eval(operandStack, kZeroOrMore);    // a{0,} -> a*
+            else {
+                Eval(operandStack, kZeroOrOne);         // a{0,5} -> a?
+                for (unsigned i = 0; i < m - 1; i++)
+                    CloneTopOperand(operandStack);      // a{0,5} -> a? a? a? a? a?
+                for (unsigned i = 0; i < m - 1; i++)
+                    Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a?
+            }
+            return true;
+        }
+
+        for (unsigned i = 0; i < n - 1; i++)        // a{3} -> a a a
+            CloneTopOperand(operandStack);
+
+        if (m == kInfinityQuantifier)
+            Eval(operandStack, kOneOrMore);         // a{3,} -> a a a+
+        else if (m > n) {
+            CloneTopOperand(operandStack);          // a{3,5} -> a a a a
+            Eval(operandStack, kZeroOrOne);         // a{3,5} -> a a a a?
+            for (unsigned i = n; i < m - 1; i++)
+                CloneTopOperand(operandStack);      // a{3,5} -> a a a a? a?
+            for (unsigned i = n; i < m; i++)
+                Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a?
+        }
+
+        for (unsigned i = 0; i < n - 1; i++)
+            Eval(operandStack, kConcatenation);     // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a?
+
+        return true;
+    }
+
+    static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; }
+
+    void CloneTopOperand(Stack<Allocator>& operandStack) {
+        const Frag src = *operandStack.template Top<Frag>(); // Copy constructor to prevent invalidation
+        SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_)
+        State* s = states_.template Push<State>(count);
+        memcpy(s, &GetState(src.minIndex), count * sizeof(State));
+        for (SizeType j = 0; j < count; j++) {
+            if (s[j].out != kRegexInvalidState)
+                s[j].out += count;
+            if (s[j].out1 != kRegexInvalidState)
+                s[j].out1 += count;
+        }
+        *operandStack.template Push<Frag>() = Frag(src.start + count, src.out + count, src.minIndex + count);
+        stateCount_ += count;
+    }
+
+    template <typename InputStream>
+    bool ParseUnsigned(DecodedStream<InputStream, Encoding>& ds, unsigned* u) {
+        unsigned r = 0;
+        if (ds.Peek() < '0' || ds.Peek() > '9')
+            return false;
+        while (ds.Peek() >= '0' && ds.Peek() <= '9') {
+            if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295
+                return false; // overflow
+            r = r * 10 + (ds.Take() - '0');
+        }
+        *u = r;
+        return true;
+    }
+
+    template <typename InputStream>
+    bool ParseRange(DecodedStream<InputStream, Encoding>& ds, SizeType* range) {
+        bool isBegin = true;
+        bool negate = false;
+        int step = 0;
+        SizeType start = kRegexInvalidRange;
+        SizeType current = kRegexInvalidRange;
+        unsigned codepoint;
+        while ((codepoint = ds.Take()) != 0) {
+            if (isBegin) {
+                isBegin = false;
+                if (codepoint == '^') {
+                    negate = true;
+                    continue;
+                }
+            }
+
+            switch (codepoint) {
+            case ']':
+                if (start == kRegexInvalidRange)
+                    return false;   // Error: nothing inside []
+                if (step == 2) { // Add trailing '-'
+                    SizeType r = NewRange('-');
+                    RAPIDJSON_ASSERT(current != kRegexInvalidRange);
+                    GetRange(current).next = r;
+                }
+                if (negate)
+                    GetRange(start).start |= kRangeNegationFlag;
+                *range = start;
+                return true;
+
+            case '\\':
+                if (ds.Peek() == 'b') {
+                    ds.Take();
+                    codepoint = 0x0008; // Escape backspace character
+                }
+                else if (!CharacterEscape(ds, &codepoint))
+                    return false;
+                // fall through to default
+
+            default:
+                switch (step) {
+                case 1:
+                    if (codepoint == '-') {
+                        step++;
+                        break;
+                    }
+                    // fall through to step 0 for other characters
+
+                case 0:
+                    {
+                        SizeType r = NewRange(codepoint);
+                        if (current != kRegexInvalidRange)
+                            GetRange(current).next = r;
+                        if (start == kRegexInvalidRange)
+                            start = r;
+                        current = r;
+                    }
+                    step = 1;
+                    break;
+
+                default:
+                    RAPIDJSON_ASSERT(step == 2);
+                    GetRange(current).end = codepoint;
+                    step = 0;
+                }
+            }
+        }
+        return false;
+    }
+    
+    SizeType NewRange(unsigned codepoint) {
+        Range* r = ranges_.template Push<Range>();
+        r->start = r->end = codepoint;
+        r->next = kRegexInvalidRange;
+        return rangeCount_++;
+    }
+
+    template <typename InputStream>
+    bool CharacterEscape(DecodedStream<InputStream, Encoding>& ds, unsigned* escapedCodepoint) {
+        unsigned codepoint;
+        switch (codepoint = ds.Take()) {
+            case '^':
+            case '$':
+            case '|':
+            case '(':
+            case ')':
+            case '?':
+            case '*':
+            case '+':
+            case '.':
+            case '[':
+            case ']':
+            case '{':
+            case '}':
+            case '\\':
+                *escapedCodepoint = codepoint; return true;
+            case 'f': *escapedCodepoint = 0x000C; return true;
+            case 'n': *escapedCodepoint = 0x000A; return true;
+            case 'r': *escapedCodepoint = 0x000D; return true;
+            case 't': *escapedCodepoint = 0x0009; return true;
+            case 'v': *escapedCodepoint = 0x000B; return true;
+            default:
+                return false; // Unsupported escape character
+        }
+    }
+
+    Allocator* ownAllocator_;
+    Allocator* allocator_;
+    Stack<Allocator> states_;
+    Stack<Allocator> ranges_;
+    SizeType root_;
+    SizeType stateCount_;
+    SizeType rangeCount_;
+
+    static const unsigned kInfinityQuantifier = ~0u;
+
+    // For SearchWithAnchoring()
+    bool anchorBegin_;
+    bool anchorEnd_;
+};
+
+template <typename RegexType, typename Allocator = CrtAllocator>
+class GenericRegexSearch {
+public:
+    typedef typename RegexType::EncodingType Encoding;
+    typedef typename Encoding::Ch Ch;
+
+    GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) : 
+        regex_(regex), allocator_(allocator), ownAllocator_(0),
+        state0_(allocator, 0), state1_(allocator, 0), stateSet_()
+    {
+        RAPIDJSON_ASSERT(regex_.IsValid());
+        if (!allocator_)
+            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
+        stateSet_ = static_cast<unsigned*>(allocator_->Malloc(GetStateSetSize()));
+        state0_.template Reserve<SizeType>(regex_.stateCount_);
+        state1_.template Reserve<SizeType>(regex_.stateCount_);
+    }
+
+    ~GenericRegexSearch() {
+        Allocator::Free(stateSet_);
+        RAPIDJSON_DELETE(ownAllocator_);
+    }
+
+    template <typename InputStream>
+    bool Match(InputStream& is) {
+        return SearchWithAnchoring(is, true, true);
+    }
+
+    bool Match(const Ch* s) {
+        GenericStringStream<Encoding> is(s);
+        return Match(is);
+    }
+
+    template <typename InputStream>
+    bool Search(InputStream& is) {
+        return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_);
+    }
+
+    bool Search(const Ch* s) {
+        GenericStringStream<Encoding> is(s);
+        return Search(is);
+    }
+
+private:
+    typedef typename RegexType::State State;
+    typedef typename RegexType::Range Range;
+
+    template <typename InputStream>
+    bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) {
+        DecodedStream<InputStream, Encoding> ds(is);
+
+        state0_.Clear();
+        Stack<Allocator> *current = &state0_, *next = &state1_;
+        const size_t stateSetSize = GetStateSetSize();
+        std::memset(stateSet_, 0, stateSetSize);
+
+        bool matched = AddState(*current, regex_.root_);
+        unsigned codepoint;
+        while (!current->Empty() && (codepoint = ds.Take()) != 0) {
+            std::memset(stateSet_, 0, stateSetSize);
+            next->Clear();
+            matched = false;
+            for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
+                const State& sr = regex_.GetState(*s);
+                if (sr.codepoint == codepoint ||
+                    sr.codepoint == RegexType::kAnyCharacterClass || 
+                    (sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
+                {
+                    matched = AddState(*next, sr.out) || matched;
+                    if (!anchorEnd && matched)
+                        return true;
+                }
+                if (!anchorBegin)
+                    AddState(*next, regex_.root_);
+            }
+            internal::Swap(current, next);
+        }
+
+        return matched;
+    }
+
+    size_t GetStateSetSize() const {
+        return (regex_.stateCount_ + 31) / 32 * 4;
+    }
+
+    // Return whether the added states is a match state
+    bool AddState(Stack<Allocator>& l, SizeType index) {
+        RAPIDJSON_ASSERT(index != kRegexInvalidState);
+
+        const State& s = regex_.GetState(index);
+        if (s.out1 != kRegexInvalidState) { // Split
+            bool matched = AddState(l, s.out);
+            return AddState(l, s.out1) || matched;
+        }
+        else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) {
+            stateSet_[index >> 5] |= (1u << (index & 31));
+            *l.template PushUnsafe<SizeType>() = index;
+        }
+        return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation.
+    }
+
+    bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {
+        bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0;
+        while (rangeIndex != kRegexInvalidRange) {
+            const Range& r = regex_.GetRange(rangeIndex);
+            if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end)
+                return yes;
+            rangeIndex = r.next;
+        }
+        return !yes;
+    }
+
+    const RegexType& regex_;
+    Allocator* allocator_;
+    Allocator* ownAllocator_;
+    Stack<Allocator> state0_;
+    Stack<Allocator> state1_;
+    uint32_t* stateSet_;
+};
+
+typedef GenericRegex<UTF8<> > Regex;
+typedef GenericRegexSearch<Regex> RegexSearch;
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#if defined(__clang__) || defined(_MSC_VER)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_INTERNAL_REGEX_H_

+ 232 - 0
jni/base/rapidjson/internal/stack.h

@@ -0,0 +1,232 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_STACK_H_
+#define RAPIDJSON_INTERNAL_STACK_H_
+
+#include "../allocators.h"
+#include "swap.h"
+#include <cstddef>
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+///////////////////////////////////////////////////////////////////////////////
+// Stack
+
+//! A type-unsafe stack for storing different types of data.
+/*! \tparam Allocator Allocator for allocating stack memory.
+*/
+template <typename Allocator>
+class Stack {
+public:
+    // Optimization note: Do not allocate memory for stack_ in constructor.
+    // Do it lazily when first Push() -> Expand() -> Resize().
+    Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
+    }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    Stack(Stack&& rhs)
+        : allocator_(rhs.allocator_),
+          ownAllocator_(rhs.ownAllocator_),
+          stack_(rhs.stack_),
+          stackTop_(rhs.stackTop_),
+          stackEnd_(rhs.stackEnd_),
+          initialCapacity_(rhs.initialCapacity_)
+    {
+        rhs.allocator_ = 0;
+        rhs.ownAllocator_ = 0;
+        rhs.stack_ = 0;
+        rhs.stackTop_ = 0;
+        rhs.stackEnd_ = 0;
+        rhs.initialCapacity_ = 0;
+    }
+#endif
+
+    ~Stack() {
+        Destroy();
+    }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    Stack& operator=(Stack&& rhs) {
+        if (&rhs != this)
+        {
+            Destroy();
+
+            allocator_ = rhs.allocator_;
+            ownAllocator_ = rhs.ownAllocator_;
+            stack_ = rhs.stack_;
+            stackTop_ = rhs.stackTop_;
+            stackEnd_ = rhs.stackEnd_;
+            initialCapacity_ = rhs.initialCapacity_;
+
+            rhs.allocator_ = 0;
+            rhs.ownAllocator_ = 0;
+            rhs.stack_ = 0;
+            rhs.stackTop_ = 0;
+            rhs.stackEnd_ = 0;
+            rhs.initialCapacity_ = 0;
+        }
+        return *this;
+    }
+#endif
+
+    void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
+        internal::Swap(allocator_, rhs.allocator_);
+        internal::Swap(ownAllocator_, rhs.ownAllocator_);
+        internal::Swap(stack_, rhs.stack_);
+        internal::Swap(stackTop_, rhs.stackTop_);
+        internal::Swap(stackEnd_, rhs.stackEnd_);
+        internal::Swap(initialCapacity_, rhs.initialCapacity_);
+    }
+
+    void Clear() { stackTop_ = stack_; }
+
+    void ShrinkToFit() { 
+        if (Empty()) {
+            // If the stack is empty, completely deallocate the memory.
+            Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc)
+            stack_ = 0;
+            stackTop_ = 0;
+            stackEnd_ = 0;
+        }
+        else
+            Resize(GetSize());
+    }
+
+    // Optimization note: try to minimize the size of this function for force inline.
+    // Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
+    template<typename T>
+    RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
+         // Expand the stack if needed
+        if (RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_)))
+            Expand<T>(count);
+    }
+
+    template<typename T>
+    RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
+        Reserve<T>(count);
+        return PushUnsafe<T>(count);
+    }
+
+    template<typename T>
+    RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
+        RAPIDJSON_ASSERT(stackTop_);
+        RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_));
+        T* ret = reinterpret_cast<T*>(stackTop_);
+        stackTop_ += sizeof(T) * count;
+        return ret;
+    }
+
+    template<typename T>
+    T* Pop(size_t count) {
+        RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
+        stackTop_ -= count * sizeof(T);
+        return reinterpret_cast<T*>(stackTop_);
+    }
+
+    template<typename T>
+    T* Top() { 
+        RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
+        return reinterpret_cast<T*>(stackTop_ - sizeof(T));
+    }
+
+    template<typename T>
+    const T* Top() const {
+        RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
+        return reinterpret_cast<T*>(stackTop_ - sizeof(T));
+    }
+
+    template<typename T>
+    T* End() { return reinterpret_cast<T*>(stackTop_); }
+
+    template<typename T>
+    const T* End() const { return reinterpret_cast<T*>(stackTop_); }
+
+    template<typename T>
+    T* Bottom() { return reinterpret_cast<T*>(stack_); }
+
+    template<typename T>
+    const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
+
+    bool HasAllocator() const {
+        return allocator_ != 0;
+    }
+
+    Allocator& GetAllocator() {
+        RAPIDJSON_ASSERT(allocator_);
+        return *allocator_;
+    }
+
+    bool Empty() const { return stackTop_ == stack_; }
+    size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
+    size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
+
+private:
+    template<typename T>
+    void Expand(size_t count) {
+        // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
+        size_t newCapacity;
+        if (stack_ == 0) {
+            if (!allocator_)
+                ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
+            newCapacity = initialCapacity_;
+        } else {
+            newCapacity = GetCapacity();
+            newCapacity += (newCapacity + 1) / 2;
+        }
+        size_t newSize = GetSize() + sizeof(T) * count;
+        if (newCapacity < newSize)
+            newCapacity = newSize;
+
+        Resize(newCapacity);
+    }
+
+    void Resize(size_t newCapacity) {
+        const size_t size = GetSize();  // Backup the current size
+        stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
+        stackTop_ = stack_ + size;
+        stackEnd_ = stack_ + newCapacity;
+    }
+
+    void Destroy() {
+        Allocator::Free(stack_);
+        RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
+    }
+
+    // Prohibit copy constructor & assignment operator.
+    Stack(const Stack&);
+    Stack& operator=(const Stack&);
+
+    Allocator* allocator_;
+    Allocator* ownAllocator_;
+    char *stack_;
+    char *stackTop_;
+    char *stackEnd_;
+    size_t initialCapacity_;
+};
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_STACK_H_

+ 69 - 0
jni/base/rapidjson/internal/strfunc.h

@@ -0,0 +1,69 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
+#define RAPIDJSON_INTERNAL_STRFUNC_H_
+
+#include "../stream.h"
+#include <cwchar>
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+//! Custom strlen() which works on different character types.
+/*! \tparam Ch Character type (e.g. char, wchar_t, short)
+    \param s Null-terminated input string.
+    \return Number of characters in the string. 
+    \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
+*/
+template <typename Ch>
+inline SizeType StrLen(const Ch* s) {
+    RAPIDJSON_ASSERT(s != 0);
+    const Ch* p = s;
+    while (*p) ++p;
+    return SizeType(p - s);
+}
+
+template <>
+inline SizeType StrLen(const char* s) {
+    return SizeType(std::strlen(s));
+}
+
+template <>
+inline SizeType StrLen(const wchar_t* s) {
+    return SizeType(std::wcslen(s));
+}
+
+//! Returns number of code points in a encoded string.
+template<typename Encoding>
+bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
+    RAPIDJSON_ASSERT(s != 0);
+    RAPIDJSON_ASSERT(outCount != 0);
+    GenericStringStream<Encoding> is(s);
+    const typename Encoding::Ch* end = s + length;
+    SizeType count = 0;
+    while (is.src_ < end) {
+        unsigned codepoint;
+        if (!Encoding::Decode(is, &codepoint))
+            return false;
+        count++;
+    }
+    *outCount = count;
+    return true;
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_INTERNAL_STRFUNC_H_

+ 290 - 0
jni/base/rapidjson/internal/strtod.h

@@ -0,0 +1,290 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_STRTOD_
+#define RAPIDJSON_STRTOD_
+
+#include "ieee754.h"
+#include "biginteger.h"
+#include "diyfp.h"
+#include "pow10.h"
+#include <climits>
+#include <limits>
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+inline double FastPath(double significand, int exp) {
+    if (exp < -308)
+        return 0.0;
+    else if (exp >= 0)
+        return significand * internal::Pow10(exp);
+    else
+        return significand / internal::Pow10(-exp);
+}
+
+inline double StrtodNormalPrecision(double d, int p) {
+    if (p < -308) {
+        // Prevent expSum < -308, making Pow10(p) = 0
+        d = FastPath(d, -308);
+        d = FastPath(d, p + 308);
+    }
+    else
+        d = FastPath(d, p);
+    return d;
+}
+
+template <typename T>
+inline T Min3(T a, T b, T c) {
+    T m = a;
+    if (m > b) m = b;
+    if (m > c) m = c;
+    return m;
+}
+
+inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
+    const Double db(b);
+    const uint64_t bInt = db.IntegerSignificand();
+    const int bExp = db.IntegerExponent();
+    const int hExp = bExp - 1;
+
+    int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;
+
+    // Adjust for decimal exponent
+    if (dExp >= 0) {
+        dS_Exp2 += dExp;
+        dS_Exp5 += dExp;
+    }
+    else {
+        bS_Exp2 -= dExp;
+        bS_Exp5 -= dExp;
+        hS_Exp2 -= dExp;
+        hS_Exp5 -= dExp;
+    }
+
+    // Adjust for binary exponent
+    if (bExp >= 0)
+        bS_Exp2 += bExp;
+    else {
+        dS_Exp2 -= bExp;
+        hS_Exp2 -= bExp;
+    }
+
+    // Adjust for half ulp exponent
+    if (hExp >= 0)
+        hS_Exp2 += hExp;
+    else {
+        dS_Exp2 -= hExp;
+        bS_Exp2 -= hExp;
+    }
+
+    // Remove common power of two factor from all three scaled values
+    int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
+    dS_Exp2 -= common_Exp2;
+    bS_Exp2 -= common_Exp2;
+    hS_Exp2 -= common_Exp2;
+
+    BigInteger dS = d;
+    dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
+
+    BigInteger bS(bInt);
+    bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
+
+    BigInteger hS(1);
+    hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
+
+    BigInteger delta(0);
+    dS.Difference(bS, &delta);
+
+    return delta.Compare(hS);
+}
+
+inline bool StrtodFast(double d, int p, double* result) {
+    // Use fast path for string-to-double conversion if possible
+    // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
+    if (p > 22  && p < 22 + 16) {
+        // Fast Path Cases In Disguise
+        d *= internal::Pow10(p - 22);
+        p = 22;
+    }
+
+    if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1
+        *result = FastPath(d, p);
+        return true;
+    }
+    else
+        return false;
+}
+
+// Compute an approximation and see if it is within 1/2 ULP
+inline bool StrtodDiyFp(const char* decimals, int dLen, int dExp, double* result) {
+    uint64_t significand = 0;
+    int i = 0;   // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999    
+    for (; i < dLen; i++) {
+        if (significand  >  RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
+            (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
+            break;
+        significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
+    }
+    
+    if (i < dLen && decimals[i] >= '5') // Rounding
+        significand++;
+
+    int remaining = dLen - i;
+    const int kUlpShift = 3;
+    const int kUlp = 1 << kUlpShift;
+    int64_t error = (remaining == 0) ? 0 : kUlp / 2;
+
+    DiyFp v(significand, 0);
+    v = v.Normalize();
+    error <<= -v.e;
+
+    dExp += remaining;
+
+    int actualExp;
+    DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
+    if (actualExp != dExp) {
+        static const DiyFp kPow10[] = {
+            DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 0x00000000), -60),  // 10^1
+            DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 0x00000000), -57),  // 10^2
+            DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 0x00000000), -54),  // 10^3
+            DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), -50),  // 10^4
+            DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 0x00000000), -47),  // 10^5
+            DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 0x00000000), -44),  // 10^6
+            DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 0x00000000), -40)   // 10^7
+        };
+        int adjustment = dExp - actualExp;
+        RAPIDJSON_ASSERT(adjustment >= 1 && adjustment < 8);
+        v = v * kPow10[adjustment - 1];
+        if (dLen + adjustment > 19) // has more digits than decimal digits in 64-bit
+            error += kUlp / 2;
+    }
+
+    v = v * cachedPower;
+
+    error += kUlp + (error == 0 ? 0 : 1);
+
+    const int oldExp = v.e;
+    v = v.Normalize();
+    error <<= oldExp - v.e;
+
+    const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
+    int precisionSize = 64 - effectiveSignificandSize;
+    if (precisionSize + kUlpShift >= 64) {
+        int scaleExp = (precisionSize + kUlpShift) - 63;
+        v.f >>= scaleExp;
+        v.e += scaleExp; 
+        error = (error >> scaleExp) + 1 + kUlp;
+        precisionSize -= scaleExp;
+    }
+
+    DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);
+    const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
+    const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
+    if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
+        rounded.f++;
+        if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
+            rounded.f >>= 1;
+            rounded.e++;
+        }
+    }
+
+    *result = rounded.ToDouble();
+
+    return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
+}
+
+inline double StrtodBigInteger(double approx, const char* decimals, int dLen, int dExp) {
+    RAPIDJSON_ASSERT(dLen >= 0);
+    const BigInteger dInt(decimals, static_cast<unsigned>(dLen));
+    Double a(approx);
+    int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
+    if (cmp < 0)
+        return a.Value();  // within half ULP
+    else if (cmp == 0) {
+        // Round towards even
+        if (a.Significand() & 1)
+            return a.NextPositiveDouble();
+        else
+            return a.Value();
+    }
+    else // adjustment
+        return a.NextPositiveDouble();
+}
+
+inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
+    RAPIDJSON_ASSERT(d >= 0.0);
+    RAPIDJSON_ASSERT(length >= 1);
+
+    double result = 0.0;
+    if (StrtodFast(d, p, &result))
+        return result;
+
+    RAPIDJSON_ASSERT(length <= INT_MAX);
+    int dLen = static_cast<int>(length);
+
+    RAPIDJSON_ASSERT(length >= decimalPosition);
+    RAPIDJSON_ASSERT(length - decimalPosition <= INT_MAX);
+    int dExpAdjust = static_cast<int>(length - decimalPosition);
+
+    RAPIDJSON_ASSERT(exp >= INT_MIN + dExpAdjust);
+    int dExp = exp - dExpAdjust;
+
+    // Make sure length+dExp does not overflow
+    RAPIDJSON_ASSERT(dExp <= INT_MAX - dLen);
+
+    // Trim leading zeros
+    while (dLen > 0 && *decimals == '0') {
+        dLen--;
+        decimals++;
+    }
+
+    // Trim trailing zeros
+    while (dLen > 0 && decimals[dLen - 1] == '0') {
+        dLen--;
+        dExp++;
+    }
+
+    if (dLen == 0) { // Buffer only contains zeros.
+        return 0.0;
+    }
+
+    // Trim right-most digits
+    const int kMaxDecimalDigit = 767 + 1;
+    if (dLen > kMaxDecimalDigit) {
+        dExp += dLen - kMaxDecimalDigit;
+        dLen = kMaxDecimalDigit;
+    }
+
+    // If too small, underflow to zero.
+    // Any x <= 10^-324 is interpreted as zero.
+    if (dLen + dExp <= -324)
+        return 0.0;
+
+    // If too large, overflow to infinity.
+    // Any x >= 10^309 is interpreted as +infinity.
+    if (dLen + dExp > 309)
+        return std::numeric_limits<double>::infinity();
+
+    if (StrtodDiyFp(decimals, dLen, dExp, &result))
+        return result;
+
+    // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
+    return StrtodBigInteger(result, decimals, dLen, dExp);
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_STRTOD_

+ 46 - 0
jni/base/rapidjson/internal/swap.h

@@ -0,0 +1,46 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_SWAP_H_
+#define RAPIDJSON_INTERNAL_SWAP_H_
+
+#include "../rapidjson.h"
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+//! Custom swap() to avoid dependency on C++ <algorithm> header
+/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
+    \note This has the same semantics as std::swap().
+*/
+template <typename T>
+inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
+    T tmp = a;
+        a = b;
+        b = tmp;
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_INTERNAL_SWAP_H_

+ 128 - 0
jni/base/rapidjson/istreamwrapper.h

@@ -0,0 +1,128 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ISTREAMWRAPPER_H_
+#define RAPIDJSON_ISTREAMWRAPPER_H_
+
+#include "stream.h"
+#include <iosfwd>
+#include <ios>
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#elif defined(_MSC_VER)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept.
+/*!
+    The classes can be wrapped including but not limited to:
+
+    - \c std::istringstream
+    - \c std::stringstream
+    - \c std::wistringstream
+    - \c std::wstringstream
+    - \c std::ifstream
+    - \c std::fstream
+    - \c std::wifstream
+    - \c std::wfstream
+
+    \tparam StreamType Class derived from \c std::basic_istream.
+*/
+   
+template <typename StreamType>
+class BasicIStreamWrapper {
+public:
+    typedef typename StreamType::char_type Ch;
+
+    //! Constructor.
+    /*!
+        \param stream stream opened for read.
+    */
+    BasicIStreamWrapper(StreamType &stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 
+        Read();
+    }
+
+    //! Constructor.
+    /*!
+        \param stream stream opened for read.
+        \param buffer user-supplied buffer.
+        \param bufferSize size of buffer in bytes. Must >=4 bytes.
+    */
+    BasicIStreamWrapper(StreamType &stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 
+        RAPIDJSON_ASSERT(bufferSize >= 4);
+        Read();
+    }
+
+    Ch Peek() const { return *current_; }
+    Ch Take() { Ch c = *current_; Read(); return c; }
+    size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
+
+    // Not implemented
+    void Put(Ch) { RAPIDJSON_ASSERT(false); }
+    void Flush() { RAPIDJSON_ASSERT(false); } 
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+    // For encoding detection only.
+    const Ch* Peek4() const {
+        return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;
+    }
+
+private:
+    BasicIStreamWrapper();
+    BasicIStreamWrapper(const BasicIStreamWrapper&);
+    BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
+
+    void Read() {
+        if (current_ < bufferLast_)
+            ++current_;
+        else if (!eof_) {
+            count_ += readCount_;
+            readCount_ = bufferSize_;
+            bufferLast_ = buffer_ + readCount_ - 1;
+            current_ = buffer_;
+
+            if (!stream_.read(buffer_, static_cast<std::streamsize>(bufferSize_))) {
+                readCount_ = static_cast<size_t>(stream_.gcount());
+                *(bufferLast_ = buffer_ + readCount_) = '\0';
+                eof_ = true;
+            }
+        }
+    }
+
+    StreamType &stream_;
+    Ch peekBuffer_[4], *buffer_;
+    size_t bufferSize_;
+    Ch *bufferLast_;
+    Ch *current_;
+    size_t readCount_;
+    size_t count_;  //!< Number of characters read
+    bool eof_;
+};
+
+typedef BasicIStreamWrapper<std::istream> IStreamWrapper;
+typedef BasicIStreamWrapper<std::wistream> WIStreamWrapper;
+
+#if defined(__clang__) || defined(_MSC_VER)
+RAPIDJSON_DIAG_POP
+#endif
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_ISTREAMWRAPPER_H_

+ 70 - 0
jni/base/rapidjson/memorybuffer.h

@@ -0,0 +1,70 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_MEMORYBUFFER_H_
+#define RAPIDJSON_MEMORYBUFFER_H_
+
+#include "stream.h"
+#include "internal/stack.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Represents an in-memory output byte stream.
+/*!
+    This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream.
+
+    It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.
+
+    Differences between MemoryBuffer and StringBuffer:
+    1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. 
+    2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.
+
+    \tparam Allocator type for allocating memory buffer.
+    \note implements Stream concept
+*/
+template <typename Allocator = CrtAllocator>
+struct GenericMemoryBuffer {
+    typedef char Ch; // byte
+
+    GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
+
+    void Put(Ch c) { *stack_.template Push<Ch>() = c; }
+    void Flush() {}
+
+    void Clear() { stack_.Clear(); }
+    void ShrinkToFit() { stack_.ShrinkToFit(); }
+    Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
+    void Pop(size_t count) { stack_.template Pop<Ch>(count); }
+
+    const Ch* GetBuffer() const {
+        return stack_.template Bottom<Ch>();
+    }
+
+    size_t GetSize() const { return stack_.GetSize(); }
+
+    static const size_t kDefaultCapacity = 256;
+    mutable internal::Stack<Allocator> stack_;
+};
+
+typedef GenericMemoryBuffer<> MemoryBuffer;
+
+//! Implement specialized version of PutN() with memset() for better performance.
+template<>
+inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {
+    std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_MEMORYBUFFER_H_

+ 71 - 0
jni/base/rapidjson/memorystream.h

@@ -0,0 +1,71 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_MEMORYSTREAM_H_
+#define RAPIDJSON_MEMORYSTREAM_H_
+
+#include "stream.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(unreachable-code)
+RAPIDJSON_DIAG_OFF(missing-noreturn)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Represents an in-memory input byte stream.
+/*!
+    This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream.
+
+    It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file.
+
+    Differences between MemoryStream and StringStream:
+    1. StringStream has encoding but MemoryStream is a byte stream.
+    2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source.
+    3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4().
+    \note implements Stream concept
+*/
+struct MemoryStream {
+    typedef char Ch; // byte
+
+    MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
+
+    Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; }
+    Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; }
+    size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
+
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    void Put(Ch) { RAPIDJSON_ASSERT(false); }
+    void Flush() { RAPIDJSON_ASSERT(false); }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+    // For encoding detection only.
+    const Ch* Peek4() const {
+        return Tell() + 4 <= size_ ? src_ : 0;
+    }
+
+    const Ch* src_;     //!< Current read position.
+    const Ch* begin_;   //!< Original head of the string.
+    const Ch* end_;     //!< End of stream.
+    size_t size_;       //!< Size of the stream.
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_MEMORYBUFFER_H_

+ 316 - 0
jni/base/rapidjson/msinttypes/inttypes.h

@@ -0,0 +1,316 @@
+// ISO C9x  compliant inttypes.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 
+// 
+//  Copyright (c) 2006-2013 Alexander Chemeris
+// 
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+// 
+//   1. Redistributions of source code must retain the above copyright notice,
+//      this list of conditions and the following disclaimer.
+// 
+//   2. Redistributions in binary form must reproduce the above copyright
+//      notice, this list of conditions and the following disclaimer in the
+//      documentation and/or other materials provided with the distribution.
+// 
+//   3. Neither the name of the product nor the names of its contributors may
+//      be used to endorse or promote products derived from this software
+//      without specific prior written permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// 
+///////////////////////////////////////////////////////////////////////////////
+
+// The above software in this distribution may have been modified by 
+// THL A29 Limited ("Tencent Modifications"). 
+// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_INTTYPES_H_ // [
+#define _MSC_INTTYPES_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include "stdint.h"
+
+// miloyip: VC supports inttypes.h since VC2013
+#if _MSC_VER >= 1800
+#include <inttypes.h>
+#else
+
+// 7.8 Format conversion of integer types
+
+typedef struct {
+   intmax_t quot;
+   intmax_t rem;
+} imaxdiv_t;
+
+// 7.8.1 Macros for format specifiers
+
+#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [   See footnote 185 at page 198
+
+// The fprintf macros for signed integers are:
+#define PRId8       "d"
+#define PRIi8       "i"
+#define PRIdLEAST8  "d"
+#define PRIiLEAST8  "i"
+#define PRIdFAST8   "d"
+#define PRIiFAST8   "i"
+
+#define PRId16       "hd"
+#define PRIi16       "hi"
+#define PRIdLEAST16  "hd"
+#define PRIiLEAST16  "hi"
+#define PRIdFAST16   "hd"
+#define PRIiFAST16   "hi"
+
+#define PRId32       "I32d"
+#define PRIi32       "I32i"
+#define PRIdLEAST32  "I32d"
+#define PRIiLEAST32  "I32i"
+#define PRIdFAST32   "I32d"
+#define PRIiFAST32   "I32i"
+
+#define PRId64       "I64d"
+#define PRIi64       "I64i"
+#define PRIdLEAST64  "I64d"
+#define PRIiLEAST64  "I64i"
+#define PRIdFAST64   "I64d"
+#define PRIiFAST64   "I64i"
+
+#define PRIdMAX     "I64d"
+#define PRIiMAX     "I64i"
+
+#define PRIdPTR     "Id"
+#define PRIiPTR     "Ii"
+
+// The fprintf macros for unsigned integers are:
+#define PRIo8       "o"
+#define PRIu8       "u"
+#define PRIx8       "x"
+#define PRIX8       "X"
+#define PRIoLEAST8  "o"
+#define PRIuLEAST8  "u"
+#define PRIxLEAST8  "x"
+#define PRIXLEAST8  "X"
+#define PRIoFAST8   "o"
+#define PRIuFAST8   "u"
+#define PRIxFAST8   "x"
+#define PRIXFAST8   "X"
+
+#define PRIo16       "ho"
+#define PRIu16       "hu"
+#define PRIx16       "hx"
+#define PRIX16       "hX"
+#define PRIoLEAST16  "ho"
+#define PRIuLEAST16  "hu"
+#define PRIxLEAST16  "hx"
+#define PRIXLEAST16  "hX"
+#define PRIoFAST16   "ho"
+#define PRIuFAST16   "hu"
+#define PRIxFAST16   "hx"
+#define PRIXFAST16   "hX"
+
+#define PRIo32       "I32o"
+#define PRIu32       "I32u"
+#define PRIx32       "I32x"
+#define PRIX32       "I32X"
+#define PRIoLEAST32  "I32o"
+#define PRIuLEAST32  "I32u"
+#define PRIxLEAST32  "I32x"
+#define PRIXLEAST32  "I32X"
+#define PRIoFAST32   "I32o"
+#define PRIuFAST32   "I32u"
+#define PRIxFAST32   "I32x"
+#define PRIXFAST32   "I32X"
+
+#define PRIo64       "I64o"
+#define PRIu64       "I64u"
+#define PRIx64       "I64x"
+#define PRIX64       "I64X"
+#define PRIoLEAST64  "I64o"
+#define PRIuLEAST64  "I64u"
+#define PRIxLEAST64  "I64x"
+#define PRIXLEAST64  "I64X"
+#define PRIoFAST64   "I64o"
+#define PRIuFAST64   "I64u"
+#define PRIxFAST64   "I64x"
+#define PRIXFAST64   "I64X"
+
+#define PRIoMAX     "I64o"
+#define PRIuMAX     "I64u"
+#define PRIxMAX     "I64x"
+#define PRIXMAX     "I64X"
+
+#define PRIoPTR     "Io"
+#define PRIuPTR     "Iu"
+#define PRIxPTR     "Ix"
+#define PRIXPTR     "IX"
+
+// The fscanf macros for signed integers are:
+#define SCNd8       "d"
+#define SCNi8       "i"
+#define SCNdLEAST8  "d"
+#define SCNiLEAST8  "i"
+#define SCNdFAST8   "d"
+#define SCNiFAST8   "i"
+
+#define SCNd16       "hd"
+#define SCNi16       "hi"
+#define SCNdLEAST16  "hd"
+#define SCNiLEAST16  "hi"
+#define SCNdFAST16   "hd"
+#define SCNiFAST16   "hi"
+
+#define SCNd32       "ld"
+#define SCNi32       "li"
+#define SCNdLEAST32  "ld"
+#define SCNiLEAST32  "li"
+#define SCNdFAST32   "ld"
+#define SCNiFAST32   "li"
+
+#define SCNd64       "I64d"
+#define SCNi64       "I64i"
+#define SCNdLEAST64  "I64d"
+#define SCNiLEAST64  "I64i"
+#define SCNdFAST64   "I64d"
+#define SCNiFAST64   "I64i"
+
+#define SCNdMAX     "I64d"
+#define SCNiMAX     "I64i"
+
+#ifdef _WIN64 // [
+#  define SCNdPTR     "I64d"
+#  define SCNiPTR     "I64i"
+#else  // _WIN64 ][
+#  define SCNdPTR     "ld"
+#  define SCNiPTR     "li"
+#endif  // _WIN64 ]
+
+// The fscanf macros for unsigned integers are:
+#define SCNo8       "o"
+#define SCNu8       "u"
+#define SCNx8       "x"
+#define SCNX8       "X"
+#define SCNoLEAST8  "o"
+#define SCNuLEAST8  "u"
+#define SCNxLEAST8  "x"
+#define SCNXLEAST8  "X"
+#define SCNoFAST8   "o"
+#define SCNuFAST8   "u"
+#define SCNxFAST8   "x"
+#define SCNXFAST8   "X"
+
+#define SCNo16       "ho"
+#define SCNu16       "hu"
+#define SCNx16       "hx"
+#define SCNX16       "hX"
+#define SCNoLEAST16  "ho"
+#define SCNuLEAST16  "hu"
+#define SCNxLEAST16  "hx"
+#define SCNXLEAST16  "hX"
+#define SCNoFAST16   "ho"
+#define SCNuFAST16   "hu"
+#define SCNxFAST16   "hx"
+#define SCNXFAST16   "hX"
+
+#define SCNo32       "lo"
+#define SCNu32       "lu"
+#define SCNx32       "lx"
+#define SCNX32       "lX"
+#define SCNoLEAST32  "lo"
+#define SCNuLEAST32  "lu"
+#define SCNxLEAST32  "lx"
+#define SCNXLEAST32  "lX"
+#define SCNoFAST32   "lo"
+#define SCNuFAST32   "lu"
+#define SCNxFAST32   "lx"
+#define SCNXFAST32   "lX"
+
+#define SCNo64       "I64o"
+#define SCNu64       "I64u"
+#define SCNx64       "I64x"
+#define SCNX64       "I64X"
+#define SCNoLEAST64  "I64o"
+#define SCNuLEAST64  "I64u"
+#define SCNxLEAST64  "I64x"
+#define SCNXLEAST64  "I64X"
+#define SCNoFAST64   "I64o"
+#define SCNuFAST64   "I64u"
+#define SCNxFAST64   "I64x"
+#define SCNXFAST64   "I64X"
+
+#define SCNoMAX     "I64o"
+#define SCNuMAX     "I64u"
+#define SCNxMAX     "I64x"
+#define SCNXMAX     "I64X"
+
+#ifdef _WIN64 // [
+#  define SCNoPTR     "I64o"
+#  define SCNuPTR     "I64u"
+#  define SCNxPTR     "I64x"
+#  define SCNXPTR     "I64X"
+#else  // _WIN64 ][
+#  define SCNoPTR     "lo"
+#  define SCNuPTR     "lu"
+#  define SCNxPTR     "lx"
+#  define SCNXPTR     "lX"
+#endif  // _WIN64 ]
+
+#endif // __STDC_FORMAT_MACROS ]
+
+// 7.8.2 Functions for greatest-width integer types
+
+// 7.8.2.1 The imaxabs function
+#define imaxabs _abs64
+
+// 7.8.2.2 The imaxdiv function
+
+// This is modified version of div() function from Microsoft's div.c found
+// in %MSVC.NET%\crt\src\div.c
+#ifdef STATIC_IMAXDIV // [
+static
+#else // STATIC_IMAXDIV ][
+_inline
+#endif // STATIC_IMAXDIV ]
+imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
+{
+   imaxdiv_t result;
+
+   result.quot = numer / denom;
+   result.rem = numer % denom;
+
+   if (numer < 0 && result.rem > 0) {
+      // did division wrong; must fix up
+      ++result.quot;
+      result.rem -= denom;
+   }
+
+   return result;
+}
+
+// 7.8.2.3 The strtoimax and strtoumax functions
+#define strtoimax _strtoi64
+#define strtoumax _strtoui64
+
+// 7.8.2.4 The wcstoimax and wcstoumax functions
+#define wcstoimax _wcstoi64
+#define wcstoumax _wcstoui64
+
+#endif // _MSC_VER >= 1800
+
+#endif // _MSC_INTTYPES_H_ ]

+ 300 - 0
jni/base/rapidjson/msinttypes/stdint.h

@@ -0,0 +1,300 @@
+// ISO C9x  compliant stdint.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 
+// 
+//  Copyright (c) 2006-2013 Alexander Chemeris
+// 
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+// 
+//   1. Redistributions of source code must retain the above copyright notice,
+//      this list of conditions and the following disclaimer.
+// 
+//   2. Redistributions in binary form must reproduce the above copyright
+//      notice, this list of conditions and the following disclaimer in the
+//      documentation and/or other materials provided with the distribution.
+// 
+//   3. Neither the name of the product nor the names of its contributors may
+//      be used to endorse or promote products derived from this software
+//      without specific prior written permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// 
+///////////////////////////////////////////////////////////////////////////////
+
+// The above software in this distribution may have been modified by 
+// THL A29 Limited ("Tencent Modifications"). 
+// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_STDINT_H_ // [
+#define _MSC_STDINT_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010.
+#if _MSC_VER >= 1600 // [
+#include <stdint.h>
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [   See footnote 224 at page 260
+
+#undef INT8_C
+#undef INT16_C
+#undef INT32_C
+#undef INT64_C
+#undef UINT8_C
+#undef UINT16_C
+#undef UINT32_C
+#undef UINT64_C
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val)  val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val)  val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
+// Check out Issue 9 for the details.
+#ifndef INTMAX_C //   [
+#  define INTMAX_C   INT64_C
+#endif // INTMAX_C    ]
+#ifndef UINTMAX_C //  [
+#  define UINTMAX_C  UINT64_C
+#endif // UINTMAX_C   ]
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+#else // ] _MSC_VER >= 1700 [
+
+#include <limits.h>
+
+// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
+// compiling for ARM we have to wrap <wchar.h> include with 'extern "C++" {}'
+// or compiler would give many errors like this:
+//   error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#if defined(__cplusplus) && !defined(_M_ARM)
+extern "C" {
+#endif
+#  include <wchar.h>
+#if defined(__cplusplus) && !defined(_M_ARM)
+}
+#endif
+
+// Define _W64 macros to mark types changing their size, like intptr_t.
+#ifndef _W64
+#  if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+#     define _W64 __w64
+#  else
+#     define _W64
+#  endif
+#endif
+
+
+// 7.18.1 Integer types
+
+// 7.18.1.1 Exact-width integer types
+
+// Visual Studio 6 and Embedded Visual C++ 4 doesn't
+// realize that, e.g. char has the same size as __int8
+// so we give up on __intX for them.
+#if (_MSC_VER < 1300)
+   typedef signed char       int8_t;
+   typedef signed short      int16_t;
+   typedef signed int        int32_t;
+   typedef unsigned char     uint8_t;
+   typedef unsigned short    uint16_t;
+   typedef unsigned int      uint32_t;
+#else
+   typedef signed __int8     int8_t;
+   typedef signed __int16    int16_t;
+   typedef signed __int32    int32_t;
+   typedef unsigned __int8   uint8_t;
+   typedef unsigned __int16  uint16_t;
+   typedef unsigned __int32  uint32_t;
+#endif
+typedef signed __int64       int64_t;
+typedef unsigned __int64     uint64_t;
+
+
+// 7.18.1.2 Minimum-width integer types
+typedef int8_t    int_least8_t;
+typedef int16_t   int_least16_t;
+typedef int32_t   int_least32_t;
+typedef int64_t   int_least64_t;
+typedef uint8_t   uint_least8_t;
+typedef uint16_t  uint_least16_t;
+typedef uint32_t  uint_least32_t;
+typedef uint64_t  uint_least64_t;
+
+// 7.18.1.3 Fastest minimum-width integer types
+typedef int8_t    int_fast8_t;
+typedef int16_t   int_fast16_t;
+typedef int32_t   int_fast32_t;
+typedef int64_t   int_fast64_t;
+typedef uint8_t   uint_fast8_t;
+typedef uint16_t  uint_fast16_t;
+typedef uint32_t  uint_fast32_t;
+typedef uint64_t  uint_fast64_t;
+
+// 7.18.1.4 Integer types capable of holding object pointers
+#ifdef _WIN64 // [
+   typedef signed __int64    intptr_t;
+   typedef unsigned __int64  uintptr_t;
+#else // _WIN64 ][
+   typedef _W64 signed int   intptr_t;
+   typedef _W64 unsigned int uintptr_t;
+#endif // _WIN64 ]
+
+// 7.18.1.5 Greatest-width integer types
+typedef int64_t   intmax_t;
+typedef uint64_t  uintmax_t;
+
+
+// 7.18.2 Limits of specified-width integer types
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [   See footnote 220 at page 257 and footnote 221 at page 259
+
+// 7.18.2.1 Limits of exact-width integer types
+#define INT8_MIN     ((int8_t)_I8_MIN)
+#define INT8_MAX     _I8_MAX
+#define INT16_MIN    ((int16_t)_I16_MIN)
+#define INT16_MAX    _I16_MAX
+#define INT32_MIN    ((int32_t)_I32_MIN)
+#define INT32_MAX    _I32_MAX
+#define INT64_MIN    ((int64_t)_I64_MIN)
+#define INT64_MAX    _I64_MAX
+#define UINT8_MAX    _UI8_MAX
+#define UINT16_MAX   _UI16_MAX
+#define UINT32_MAX   _UI32_MAX
+#define UINT64_MAX   _UI64_MAX
+
+// 7.18.2.2 Limits of minimum-width integer types
+#define INT_LEAST8_MIN    INT8_MIN
+#define INT_LEAST8_MAX    INT8_MAX
+#define INT_LEAST16_MIN   INT16_MIN
+#define INT_LEAST16_MAX   INT16_MAX
+#define INT_LEAST32_MIN   INT32_MIN
+#define INT_LEAST32_MAX   INT32_MAX
+#define INT_LEAST64_MIN   INT64_MIN
+#define INT_LEAST64_MAX   INT64_MAX
+#define UINT_LEAST8_MAX   UINT8_MAX
+#define UINT_LEAST16_MAX  UINT16_MAX
+#define UINT_LEAST32_MAX  UINT32_MAX
+#define UINT_LEAST64_MAX  UINT64_MAX
+
+// 7.18.2.3 Limits of fastest minimum-width integer types
+#define INT_FAST8_MIN    INT8_MIN
+#define INT_FAST8_MAX    INT8_MAX
+#define INT_FAST16_MIN   INT16_MIN
+#define INT_FAST16_MAX   INT16_MAX
+#define INT_FAST32_MIN   INT32_MIN
+#define INT_FAST32_MAX   INT32_MAX
+#define INT_FAST64_MIN   INT64_MIN
+#define INT_FAST64_MAX   INT64_MAX
+#define UINT_FAST8_MAX   UINT8_MAX
+#define UINT_FAST16_MAX  UINT16_MAX
+#define UINT_FAST32_MAX  UINT32_MAX
+#define UINT_FAST64_MAX  UINT64_MAX
+
+// 7.18.2.4 Limits of integer types capable of holding object pointers
+#ifdef _WIN64 // [
+#  define INTPTR_MIN   INT64_MIN
+#  define INTPTR_MAX   INT64_MAX
+#  define UINTPTR_MAX  UINT64_MAX
+#else // _WIN64 ][
+#  define INTPTR_MIN   INT32_MIN
+#  define INTPTR_MAX   INT32_MAX
+#  define UINTPTR_MAX  UINT32_MAX
+#endif // _WIN64 ]
+
+// 7.18.2.5 Limits of greatest-width integer types
+#define INTMAX_MIN   INT64_MIN
+#define INTMAX_MAX   INT64_MAX
+#define UINTMAX_MAX  UINT64_MAX
+
+// 7.18.3 Limits of other integer types
+
+#ifdef _WIN64 // [
+#  define PTRDIFF_MIN  _I64_MIN
+#  define PTRDIFF_MAX  _I64_MAX
+#else  // _WIN64 ][
+#  define PTRDIFF_MIN  _I32_MIN
+#  define PTRDIFF_MAX  _I32_MAX
+#endif  // _WIN64 ]
+
+#define SIG_ATOMIC_MIN  INT_MIN
+#define SIG_ATOMIC_MAX  INT_MAX
+
+#ifndef SIZE_MAX // [
+#  ifdef _WIN64 // [
+#     define SIZE_MAX  _UI64_MAX
+#  else // _WIN64 ][
+#     define SIZE_MAX  _UI32_MAX
+#  endif // _WIN64 ]
+#endif // SIZE_MAX ]
+
+// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
+#ifndef WCHAR_MIN // [
+#  define WCHAR_MIN  0
+#endif  // WCHAR_MIN ]
+#ifndef WCHAR_MAX // [
+#  define WCHAR_MAX  _UI16_MAX
+#endif  // WCHAR_MAX ]
+
+#define WINT_MIN  0
+#define WINT_MAX  _UI16_MAX
+
+#endif // __STDC_LIMIT_MACROS ]
+
+
+// 7.18.4 Limits of other integer types
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [   See footnote 224 at page 260
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val)  val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val)  val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
+// Check out Issue 9 for the details.
+#ifndef INTMAX_C //   [
+#  define INTMAX_C   INT64_C
+#endif // INTMAX_C    ]
+#ifndef UINTMAX_C //  [
+#  define UINTMAX_C  UINT64_C
+#endif // UINTMAX_C   ]
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+#endif // _MSC_VER >= 1600 ]
+
+#endif // _MSC_STDINT_H_ ]

+ 81 - 0
jni/base/rapidjson/ostreamwrapper.h

@@ -0,0 +1,81 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_OSTREAMWRAPPER_H_
+#define RAPIDJSON_OSTREAMWRAPPER_H_
+
+#include "stream.h"
+#include <iosfwd>
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept.
+/*!
+    The classes can be wrapped including but not limited to:
+
+    - \c std::ostringstream
+    - \c std::stringstream
+    - \c std::wpstringstream
+    - \c std::wstringstream
+    - \c std::ifstream
+    - \c std::fstream
+    - \c std::wofstream
+    - \c std::wfstream
+
+    \tparam StreamType Class derived from \c std::basic_ostream.
+*/
+   
+template <typename StreamType>
+class BasicOStreamWrapper {
+public:
+    typedef typename StreamType::char_type Ch;
+    BasicOStreamWrapper(StreamType& stream) : stream_(stream) {}
+
+    void Put(Ch c) {
+        stream_.put(c);
+    }
+
+    void Flush() {
+        stream_.flush();
+    }
+
+    // Not implemented
+    char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
+    char Take() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
+    char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+    BasicOStreamWrapper(const BasicOStreamWrapper&);
+    BasicOStreamWrapper& operator=(const BasicOStreamWrapper&);
+
+    StreamType& stream_;
+};
+
+typedef BasicOStreamWrapper<std::ostream> OStreamWrapper;
+typedef BasicOStreamWrapper<std::wostream> WOStreamWrapper;
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_OSTREAMWRAPPER_H_

File diff suppressed because it is too large
+ 1415 - 0
jni/base/rapidjson/pointer.h


+ 277 - 0
jni/base/rapidjson/prettywriter.h

@@ -0,0 +1,277 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_PRETTYWRITER_H_
+#define RAPIDJSON_PRETTYWRITER_H_
+
+#include "writer.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Combination of PrettyWriter format flags.
+/*! \see PrettyWriter::SetFormatOptions
+ */
+enum PrettyFormatOptions {
+    kFormatDefault = 0,         //!< Default pretty formatting.
+    kFormatSingleLineArray = 1  //!< Format arrays on a single line.
+};
+
+//! Writer with indentation and spacing.
+/*!
+    \tparam OutputStream Type of output os.
+    \tparam SourceEncoding Encoding of source string.
+    \tparam TargetEncoding Encoding of output stream.
+    \tparam StackAllocator Type of allocator for allocating memory of stack.
+*/
+template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
+class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {
+public:
+    typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> Base;
+    typedef typename Base::Ch Ch;
+
+    //! Constructor
+    /*! \param os Output stream.
+        \param allocator User supplied allocator. If it is null, it will create a private one.
+        \param levelDepth Initial capacity of stack.
+    */
+    explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : 
+        Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
+
+
+    explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : 
+        Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    PrettyWriter(PrettyWriter&& rhs) :
+        Base(std::forward<PrettyWriter>(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {}
+#endif
+
+    //! Set custom indentation.
+    /*! \param indentChar       Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
+        \param indentCharCount  Number of indent characters for each indentation level.
+        \note The default indentation is 4 spaces.
+    */
+    PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
+        RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
+        indentChar_ = indentChar;
+        indentCharCount_ = indentCharCount;
+        return *this;
+    }
+
+    //! Set pretty writer formatting options.
+    /*! \param options Formatting options.
+    */
+    PrettyWriter& SetFormatOptions(PrettyFormatOptions options) {
+        formatOptions_ = options;
+        return *this;
+    }
+
+    /*! @name Implementation of Handler
+        \see Handler
+    */
+    //@{
+
+    bool Null()                 { PrettyPrefix(kNullType);   return Base::EndValue(Base::WriteNull()); }
+    bool Bool(bool b)           { PrettyPrefix(b ? kTrueType : kFalseType); return Base::EndValue(Base::WriteBool(b)); }
+    bool Int(int i)             { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt(i)); }
+    bool Uint(unsigned u)       { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint(u)); }
+    bool Int64(int64_t i64)     { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt64(i64)); }
+    bool Uint64(uint64_t u64)   { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint64(u64));  }
+    bool Double(double d)       { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteDouble(d)); }
+
+    bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
+        RAPIDJSON_ASSERT(str != 0);
+        (void)copy;
+        PrettyPrefix(kNumberType);
+        return Base::EndValue(Base::WriteString(str, length));
+    }
+
+    bool String(const Ch* str, SizeType length, bool copy = false) {
+        RAPIDJSON_ASSERT(str != 0);
+        (void)copy;
+        PrettyPrefix(kStringType);
+        return Base::EndValue(Base::WriteString(str, length));
+    }
+
+#if RAPIDJSON_HAS_STDSTRING
+    bool String(const std::basic_string<Ch>& str) {
+        return String(str.data(), SizeType(str.size()));
+    }
+#endif
+
+    bool StartObject() {
+        PrettyPrefix(kObjectType);
+        new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
+        return Base::WriteStartObject();
+    }
+
+    bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
+
+#if RAPIDJSON_HAS_STDSTRING
+    bool Key(const std::basic_string<Ch>& str) {
+        return Key(str.data(), SizeType(str.size()));
+    }
+#endif
+	
+    bool EndObject(SizeType memberCount = 0) {
+        (void)memberCount;
+        RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object
+        RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray); // currently inside an Array, not Object
+        RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top<typename Base::Level>()->valueCount % 2); // Object has a Key without a Value
+       
+        bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
+
+        if (!empty) {
+            Base::os_->Put('\n');
+            WriteIndent();
+        }
+        bool ret = Base::EndValue(Base::WriteEndObject());
+        (void)ret;
+        RAPIDJSON_ASSERT(ret == true);
+        if (Base::level_stack_.Empty()) // end of json text
+            Base::Flush();
+        return true;
+    }
+
+    bool StartArray() {
+        PrettyPrefix(kArrayType);
+        new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
+        return Base::WriteStartArray();
+    }
+
+    bool EndArray(SizeType memberCount = 0) {
+        (void)memberCount;
+        RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
+        RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
+        bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
+
+        if (!empty && !(formatOptions_ & kFormatSingleLineArray)) {
+            Base::os_->Put('\n');
+            WriteIndent();
+        }
+        bool ret = Base::EndValue(Base::WriteEndArray());
+        (void)ret;
+        RAPIDJSON_ASSERT(ret == true);
+        if (Base::level_stack_.Empty()) // end of json text
+            Base::Flush();
+        return true;
+    }
+
+    //@}
+
+    /*! @name Convenience extensions */
+    //@{
+
+    //! Simpler but slower overload.
+    bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
+    bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
+
+    //@}
+
+    //! Write a raw JSON value.
+    /*!
+        For user to write a stringified JSON as a value.
+
+        \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
+        \param length Length of the json.
+        \param type Type of the root of json.
+        \note When using PrettyWriter::RawValue(), the result json may not be indented correctly.
+    */
+    bool RawValue(const Ch* json, size_t length, Type type) {
+        RAPIDJSON_ASSERT(json != 0);
+        PrettyPrefix(type);
+        return Base::EndValue(Base::WriteRawValue(json, length));
+    }
+
+protected:
+    void PrettyPrefix(Type type) {
+        (void)type;
+        if (Base::level_stack_.GetSize() != 0) { // this value is not at root
+            typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
+
+            if (level->inArray) {
+                if (level->valueCount > 0) {
+                    Base::os_->Put(','); // add comma if it is not the first element in array
+                    if (formatOptions_ & kFormatSingleLineArray)
+                        Base::os_->Put(' ');
+                }
+
+                if (!(formatOptions_ & kFormatSingleLineArray)) {
+                    Base::os_->Put('\n');
+                    WriteIndent();
+                }
+            }
+            else {  // in object
+                if (level->valueCount > 0) {
+                    if (level->valueCount % 2 == 0) {
+                        Base::os_->Put(',');
+                        Base::os_->Put('\n');
+                    }
+                    else {
+                        Base::os_->Put(':');
+                        Base::os_->Put(' ');
+                    }
+                }
+                else
+                    Base::os_->Put('\n');
+
+                if (level->valueCount % 2 == 0)
+                    WriteIndent();
+            }
+            if (!level->inArray && level->valueCount % 2 == 0)
+                RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name
+            level->valueCount++;
+        }
+        else {
+            RAPIDJSON_ASSERT(!Base::hasRoot_);  // Should only has one and only one root.
+            Base::hasRoot_ = true;
+        }
+    }
+
+    void WriteIndent()  {
+        size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
+        PutN(*Base::os_, static_cast<typename OutputStream::Ch>(indentChar_), count);
+    }
+
+    Ch indentChar_;
+    unsigned indentCharCount_;
+    PrettyFormatOptions formatOptions_;
+
+private:
+    // Prohibit copy constructor & assignment operator.
+    PrettyWriter(const PrettyWriter&);
+    PrettyWriter& operator=(const PrettyWriter&);
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_RAPIDJSON_H_

+ 658 - 0
jni/base/rapidjson/rapidjson.h

@@ -0,0 +1,658 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_RAPIDJSON_H_
+#define RAPIDJSON_RAPIDJSON_H_
+
+/*!\file rapidjson.h
+    \brief common definitions and configuration
+    
+    \see RAPIDJSON_CONFIG
+ */
+
+/*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration
+    \brief Configuration macros for library features
+
+    Some RapidJSON features are configurable to adapt the library to a wide
+    variety of platforms, environments and usage scenarios.  Most of the
+    features can be configured in terms of overridden or predefined
+    preprocessor macros at compile-time.
+
+    Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs.
+
+    \note These macros should be given on the compiler command-line
+          (where applicable)  to avoid inconsistent values when compiling
+          different translation units of a single application.
+ */
+
+#include <cstdlib>  // malloc(), realloc(), free(), size_t
+#include <cstring>  // memset(), memcpy(), memmove(), memcmp()
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_VERSION_STRING
+//
+// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt.
+//
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+// token stringification
+#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)
+#define RAPIDJSON_DO_STRINGIFY(x) #x
+
+// token concatenation
+#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)
+#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)
+#define RAPIDJSON_DO_JOIN2(X, Y) X##Y
+//!@endcond
+
+/*! \def RAPIDJSON_MAJOR_VERSION
+    \ingroup RAPIDJSON_CONFIG
+    \brief Major version of RapidJSON in integer.
+*/
+/*! \def RAPIDJSON_MINOR_VERSION
+    \ingroup RAPIDJSON_CONFIG
+    \brief Minor version of RapidJSON in integer.
+*/
+/*! \def RAPIDJSON_PATCH_VERSION
+    \ingroup RAPIDJSON_CONFIG
+    \brief Patch version of RapidJSON in integer.
+*/
+/*! \def RAPIDJSON_VERSION_STRING
+    \ingroup RAPIDJSON_CONFIG
+    \brief Version of RapidJSON in "<major>.<minor>.<patch>" string format.
+*/
+#define RAPIDJSON_MAJOR_VERSION 1
+#define RAPIDJSON_MINOR_VERSION 1
+#define RAPIDJSON_PATCH_VERSION 0
+#define RAPIDJSON_VERSION_STRING \
+    RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION)
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NAMESPACE_(BEGIN|END)
+/*! \def RAPIDJSON_NAMESPACE
+    \ingroup RAPIDJSON_CONFIG
+    \brief   provide custom rapidjson namespace
+
+    In order to avoid symbol clashes and/or "One Definition Rule" errors
+    between multiple inclusions of (different versions of) RapidJSON in
+    a single binary, users can customize the name of the main RapidJSON
+    namespace.
+
+    In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE
+    to a custom name (e.g. \c MyRapidJSON) is sufficient.  If multiple
+    levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref
+    RAPIDJSON_NAMESPACE_END need to be defined as well:
+
+    \code
+    // in some .cpp file
+    #define RAPIDJSON_NAMESPACE my::rapidjson
+    #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson {
+    #define RAPIDJSON_NAMESPACE_END   } }
+    #include "rapidjson/..."
+    \endcode
+
+    \see rapidjson
+ */
+/*! \def RAPIDJSON_NAMESPACE_BEGIN
+    \ingroup RAPIDJSON_CONFIG
+    \brief   provide custom rapidjson namespace (opening expression)
+    \see RAPIDJSON_NAMESPACE
+*/
+/*! \def RAPIDJSON_NAMESPACE_END
+    \ingroup RAPIDJSON_CONFIG
+    \brief   provide custom rapidjson namespace (closing expression)
+    \see RAPIDJSON_NAMESPACE
+*/
+#ifndef RAPIDJSON_NAMESPACE
+#define RAPIDJSON_NAMESPACE rapidjson
+#endif
+#ifndef RAPIDJSON_NAMESPACE_BEGIN
+#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE {
+#endif
+#ifndef RAPIDJSON_NAMESPACE_END
+#define RAPIDJSON_NAMESPACE_END }
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_HAS_STDSTRING
+
+#define RAPIDJSON_HAS_STDSTRING 1
+
+#ifndef RAPIDJSON_HAS_STDSTRING
+#ifdef RAPIDJSON_DOXYGEN_RUNNING
+#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation
+#else
+#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default
+#endif
+/*! \def RAPIDJSON_HAS_STDSTRING
+    \ingroup RAPIDJSON_CONFIG
+    \brief Enable RapidJSON support for \c std::string
+
+    By defining this preprocessor symbol to \c 1, several convenience functions for using
+    \ref rapidjson::GenericValue with \c std::string are enabled, especially
+    for construction and comparison.
+
+    \hideinitializer
+*/
+#endif // !defined(RAPIDJSON_HAS_STDSTRING)
+
+#if RAPIDJSON_HAS_STDSTRING
+#include <string>
+#endif // RAPIDJSON_HAS_STDSTRING
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NO_INT64DEFINE
+
+/*! \def RAPIDJSON_NO_INT64DEFINE
+    \ingroup RAPIDJSON_CONFIG
+    \brief Use external 64-bit integer types.
+
+    RapidJSON requires the 64-bit integer types \c int64_t and  \c uint64_t types
+    to be available at global scope.
+
+    If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to
+    prevent RapidJSON from defining its own types.
+*/
+#ifndef RAPIDJSON_NO_INT64DEFINE
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#if defined(_MSC_VER) && (_MSC_VER < 1800)	// Visual Studio 2013
+#include "msinttypes/stdint.h"
+#include "msinttypes/inttypes.h"
+#else
+// Other compilers should have this.
+#include <stdint.h>
+#include <inttypes.h>
+#endif
+//!@endcond
+#ifdef RAPIDJSON_DOXYGEN_RUNNING
+#define RAPIDJSON_NO_INT64DEFINE
+#endif
+#endif // RAPIDJSON_NO_INT64TYPEDEF
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_FORCEINLINE
+
+#ifndef RAPIDJSON_FORCEINLINE
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#if defined(_MSC_VER) && defined(NDEBUG)
+#define RAPIDJSON_FORCEINLINE __forceinline
+#elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG)
+#define RAPIDJSON_FORCEINLINE __attribute__((always_inline))
+#else
+#define RAPIDJSON_FORCEINLINE
+#endif
+//!@endcond
+#endif // RAPIDJSON_FORCEINLINE
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ENDIAN
+#define RAPIDJSON_LITTLEENDIAN  0   //!< Little endian machine
+#define RAPIDJSON_BIGENDIAN     1   //!< Big endian machine
+
+//! Endianness of the machine.
+/*!
+    \def RAPIDJSON_ENDIAN
+    \ingroup RAPIDJSON_CONFIG
+
+    GCC 4.6 provided macro for detecting endianness of the target machine. But other
+    compilers may not have this. User can define RAPIDJSON_ENDIAN to either
+    \ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN.
+
+    Default detection implemented with reference to
+    \li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html
+    \li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp
+*/
+#ifndef RAPIDJSON_ENDIAN
+// Detect with GCC 4.6's macro
+#  ifdef __BYTE_ORDER__
+#    if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#      define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+#    elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#      define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+#    else
+#      error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.
+#    endif // __BYTE_ORDER__
+// Detect with GLIBC's endian.h
+#  elif defined(__GLIBC__)
+#    include <endian.h>
+#    if (__BYTE_ORDER == __LITTLE_ENDIAN)
+#      define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+#    elif (__BYTE_ORDER == __BIG_ENDIAN)
+#      define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+#    else
+#      error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.
+#   endif // __GLIBC__
+// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro
+#  elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
+#    define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+#  elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
+#    define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+// Detect with architecture macros
+#  elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__)
+#    define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+#  elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
+#    define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+#  elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
+#    define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+#  elif defined(RAPIDJSON_DOXYGEN_RUNNING)
+#    define RAPIDJSON_ENDIAN
+#  else
+#    error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.   
+#  endif
+#endif // RAPIDJSON_ENDIAN
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_64BIT
+
+//! Whether using 64-bit architecture
+#ifndef RAPIDJSON_64BIT
+#if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__)
+#define RAPIDJSON_64BIT 1
+#else
+#define RAPIDJSON_64BIT 0
+#endif
+#endif // RAPIDJSON_64BIT
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ALIGN
+
+//! Data alignment of the machine.
+/*! \ingroup RAPIDJSON_CONFIG
+    \param x pointer to align
+
+    Some machines require strict data alignment. The default is 8 bytes.
+    User can customize by defining the RAPIDJSON_ALIGN function macro.
+*/
+#ifndef RAPIDJSON_ALIGN
+#define RAPIDJSON_ALIGN(x) (((x) + static_cast<size_t>(7u)) & ~static_cast<size_t>(7u))
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_UINT64_C2
+
+//! Construct a 64-bit literal by a pair of 32-bit integer.
+/*!
+    64-bit literal with or without ULL suffix is prone to compiler warnings.
+    UINT64_C() is C macro which cause compilation problems.
+    Use this macro to define 64-bit constants by a pair of 32-bit integer.
+*/
+#ifndef RAPIDJSON_UINT64_C2
+#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_48BITPOINTER_OPTIMIZATION
+
+//! Use only lower 48-bit address for some pointers.
+/*!
+    \ingroup RAPIDJSON_CONFIG
+
+    This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address.
+    The higher 16-bit can be used for storing other data.
+    \c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture.
+*/
+#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION
+#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
+#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1
+#else
+#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0
+#endif
+#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION
+
+#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1
+#if RAPIDJSON_64BIT != 1
+#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1
+#endif
+#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x))))
+#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF))))
+#else
+#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x))
+#define RAPIDJSON_GETPOINTER(type, p) (p)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_NEON/RAPIDJSON_SIMD
+
+/*! \def RAPIDJSON_SIMD
+    \ingroup RAPIDJSON_CONFIG
+    \brief Enable SSE2/SSE4.2/Neon optimization.
+
+    RapidJSON supports optimized implementations for some parsing operations
+    based on the SSE2, SSE4.2 or NEon SIMD extensions on modern Intel
+    or ARM compatible processors.
+
+    To enable these optimizations, three different symbols can be defined;
+    \code
+    // Enable SSE2 optimization.
+    #define RAPIDJSON_SSE2
+
+    // Enable SSE4.2 optimization.
+    #define RAPIDJSON_SSE42
+    \endcode
+
+    // Enable ARM Neon optimization.
+    #define RAPIDJSON_NEON
+    \endcode
+
+    \c RAPIDJSON_SSE42 takes precedence over SSE2, if both are defined.
+
+    If any of these symbols is defined, RapidJSON defines the macro
+    \c RAPIDJSON_SIMD to indicate the availability of the optimized code.
+*/
+#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \
+    || defined(RAPIDJSON_NEON) || defined(RAPIDJSON_DOXYGEN_RUNNING)
+#define RAPIDJSON_SIMD
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NO_SIZETYPEDEFINE
+
+#ifndef RAPIDJSON_NO_SIZETYPEDEFINE
+/*! \def RAPIDJSON_NO_SIZETYPEDEFINE
+    \ingroup RAPIDJSON_CONFIG
+    \brief User-provided \c SizeType definition.
+
+    In order to avoid using 32-bit size types for indexing strings and arrays,
+    define this preprocessor symbol and provide the type rapidjson::SizeType
+    before including RapidJSON:
+    \code
+    #define RAPIDJSON_NO_SIZETYPEDEFINE
+    namespace rapidjson { typedef ::std::size_t SizeType; }
+    #include "rapidjson/..."
+    \endcode
+
+    \see rapidjson::SizeType
+*/
+#ifdef RAPIDJSON_DOXYGEN_RUNNING
+#define RAPIDJSON_NO_SIZETYPEDEFINE
+#endif
+RAPIDJSON_NAMESPACE_BEGIN
+//! Size type (for string lengths, array sizes, etc.)
+/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms,
+    instead of using \c size_t. Users may override the SizeType by defining
+    \ref RAPIDJSON_NO_SIZETYPEDEFINE.
+*/
+typedef unsigned SizeType;
+RAPIDJSON_NAMESPACE_END
+#endif
+
+// always import std::size_t to rapidjson namespace
+RAPIDJSON_NAMESPACE_BEGIN
+using std::size_t;
+RAPIDJSON_NAMESPACE_END
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ASSERT
+
+//! Assertion.
+/*! \ingroup RAPIDJSON_CONFIG
+    By default, rapidjson uses C \c assert() for internal assertions.
+    User can override it by defining RAPIDJSON_ASSERT(x) macro.
+
+    \note Parsing errors are handled and can be customized by the
+          \ref RAPIDJSON_ERRORS APIs.
+*/
+#ifndef RAPIDJSON_ASSERT
+#include <cassert>
+#define RAPIDJSON_ASSERT(x) assert(x)
+#endif // RAPIDJSON_ASSERT
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_STATIC_ASSERT
+
+// Prefer C++11 static_assert, if available
+#ifndef RAPIDJSON_STATIC_ASSERT
+#if __cplusplus >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 )
+#define RAPIDJSON_STATIC_ASSERT(x) \
+   static_assert(x, RAPIDJSON_STRINGIFY(x))
+#endif // C++11
+#endif // RAPIDJSON_STATIC_ASSERT
+
+// Adopt C++03 implementation from boost
+#ifndef RAPIDJSON_STATIC_ASSERT
+#ifndef __clang__
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#endif
+RAPIDJSON_NAMESPACE_BEGIN
+template <bool x> struct STATIC_ASSERTION_FAILURE;
+template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
+template <size_t x> struct StaticAssertTest {};
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__GNUC__) || defined(__clang__)
+#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
+#else
+#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE 
+#endif
+#ifndef __clang__
+//!@endcond
+#endif
+
+/*! \def RAPIDJSON_STATIC_ASSERT
+    \brief (Internal) macro to check for conditions at compile-time
+    \param x compile-time condition
+    \hideinitializer
+ */
+#define RAPIDJSON_STATIC_ASSERT(x) \
+    typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \
+      sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \
+    RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
+#endif // RAPIDJSON_STATIC_ASSERT
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY
+
+//! Compiler branching hint for expression with high probability to be true.
+/*!
+    \ingroup RAPIDJSON_CONFIG
+    \param x Boolean expression likely to be true.
+*/
+#ifndef RAPIDJSON_LIKELY
+#if defined(__GNUC__) || defined(__clang__)
+#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
+#else
+#define RAPIDJSON_LIKELY(x) (x)
+#endif
+#endif
+
+//! Compiler branching hint for expression with low probability to be true.
+/*!
+    \ingroup RAPIDJSON_CONFIG
+    \param x Boolean expression unlikely to be true.
+*/
+#ifndef RAPIDJSON_UNLIKELY
+#if defined(__GNUC__) || defined(__clang__)
+#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+#define RAPIDJSON_UNLIKELY(x) (x)
+#endif
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Helpers
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+
+#define RAPIDJSON_MULTILINEMACRO_BEGIN do {  
+#define RAPIDJSON_MULTILINEMACRO_END \
+} while((void)0, 0)
+
+// adopted from Boost
+#define RAPIDJSON_VERSION_CODE(x,y,z) \
+  (((x)*100000) + ((y)*100) + (z))
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF
+
+#if defined(__GNUC__)
+#define RAPIDJSON_GNUC \
+    RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__)
+#endif
+
+#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0))
+
+#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x))
+#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x)
+#define RAPIDJSON_DIAG_OFF(x) \
+    RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x)))
+
+// push/pop support in Clang and GCC>=4.6
+#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0))
+#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
+#define RAPIDJSON_DIAG_POP  RAPIDJSON_DIAG_PRAGMA(pop)
+#else // GCC >= 4.2, < 4.6
+#define RAPIDJSON_DIAG_PUSH /* ignored */
+#define RAPIDJSON_DIAG_POP /* ignored */
+#endif
+
+#elif defined(_MSC_VER)
+
+// pragma (MSVC specific)
+#define RAPIDJSON_PRAGMA(x) __pragma(x)
+#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x))
+
+#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x)
+#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
+#define RAPIDJSON_DIAG_POP  RAPIDJSON_DIAG_PRAGMA(pop)
+
+#else
+
+#define RAPIDJSON_DIAG_OFF(x) /* ignored */
+#define RAPIDJSON_DIAG_PUSH   /* ignored */
+#define RAPIDJSON_DIAG_POP    /* ignored */
+
+#endif // RAPIDJSON_DIAG_*
+
+///////////////////////////////////////////////////////////////////////////////
+// C++11 features
+
+#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#if defined(__clang__)
+#if __has_feature(cxx_rvalue_references) && \
+    (defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
+#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
+#else
+#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
+#endif
+#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
+      (defined(_MSC_VER) && _MSC_VER >= 1600) || \
+      (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__))
+
+#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
+#else
+#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
+#endif
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT
+#if defined(__clang__)
+#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
+#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
+    (defined(_MSC_VER) && _MSC_VER >= 1900) || \
+    (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__))
+#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
+#else
+#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
+#endif
+#endif
+#if RAPIDJSON_HAS_CXX11_NOEXCEPT
+#define RAPIDJSON_NOEXCEPT noexcept
+#else
+#define RAPIDJSON_NOEXCEPT /* noexcept */
+#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
+
+// no automatic detection, yet
+#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS
+#if (defined(_MSC_VER) && _MSC_VER >= 1700)
+#define RAPIDJSON_HAS_CXX11_TYPETRAITS 1
+#else
+#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0
+#endif
+#endif
+
+#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR
+#if defined(__clang__)
+#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for)
+#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
+      (defined(_MSC_VER) && _MSC_VER >= 1700) || \
+      (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__))
+#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1
+#else
+#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0
+#endif
+#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR
+
+//!@endcond
+
+//! Assertion (in non-throwing contexts).
+ /*! \ingroup RAPIDJSON_CONFIG
+    Some functions provide a \c noexcept guarantee, if the compiler supports it.
+    In these cases, the \ref RAPIDJSON_ASSERT macro cannot be overridden to
+    throw an exception.  This macro adds a separate customization point for
+    such cases.
+
+    Defaults to C \c assert() (as \ref RAPIDJSON_ASSERT), if \c noexcept is
+    supported, and to \ref RAPIDJSON_ASSERT otherwise.
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NOEXCEPT_ASSERT
+
+#ifndef RAPIDJSON_NOEXCEPT_ASSERT
+#ifdef RAPIDJSON_ASSERT_THROWS
+#if RAPIDJSON_HAS_CXX11_NOEXCEPT
+#define RAPIDJSON_NOEXCEPT_ASSERT(x)
+#else
+#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x)
+#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
+#else
+#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x)
+#endif // RAPIDJSON_ASSERT_THROWS
+#endif // RAPIDJSON_NOEXCEPT_ASSERT
+
+///////////////////////////////////////////////////////////////////////////////
+// new/delete
+
+#ifndef RAPIDJSON_NEW
+///! customization point for global \c new
+#define RAPIDJSON_NEW(TypeName) new TypeName
+#endif
+#ifndef RAPIDJSON_DELETE
+///! customization point for global \c delete
+#define RAPIDJSON_DELETE(x) delete x
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Type
+
+/*! \namespace rapidjson
+    \brief main RapidJSON namespace
+    \see RAPIDJSON_NAMESPACE
+*/
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Type of JSON value
+enum Type {
+    kNullType = 0,      //!< null
+    kFalseType = 1,     //!< false
+    kTrueType = 2,      //!< true
+    kObjectType = 3,    //!< object
+    kArrayType = 4,     //!< array 
+    kStringType = 5,    //!< string
+    kNumberType = 6     //!< number
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_RAPIDJSON_H_

File diff suppressed because it is too large
+ 2230 - 0
jni/base/rapidjson/reader.h


File diff suppressed because it is too large
+ 2497 - 0
jni/base/rapidjson/schema.h


+ 223 - 0
jni/base/rapidjson/stream.h

@@ -0,0 +1,223 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "rapidjson.h"
+
+#ifndef RAPIDJSON_STREAM_H_
+#define RAPIDJSON_STREAM_H_
+
+#include "encodings.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+//  Stream
+
+/*! \class rapidjson::Stream
+    \brief Concept for reading and writing characters.
+
+    For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd().
+
+    For write-only stream, only need to implement Put() and Flush().
+
+\code
+concept Stream {
+    typename Ch;    //!< Character type of the stream.
+
+    //! Read the current character from stream without moving the read cursor.
+    Ch Peek() const;
+
+    //! Read the current character from stream and moving the read cursor to next character.
+    Ch Take();
+
+    //! Get the current read cursor.
+    //! \return Number of characters read from start.
+    size_t Tell();
+
+    //! Begin writing operation at the current read pointer.
+    //! \return The begin writer pointer.
+    Ch* PutBegin();
+
+    //! Write a character.
+    void Put(Ch c);
+
+    //! Flush the buffer.
+    void Flush();
+
+    //! End the writing operation.
+    //! \param begin The begin write pointer returned by PutBegin().
+    //! \return Number of characters written.
+    size_t PutEnd(Ch* begin);
+}
+\endcode
+*/
+
+//! Provides additional information for stream.
+/*!
+    By using traits pattern, this type provides a default configuration for stream.
+    For custom stream, this type can be specialized for other configuration.
+    See TEST(Reader, CustomStringStream) in readertest.cpp for example.
+*/
+template<typename Stream>
+struct StreamTraits {
+    //! Whether to make local copy of stream for optimization during parsing.
+    /*!
+        By default, for safety, streams do not use local copy optimization.
+        Stream that can be copied fast should specialize this, like StreamTraits<StringStream>.
+    */
+    enum { copyOptimization = 0 };
+};
+
+//! Reserve n characters for writing to a stream.
+template<typename Stream>
+inline void PutReserve(Stream& stream, size_t count) {
+    (void)stream;
+    (void)count;
+}
+
+//! Write character to a stream, presuming buffer is reserved.
+template<typename Stream>
+inline void PutUnsafe(Stream& stream, typename Stream::Ch c) {
+    stream.Put(c);
+}
+
+//! Put N copies of a character to a stream.
+template<typename Stream, typename Ch>
+inline void PutN(Stream& stream, Ch c, size_t n) {
+    PutReserve(stream, n);
+    for (size_t i = 0; i < n; i++)
+        PutUnsafe(stream, c);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericStreamWrapper
+
+//! A Stream Wrapper
+/*! \tThis string stream is a wrapper for any stream by just forwarding any
+    \treceived message to the origin stream.
+    \note implements Stream concept
+*/
+
+#if defined(_MSC_VER) && _MSC_VER <= 1800
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4702)  // unreachable code
+RAPIDJSON_DIAG_OFF(4512)  // assignment operator could not be generated
+#endif
+
+template <typename InputStream, typename Encoding = UTF8<> >
+class GenericStreamWrapper {
+public:
+    typedef typename Encoding::Ch Ch;
+    GenericStreamWrapper(InputStream& is): is_(is) {}
+
+    Ch Peek() const { return is_.Peek(); }
+    Ch Take() { return is_.Take(); }
+    size_t Tell() { return is_.Tell(); }
+    Ch* PutBegin() { return is_.PutBegin(); }
+    void Put(Ch ch) { is_.Put(ch); }
+    void Flush() { is_.Flush(); }
+    size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); }
+
+    // wrapper for MemoryStream
+    const Ch* Peek4() const { return is_.Peek4(); }
+
+    // wrapper for AutoUTFInputStream
+    UTFType GetType() const { return is_.GetType(); }
+    bool HasBOM() const { return is_.HasBOM(); }
+
+protected:
+    InputStream& is_;
+};
+
+#if defined(_MSC_VER) && _MSC_VER <= 1800
+RAPIDJSON_DIAG_POP
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// StringStream
+
+//! Read-only string stream.
+/*! \note implements Stream concept
+*/
+template <typename Encoding>
+struct GenericStringStream {
+    typedef typename Encoding::Ch Ch;
+
+    GenericStringStream(const Ch *src) : src_(src), head_(src) {}
+
+    Ch Peek() const { return *src_; }
+    Ch Take() { return *src_++; }
+    size_t Tell() const { return static_cast<size_t>(src_ - head_); }
+
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    void Put(Ch) { RAPIDJSON_ASSERT(false); }
+    void Flush() { RAPIDJSON_ASSERT(false); }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+    const Ch* src_;     //!< Current read position.
+    const Ch* head_;    //!< Original head of the string.
+};
+
+template <typename Encoding>
+struct StreamTraits<GenericStringStream<Encoding> > {
+    enum { copyOptimization = 1 };
+};
+
+//! String stream with UTF8 encoding.
+typedef GenericStringStream<UTF8<> > StringStream;
+
+///////////////////////////////////////////////////////////////////////////////
+// InsituStringStream
+
+//! A read-write string stream.
+/*! This string stream is particularly designed for in-situ parsing.
+    \note implements Stream concept
+*/
+template <typename Encoding>
+struct GenericInsituStringStream {
+    typedef typename Encoding::Ch Ch;
+
+    GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}
+
+    // Read
+    Ch Peek() { return *src_; }
+    Ch Take() { return *src_++; }
+    size_t Tell() { return static_cast<size_t>(src_ - head_); }
+
+    // Write
+    void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
+
+    Ch* PutBegin() { return dst_ = src_; }
+    size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }
+    void Flush() {}
+
+    Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; }
+    void Pop(size_t count) { dst_ -= count; }
+
+    Ch* src_;
+    Ch* dst_;
+    Ch* head_;
+};
+
+template <typename Encoding>
+struct StreamTraits<GenericInsituStringStream<Encoding> > {
+    enum { copyOptimization = 1 };
+};
+
+//! Insitu string stream with UTF8 encoding.
+typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_STREAM_H_

+ 121 - 0
jni/base/rapidjson/stringbuffer.h

@@ -0,0 +1,121 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_STRINGBUFFER_H_
+#define RAPIDJSON_STRINGBUFFER_H_
+
+#include "stream.h"
+#include "internal/stack.h"
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#include <utility> // std::move
+#endif
+
+#include "internal/stack.h"
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Represents an in-memory output stream.
+/*!
+    \tparam Encoding Encoding of the stream.
+    \tparam Allocator type for allocating memory buffer.
+    \note implements Stream concept
+*/
+template <typename Encoding, typename Allocator = CrtAllocator>
+class GenericStringBuffer {
+public:
+    typedef typename Encoding::Ch Ch;
+
+    GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {}
+    GenericStringBuffer& operator=(GenericStringBuffer&& rhs) {
+        if (&rhs != this)
+            stack_ = std::move(rhs.stack_);
+        return *this;
+    }
+#endif
+
+    void Put(Ch c) { *stack_.template Push<Ch>() = c; }
+    void PutUnsafe(Ch c) { *stack_.template PushUnsafe<Ch>() = c; }
+    void Flush() {}
+
+    void Clear() { stack_.Clear(); }
+    void ShrinkToFit() {
+        // Push and pop a null terminator. This is safe.
+        *stack_.template Push<Ch>() = '\0';
+        stack_.ShrinkToFit();
+        stack_.template Pop<Ch>(1);
+    }
+
+    void Reserve(size_t count) { stack_.template Reserve<Ch>(count); }
+    Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
+    Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe<Ch>(count); }
+    void Pop(size_t count) { stack_.template Pop<Ch>(count); }
+
+    const Ch* GetString() const {
+        // Push and pop a null terminator. This is safe.
+        *stack_.template Push<Ch>() = '\0';
+        stack_.template Pop<Ch>(1);
+
+        return stack_.template Bottom<Ch>();
+    }
+
+    //! Get the size of string in bytes in the string buffer.
+    size_t GetSize() const { return stack_.GetSize(); }
+
+    //! Get the length of string in Ch in the string buffer.
+    size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); }
+
+    static const size_t kDefaultCapacity = 256;
+    mutable internal::Stack<Allocator> stack_;
+
+private:
+    // Prohibit copy constructor & assignment operator.
+    GenericStringBuffer(const GenericStringBuffer&);
+    GenericStringBuffer& operator=(const GenericStringBuffer&);
+};
+
+//! String buffer with UTF8 encoding
+typedef GenericStringBuffer<UTF8<> > StringBuffer;
+
+template<typename Encoding, typename Allocator>
+inline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream, size_t count) {
+    stream.Reserve(count);
+}
+
+template<typename Encoding, typename Allocator>
+inline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream, typename Encoding::Ch c) {
+    stream.PutUnsafe(c);
+}
+
+//! Implement specialized version of PutN() with memset() for better performance.
+template<>
+inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
+    std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_STRINGBUFFER_H_

+ 709 - 0
jni/base/rapidjson/writer.h

@@ -0,0 +1,709 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_WRITER_H_
+#define RAPIDJSON_WRITER_H_
+
+#include "stream.h"
+#include "internal/meta.h"
+#include "internal/stack.h"
+#include "internal/strfunc.h"
+#include "internal/dtoa.h"
+#include "internal/itoa.h"
+#include "stringbuffer.h"
+#include <new>      // placement new
+
+#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
+#include <intrin.h>
+#pragma intrinsic(_BitScanForward)
+#endif
+#ifdef RAPIDJSON_SSE42
+#include <nmmintrin.h>
+#elif defined(RAPIDJSON_SSE2)
+#include <emmintrin.h>
+#elif defined(RAPIDJSON_NEON)
+#include <arm_neon.h>
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(unreachable-code)
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#elif defined(_MSC_VER)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// WriteFlag
+
+/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS 
+    \ingroup RAPIDJSON_CONFIG
+    \brief User-defined kWriteDefaultFlags definition.
+
+    User can define this as any \c WriteFlag combinations.
+*/
+#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS
+#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags
+#endif
+
+//! Combination of writeFlags
+enum WriteFlag {
+    kWriteNoFlags = 0,              //!< No flags are set.
+    kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings.
+    kWriteNanAndInfFlag = 2,        //!< Allow writing of Infinity, -Infinity and NaN.
+    kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS  //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS
+};
+
+//! JSON writer
+/*! Writer implements the concept Handler.
+    It generates JSON text by events to an output os.
+
+    User may programmatically calls the functions of a writer to generate JSON text.
+
+    On the other side, a writer can also be passed to objects that generates events, 
+
+    for example Reader::Parse() and Document::Accept().
+
+    \tparam OutputStream Type of output stream.
+    \tparam SourceEncoding Encoding of source string.
+    \tparam TargetEncoding Encoding of output stream.
+    \tparam StackAllocator Type of allocator for allocating memory of stack.
+    \note implements Handler concept
+*/
+template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
+class Writer {
+public:
+    typedef typename SourceEncoding::Ch Ch;
+
+    static const int kDefaultMaxDecimalPlaces = 324;
+
+    //! Constructor
+    /*! \param os Output stream.
+        \param stackAllocator User supplied allocator. If it is null, it will create a private one.
+        \param levelDepth Initial capacity of stack.
+    */
+    explicit
+    Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : 
+        os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
+
+    explicit
+    Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
+        os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    Writer(Writer&& rhs) :
+        os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) {
+        rhs.os_ = 0;
+    }
+#endif
+
+    //! Reset the writer with a new stream.
+    /*!
+        This function reset the writer with a new stream and default settings,
+        in order to make a Writer object reusable for output multiple JSONs.
+
+        \param os New output stream.
+        \code
+        Writer<OutputStream> writer(os1);
+        writer.StartObject();
+        // ...
+        writer.EndObject();
+
+        writer.Reset(os2);
+        writer.StartObject();
+        // ...
+        writer.EndObject();
+        \endcode
+    */
+    void Reset(OutputStream& os) {
+        os_ = &os;
+        hasRoot_ = false;
+        level_stack_.Clear();
+    }
+
+    //! Checks whether the output is a complete JSON.
+    /*!
+        A complete JSON has a complete root object or array.
+    */
+    bool IsComplete() const {
+        return hasRoot_ && level_stack_.Empty();
+    }
+
+    int GetMaxDecimalPlaces() const {
+        return maxDecimalPlaces_;
+    }
+
+    //! Sets the maximum number of decimal places for double output.
+    /*!
+        This setting truncates the output with specified number of decimal places.
+
+        For example, 
+
+        \code
+        writer.SetMaxDecimalPlaces(3);
+        writer.StartArray();
+        writer.Double(0.12345);                 // "0.123"
+        writer.Double(0.0001);                  // "0.0"
+        writer.Double(1.234567890123456e30);    // "1.234567890123456e30" (do not truncate significand for positive exponent)
+        writer.Double(1.23e-4);                 // "0.0"                  (do truncate significand for negative exponent)
+        writer.EndArray();
+        \endcode
+
+        The default setting does not truncate any decimal places. You can restore to this setting by calling
+        \code
+        writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces);
+        \endcode
+    */
+    void SetMaxDecimalPlaces(int maxDecimalPlaces) {
+        maxDecimalPlaces_ = maxDecimalPlaces;
+    }
+
+    /*!@name Implementation of Handler
+        \see Handler
+    */
+    //@{
+
+    bool Null()                 { Prefix(kNullType);   return EndValue(WriteNull()); }
+    bool Bool(bool b)           { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); }
+    bool Int(int i)             { Prefix(kNumberType); return EndValue(WriteInt(i)); }
+    bool Uint(unsigned u)       { Prefix(kNumberType); return EndValue(WriteUint(u)); }
+    bool Int64(int64_t i64)     { Prefix(kNumberType); return EndValue(WriteInt64(i64)); }
+    bool Uint64(uint64_t u64)   { Prefix(kNumberType); return EndValue(WriteUint64(u64)); }
+
+    //! Writes the given \c double value to the stream
+    /*!
+        \param d The value to be written.
+        \return Whether it is succeed.
+    */
+    bool Double(double d)       { Prefix(kNumberType); return EndValue(WriteDouble(d)); }
+
+    bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
+        RAPIDJSON_ASSERT(str != 0);
+        (void)copy;
+        Prefix(kNumberType);
+        return EndValue(WriteString(str, length));
+    }
+
+    bool String(const Ch* str, SizeType length, bool copy = false) {
+        RAPIDJSON_ASSERT(str != 0);
+        (void)copy;
+        Prefix(kStringType);
+        return EndValue(WriteString(str, length));
+    }
+
+#if RAPIDJSON_HAS_STDSTRING
+    bool String(const std::basic_string<Ch>& str) {
+        return String(str.data(), SizeType(str.size()));
+    }
+#endif
+
+    bool StartObject() {
+        Prefix(kObjectType);
+        new (level_stack_.template Push<Level>()) Level(false);
+        return WriteStartObject();
+    }
+
+    bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
+
+#if RAPIDJSON_HAS_STDSTRING
+    bool Key(const std::basic_string<Ch>& str)
+    {
+      return Key(str.data(), SizeType(str.size()));
+    }
+#endif
+	
+    bool EndObject(SizeType memberCount = 0) {
+        (void)memberCount;
+        RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object
+        RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray); // currently inside an Array, not Object
+        RAPIDJSON_ASSERT(0 == level_stack_.template Top<Level>()->valueCount % 2); // Object has a Key without a Value
+        level_stack_.template Pop<Level>(1);
+        return EndValue(WriteEndObject());
+    }
+
+    bool StartArray() {
+        Prefix(kArrayType);
+        new (level_stack_.template Push<Level>()) Level(true);
+        return WriteStartArray();
+    }
+
+    bool EndArray(SizeType elementCount = 0) {
+        (void)elementCount;
+        RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
+        RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
+        level_stack_.template Pop<Level>(1);
+        return EndValue(WriteEndArray());
+    }
+    //@}
+
+    /*! @name Convenience extensions */
+    //@{
+
+    //! Simpler but slower overload.
+    bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); }
+    bool Key(const Ch* const& str) { return Key(str, internal::StrLen(str)); }
+    
+    //@}
+
+    //! Write a raw JSON value.
+    /*!
+        For user to write a stringified JSON as a value.
+
+        \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
+        \param length Length of the json.
+        \param type Type of the root of json.
+    */
+    bool RawValue(const Ch* json, size_t length, Type type) {
+        RAPIDJSON_ASSERT(json != 0);
+        Prefix(type);
+        return EndValue(WriteRawValue(json, length));
+    }
+
+    //! Flush the output stream.
+    /*!
+        Allows the user to flush the output stream immediately.
+     */
+    void Flush() {
+        os_->Flush();
+    }
+
+protected:
+    //! Information for each nested level
+    struct Level {
+        Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
+        size_t valueCount;  //!< number of values in this level
+        bool inArray;       //!< true if in array, otherwise in object
+    };
+
+    static const size_t kDefaultLevelDepth = 32;
+
+    bool WriteNull()  {
+        PutReserve(*os_, 4);
+        PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
+    }
+
+    bool WriteBool(bool b)  {
+        if (b) {
+            PutReserve(*os_, 4);
+            PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e');
+        }
+        else {
+            PutReserve(*os_, 5);
+            PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e');
+        }
+        return true;
+    }
+
+    bool WriteInt(int i) {
+        char buffer[11];
+        const char* end = internal::i32toa(i, buffer);
+        PutReserve(*os_, static_cast<size_t>(end - buffer));
+        for (const char* p = buffer; p != end; ++p)
+            PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
+        return true;
+    }
+
+    bool WriteUint(unsigned u) {
+        char buffer[10];
+        const char* end = internal::u32toa(u, buffer);
+        PutReserve(*os_, static_cast<size_t>(end - buffer));
+        for (const char* p = buffer; p != end; ++p)
+            PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
+        return true;
+    }
+
+    bool WriteInt64(int64_t i64) {
+        char buffer[21];
+        const char* end = internal::i64toa(i64, buffer);
+        PutReserve(*os_, static_cast<size_t>(end - buffer));
+        for (const char* p = buffer; p != end; ++p)
+            PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
+        return true;
+    }
+
+    bool WriteUint64(uint64_t u64) {
+        char buffer[20];
+        char* end = internal::u64toa(u64, buffer);
+        PutReserve(*os_, static_cast<size_t>(end - buffer));
+        for (char* p = buffer; p != end; ++p)
+            PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
+        return true;
+    }
+
+    bool WriteDouble(double d) {
+        if (internal::Double(d).IsNanOrInf()) {
+            if (!(writeFlags & kWriteNanAndInfFlag))
+                return false;
+            if (internal::Double(d).IsNan()) {
+                PutReserve(*os_, 3);
+                PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
+                return true;
+            }
+            if (internal::Double(d).Sign()) {
+                PutReserve(*os_, 9);
+                PutUnsafe(*os_, '-');
+            }
+            else
+                PutReserve(*os_, 8);
+            PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
+            PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
+            return true;
+        }
+
+        char buffer[25];
+        char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
+        PutReserve(*os_, static_cast<size_t>(end - buffer));
+        for (char* p = buffer; p != end; ++p)
+            PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
+        return true;
+    }
+
+    bool WriteString(const Ch* str, SizeType length)  {
+        static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+        static const char escape[256] = {
+#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+            //0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
+            'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
+            'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
+              0,   0, '"',   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, // 20
+            Z16, Z16,                                                                       // 30~4F
+              0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,'\\',   0,   0,   0, // 50
+            Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16                                // 60~FF
+#undef Z16
+        };
+
+        if (TargetEncoding::supportUnicode)
+            PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
+        else
+            PutReserve(*os_, 2 + length * 12);  // "\uxxxx\uyyyy..."
+
+        PutUnsafe(*os_, '\"');
+        GenericStringStream<SourceEncoding> is(str);
+        while (ScanWriteUnescapedString(is, length)) {
+            const Ch c = is.Peek();
+            if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {
+                // Unicode escaping
+                unsigned codepoint;
+                if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint)))
+                    return false;
+                PutUnsafe(*os_, '\\');
+                PutUnsafe(*os_, 'u');
+                if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
+                    PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]);
+                    PutUnsafe(*os_, hexDigits[(codepoint >>  8) & 15]);
+                    PutUnsafe(*os_, hexDigits[(codepoint >>  4) & 15]);
+                    PutUnsafe(*os_, hexDigits[(codepoint      ) & 15]);
+                }
+                else {
+                    RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
+                    // Surrogate pair
+                    unsigned s = codepoint - 0x010000;
+                    unsigned lead = (s >> 10) + 0xD800;
+                    unsigned trail = (s & 0x3FF) + 0xDC00;
+                    PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]);
+                    PutUnsafe(*os_, hexDigits[(lead >>  8) & 15]);
+                    PutUnsafe(*os_, hexDigits[(lead >>  4) & 15]);
+                    PutUnsafe(*os_, hexDigits[(lead      ) & 15]);
+                    PutUnsafe(*os_, '\\');
+                    PutUnsafe(*os_, 'u');
+                    PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]);
+                    PutUnsafe(*os_, hexDigits[(trail >>  8) & 15]);
+                    PutUnsafe(*os_, hexDigits[(trail >>  4) & 15]);
+                    PutUnsafe(*os_, hexDigits[(trail      ) & 15]);                    
+                }
+            }
+            else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)]))  {
+                is.Take();
+                PutUnsafe(*os_, '\\');
+                PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(escape[static_cast<unsigned char>(c)]));
+                if (escape[static_cast<unsigned char>(c)] == 'u') {
+                    PutUnsafe(*os_, '0');
+                    PutUnsafe(*os_, '0');
+                    PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]);
+                    PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
+                }
+            }
+            else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? 
+                Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
+                Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
+                return false;
+        }
+        PutUnsafe(*os_, '\"');
+        return true;
+    }
+
+    bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {
+        return RAPIDJSON_LIKELY(is.Tell() < length);
+    }
+
+    bool WriteStartObject() { os_->Put('{'); return true; }
+    bool WriteEndObject()   { os_->Put('}'); return true; }
+    bool WriteStartArray()  { os_->Put('['); return true; }
+    bool WriteEndArray()    { os_->Put(']'); return true; }
+
+    bool WriteRawValue(const Ch* json, size_t length) {
+        PutReserve(*os_, length);
+        GenericStringStream<SourceEncoding> is(json);
+        while (RAPIDJSON_LIKELY(is.Tell() < length)) {
+            RAPIDJSON_ASSERT(is.Peek() != '\0');
+            if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? 
+                Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
+                Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
+                return false;
+        }
+        return true;
+    }
+
+    void Prefix(Type type) {
+        (void)type;
+        if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root
+            Level* level = level_stack_.template Top<Level>();
+            if (level->valueCount > 0) {
+                if (level->inArray) 
+                    os_->Put(','); // add comma if it is not the first element in array
+                else  // in object
+                    os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
+            }
+            if (!level->inArray && level->valueCount % 2 == 0)
+                RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name
+            level->valueCount++;
+        }
+        else {
+            RAPIDJSON_ASSERT(!hasRoot_);    // Should only has one and only one root.
+            hasRoot_ = true;
+        }
+    }
+
+    // Flush the value if it is the top level one.
+    bool EndValue(bool ret) {
+        if (RAPIDJSON_UNLIKELY(level_stack_.Empty()))   // end of json text
+            Flush();
+        return ret;
+    }
+
+    OutputStream* os_;
+    internal::Stack<StackAllocator> level_stack_;
+    int maxDecimalPlaces_;
+    bool hasRoot_;
+
+private:
+    // Prohibit copy constructor & assignment operator.
+    Writer(const Writer&);
+    Writer& operator=(const Writer&);
+};
+
+// Full specialization for StringStream to prevent memory copying
+
+template<>
+inline bool Writer<StringBuffer>::WriteInt(int i) {
+    char *buffer = os_->Push(11);
+    const char* end = internal::i32toa(i, buffer);
+    os_->Pop(static_cast<size_t>(11 - (end - buffer)));
+    return true;
+}
+
+template<>
+inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
+    char *buffer = os_->Push(10);
+    const char* end = internal::u32toa(u, buffer);
+    os_->Pop(static_cast<size_t>(10 - (end - buffer)));
+    return true;
+}
+
+template<>
+inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
+    char *buffer = os_->Push(21);
+    const char* end = internal::i64toa(i64, buffer);
+    os_->Pop(static_cast<size_t>(21 - (end - buffer)));
+    return true;
+}
+
+template<>
+inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
+    char *buffer = os_->Push(20);
+    const char* end = internal::u64toa(u, buffer);
+    os_->Pop(static_cast<size_t>(20 - (end - buffer)));
+    return true;
+}
+
+template<>
+inline bool Writer<StringBuffer>::WriteDouble(double d) {
+    if (internal::Double(d).IsNanOrInf()) {
+        // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).
+        if (!(kWriteDefaultFlags & kWriteNanAndInfFlag))
+            return false;
+        if (internal::Double(d).IsNan()) {
+            PutReserve(*os_, 3);
+            PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
+            return true;
+        }
+        if (internal::Double(d).Sign()) {
+            PutReserve(*os_, 9);
+            PutUnsafe(*os_, '-');
+        }
+        else
+            PutReserve(*os_, 8);
+        PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
+        PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
+        return true;
+    }
+    
+    char *buffer = os_->Push(25);
+    char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
+    os_->Pop(static_cast<size_t>(25 - (end - buffer)));
+    return true;
+}
+
+#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
+template<>
+inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
+    if (length < 16)
+        return RAPIDJSON_LIKELY(is.Tell() < length);
+
+    if (!RAPIDJSON_LIKELY(is.Tell() < length))
+        return false;
+
+    const char* p = is.src_;
+    const char* end = is.head_ + length;
+    const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+    const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
+    if (nextAligned > end)
+        return true;
+
+    while (p != nextAligned)
+        if (*p < 0x20 || *p == '\"' || *p == '\\') {
+            is.src_ = p;
+            return RAPIDJSON_LIKELY(is.Tell() < length);
+        }
+        else
+            os_->PutUnsafe(*p++);
+
+    // The rest of string using SIMD
+    static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
+    static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
+    static const char space[16]  = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
+    const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
+    const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
+    const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
+
+    for (; p != endAligned; p += 16) {
+        const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
+        const __m128i t1 = _mm_cmpeq_epi8(s, dq);
+        const __m128i t2 = _mm_cmpeq_epi8(s, bs);
+        const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
+        const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
+        unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
+        if (RAPIDJSON_UNLIKELY(r != 0)) {   // some of characters is escaped
+            SizeType len;
+#ifdef _MSC_VER         // Find the index of first escaped
+            unsigned long offset;
+            _BitScanForward(&offset, r);
+            len = offset;
+#else
+            len = static_cast<SizeType>(__builtin_ffs(r) - 1);
+#endif
+            char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
+            for (size_t i = 0; i < len; i++)
+                q[i] = p[i];
+
+            p += len;
+            break;
+        }
+        _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s);
+    }
+
+    is.src_ = p;
+    return RAPIDJSON_LIKELY(is.Tell() < length);
+}
+#elif defined(RAPIDJSON_NEON)
+template<>
+inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
+    if (length < 16)
+        return RAPIDJSON_LIKELY(is.Tell() < length);
+
+    if (!RAPIDJSON_LIKELY(is.Tell() < length))
+        return false;
+
+    const char* p = is.src_;
+    const char* end = is.head_ + length;
+    const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+    const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
+    if (nextAligned > end)
+        return true;
+
+    while (p != nextAligned)
+        if (*p < 0x20 || *p == '\"' || *p == '\\') {
+            is.src_ = p;
+            return RAPIDJSON_LIKELY(is.Tell() < length);
+        }
+        else
+            os_->PutUnsafe(*p++);
+
+    // The rest of string using SIMD
+    const uint8x16_t s0 = vmovq_n_u8('"');
+    const uint8x16_t s1 = vmovq_n_u8('\\');
+    const uint8x16_t s2 = vmovq_n_u8('\b');
+    const uint8x16_t s3 = vmovq_n_u8(32);
+
+    for (; p != endAligned; p += 16) {
+        const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));
+        uint8x16_t x = vceqq_u8(s, s0);
+        x = vorrq_u8(x, vceqq_u8(s, s1));
+        x = vorrq_u8(x, vceqq_u8(s, s2));
+        x = vorrq_u8(x, vcltq_u8(s, s3));
+
+        x = vrev64q_u8(x);                     // Rev in 64
+        uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0);   // extract
+        uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1);  // extract
+
+        SizeType len = 0;
+        bool escaped = false;
+        if (low == 0) {
+            if (high != 0) {
+                unsigned lz = (unsigned)__builtin_clzll(high);
+                len = 8 + (lz >> 3);
+                escaped = true;
+            }
+        } else {
+            unsigned lz = (unsigned)__builtin_clzll(low);
+            len = lz >> 3;
+            escaped = true;
+        }
+        if (RAPIDJSON_UNLIKELY(escaped)) {   // some of characters is escaped
+            char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
+            for (size_t i = 0; i < len; i++)
+                q[i] = p[i];
+
+            p += len;
+            break;
+        }
+        vst1q_u8(reinterpret_cast<uint8_t *>(os_->PushUnsafe(16)), s);
+    }
+
+    is.src_ = p;
+    return RAPIDJSON_LIKELY(is.Tell() < length);
+}
+#endif // RAPIDJSON_NEON
+
+RAPIDJSON_NAMESPACE_END
+
+#if defined(_MSC_VER) || defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_RAPIDJSON_H_

+ 80 - 0
jni/base/simple_form.hpp

@@ -0,0 +1,80 @@
+#ifndef _FY_SIMPLE_FORM_
+#define _FY_SIMPLE_FORM_
+
+#include <string>
+#include <vector>
+
+#include "control/ZKListView.h"
+
+namespace fy {
+
+class simple_form {
+public:
+  typedef std::string (*string_getter)(int index, void* user_data);
+  typedef void (*click_listener)(int index, void* user_data);
+
+  struct form_item {
+    std::string title;
+    string_getter get_value;
+    click_listener on_click;
+    void* user_data;
+  };
+
+  void add_item(const std::string &title, string_getter get_value, click_listener on_click, void* user_data) {
+    form_item item;
+    item.title = title;
+    item.get_value = get_value;
+    item.on_click = on_click;
+    item.user_data = user_data;
+    items_.push_back(item);
+  }
+
+  int size() { return items_.size();}
+
+  void clear() { items_.clear();}
+
+  const form_item* find(int index) {
+    if (index >= (int)items_.size()) {
+      return NULL;
+    }
+    return (form_item*)&(*(items_.begin() + index));
+  }
+
+  void obtain(ZKListView::ZKListItem *pListItem, int index, int subitem_id) {
+    const form_item* item = find(index);
+    if (item == NULL) {
+      return;
+    }
+    if (pListItem) {
+      pListItem->setText(item->title);
+    }
+    ZKListView::ZKListSubItem* value = pListItem->findSubItemByID(subitem_id);
+    if (value == NULL) {
+      return;
+    }
+    if (item->get_value == NULL) {
+      value->setText("");
+      return;
+    }
+    value->setText(item->get_value(index, item->user_data));
+  }
+
+  void click(int index) {
+    const form_item* item = find(index);
+    if (item == NULL) {
+      return;
+    }
+    if (item->on_click == NULL) {
+      return;
+    }
+    item->on_click(index, item->user_data);
+  }
+
+private:
+  std::vector<simple_form::form_item> items_;
+};
+
+
+} /* namespace fy */
+
+#endif

+ 258 - 0
jni/base/strings.hpp

@@ -0,0 +1,258 @@
+#pragma once
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string>
+#include <vector>
+
+namespace base {
+
+inline std::string join(std::string val) {
+  return val;
+}
+template<class ...ARGS>
+inline std::string join(std::string val, ARGS ...args) {
+  return val + my_sum(args...);
+}
+
+/*  UTF - 8,是一种变长编码,具体规则如下:
+    1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF
+   - 8编码和ASCII码是相同的。 2)对于n字节的符号(n >
+   1),第一个字节的前n位都设为1,第n +
+   1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。
+
+    如表 :
+    1字节 0xxxxxxx
+    2字节 110xxxxx 10xxxxxx
+    3字节 1110xxxx 10xxxxxx 10xxxxxx
+    4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+    5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+    6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+*/
+
+// 将string中的中文分解成单个字, 适用于UTF-8编码
+inline void split_word(const std::string& words, std::vector<std::string>* characters) {
+  int num = words.size();
+  int i = 0;
+  while (i < num) {
+    int size = 1;
+    if (words[i] & 0x80) {
+      char temp = words[i];
+      temp <<= 1;
+      do {
+        temp <<= 1;
+        ++size;
+      } while (temp & 0x80);
+    }
+    characters->push_back(words.substr(i, size));
+    i += size;
+  }
+}
+
+inline bool endswith(const std::string& str, const std::string& end) {
+  int srclen = str.size();
+  int endlen = end.size();
+  if(srclen >= endlen) {
+    std::string temp = str.substr(srclen - endlen, endlen);
+    if(temp.compare(end) == 0)
+      return true;
+  }
+  return false;
+}
+
+/**
+ * 删除输入字符串指定长度,返回被删除部分,
+ */
+inline std::string cut(std::string* in, ::size_t n) {
+  if (in == NULL) {
+    return "";
+  }
+  if (n >= in->length()) {
+    n = in->length();
+  }
+  std::string cuts = in->substr(0, n);
+  in->erase(0, n);
+  return cuts;
+}
+
+inline bool startswith(const std::string& str, const std::string& start) {
+  int srclen = str.size();
+  int startlen = start.size();
+  if(srclen >= startlen) {
+    std::string temp = str.substr(0, startlen);
+    if(temp.compare(start) == 0)
+      return true;
+  }
+  return false;
+}
+
+inline std::string trimsuffix(const std::string &str, const std::string &suffix) {
+  ::size_t p = str.find_last_of(suffix);
+  if (p != (str.size() - suffix.size())) {
+    return str;
+  }
+  return str.substr(0, p);
+}
+
+inline std::string trimprefix(const std::string &str, const std::string &prefix) {
+  if (startswith(str, prefix)) {
+    return str.substr(prefix.size());
+  }
+  return str;
+}
+
+inline std::string trim_left_unicode(const std::string& str,
+    const std::vector<std::string>& cutset) {
+  std::string s = str;
+  for (auto it = cutset.begin(); it != cutset.end();) {
+    if (startswith(s, *it)) {
+      s.erase(0, it->length());
+      it = cutset.begin();
+      continue;
+    }
+    ++it;
+  }
+  return s;
+}
+
+inline std::string trim_left(const std::string &str, const std::string &cutset) {
+  if (str.empty() || cutset.empty()) {
+      return str;
+  }
+  std::vector<std::string> words;
+  split_word(cutset, &words);
+  return trim_left_unicode(str, words);
+}
+
+inline std::string trim_right_unicode(const std::string& str,
+    const std::vector<std::string>& cutset) {
+  std::string s = str;
+  for (auto it = cutset.begin(); it != cutset.end();) {
+    if (endswith(s, *it)) {
+      s.erase(s.length() - it->length(), it->length());
+      it = cutset.begin();
+      continue;
+    }
+    ++it;
+  }
+  return s;
+}
+
+inline std::string trim_right(const std::string &str, const std::string &cutset) {
+  if (str.empty() || cutset.empty()) {
+      return str;
+  }
+  std::vector<std::string> words;
+  split_word(cutset, &words);
+  return trim_right_unicode(str, words);
+}
+
+inline std::string trim(const std::string &str,
+    const std::string& cutset = "\n \t\r") {
+  if (str.empty() || cutset.empty()) {
+    return str;
+  }
+  std::vector<std::string> words;
+  split_word(cutset, &words);
+  return trim_right_unicode(trim_left_unicode(str, words), words);
+}
+
+inline std::string replace(const std::string& str, const std::string &old_str, const std::string& new_str) {
+  std::string::size_type pos = 0;
+  if (old_str.empty()) {
+    return str;
+  }
+  std::string temp = str;
+  while (std::string::npos != (pos = temp.find(old_str))) {
+    temp = temp.replace(pos, old_str.size(), new_str);
+  }
+  return temp;
+}
+
+inline std::string join(const std::vector<std::string> v) {
+  std::string t;
+  for (::size_t i = 0; i < v.size(); ++i) {
+    t += v[i];
+  }
+  return t;
+}
+
+inline std::string upper(const std::string& text) {
+  std::string dest = text;
+  char* p = (char*)dest.data();
+  size_t length = dest.length();
+  for (size_t i = 0; i < length; ++i) {
+    int c = (unsigned char)p[i];
+    p[i] = toupper(c);
+  }
+  return dest;
+}
+
+inline std::string lower(const std::string& text) {
+  std::string dest = text;
+  char* p = (char*)dest.data();
+  size_t length = dest.length();
+  for (size_t i = 0; i < length; ++i) {
+    int c = (unsigned char)p[i];
+    p[i] = tolower(c);
+  }
+  return dest;
+}
+
+inline std::string format(const char* format, ...) {
+  std::string tmp;
+  va_list vl;
+  va_start(vl, format);
+  size_t num = vsnprintf(0, 0, format, vl);
+  if (num >= tmp.capacity()) tmp.reserve(num + sizeof(char));
+
+  tmp.resize(num);
+  vsnprintf((char*)tmp.data(), tmp.capacity(), format, vl);
+  va_end(vl);
+  return tmp;
+}
+
+inline std::string to_style_string(const char* bytes, ::size_t len) {
+  std::string out;
+  char buf[8] = {0};
+  int base = 16;
+  for (size_t i = 0; i < len; ++i) {
+    if (base == 16) {
+      if (false) {
+        snprintf(buf, sizeof(buf), "0x%02X,", bytes[i]);
+      } else {
+        snprintf(buf, sizeof(buf), "%02X ", bytes[i]);
+      }
+    } else if (base == 10) {
+      snprintf(buf, sizeof(buf), "%03d ", bytes[i]);
+    }
+    out += buf;
+  }
+  return out;
+}
+
+inline std::string from_style_string(const std::string& str) {
+  const char* data = str.c_str();
+  ::size_t offset = 0;
+  ::size_t index = 0;
+  std::string out;
+  while (offset < str.length()) {
+    char* end = NULL;
+    long h = strtol(data + offset, &end, 16);
+    if (*end == '\0') {
+      //结束
+      out.push_back((char)h);
+      break;
+    }
+    //出错
+    if ((h == 0) && (end == (data + offset))) {
+      return out;
+    }
+    out.push_back((char)h);
+    index = index + 1;
+    offset = end - data;
+  }
+  return out;
+}
+
+} //namespace base

+ 104 - 0
jni/base/thread.hpp

@@ -0,0 +1,104 @@
+#ifndef _FY_THREAD_H_
+#define _FY_THREAD_H_
+
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+#include <string>
+#include <pthread.h>
+#include <errno.h>
+#include <utils/Log.h>
+
+namespace base {
+
+class thread {
+public:
+  typedef void (*func_thread_void)();
+  typedef void (*func_thread_arg1)(void* arg1);
+
+  struct meta_data {
+    thread* t;
+    func_thread_arg1 func;
+    void* arg;
+  };
+
+  thread(base::thread::func_thread_arg1 func, void* arg) {
+    int ret;
+    joinable_ = true;
+    struct meta_data* meta = new meta_data();
+    meta->t = this;
+    meta->func = func;
+    meta->arg = arg;
+    thread_id_ = -1;
+    ret = pthread_create(&pthread_t_, NULL, base::thread::func_thread_wrapper, meta);
+    if (ret != 0) {
+      LOGE("create thread error, errno = %d", errno);
+    }
+  }
+
+  static std::string name() {
+    char name[64] = {0};
+    prctl(PR_GET_NAME, (unsigned long)name);
+    return name;
+  }
+
+  void set_name(const char* name64) {
+    prctl(PR_SET_NAME, (unsigned long)name64);
+  }
+
+  void join() {
+    void* ret_val;
+    int ret = pthread_join(pthread_t_, &ret_val);
+    if (ret != 0) {
+      LOGE("pthread_join failed errno %d", errno);
+    }
+    joinable_ = false;
+  }
+
+  void detach() {
+    int ret = pthread_detach(pthread_t_);
+    if (ret != 0) {
+      LOGE("pthread_detach failed, ret = %d, errno = %d", ret, errno);
+    }
+    joinable_ = false;
+  }
+
+  bool joinable() {
+    return joinable_;
+  }
+
+  size_t id() {
+    return thread_id_;
+  }
+
+  static size_t current_id() {
+    return syscall(SYS_gettid);
+  }
+
+  virtual ~thread() {
+    if (joinable()) {
+      detach();
+      int ret_val;
+      pthread_exit(&ret_val);
+    }
+  }
+
+private:
+  static void* func_thread_wrapper(void *arg) {
+    LOGD("current thread id %u", thread::current_id());
+    base::thread::meta_data* meta = (base::thread::meta_data*)arg;
+    meta->t->thread_id_ = thread::current_id();
+    meta->func(meta->arg);
+    delete meta;
+    return NULL;
+  }
+
+  pthread_t pthread_t_;
+  bool joinable_;
+  size_t thread_id_;
+};
+
+} /* namespace base */
+
+#endif

+ 124 - 0
jni/base/time.hpp

@@ -0,0 +1,124 @@
+#ifndef _FY_TIME_H_
+#define _FY_TIME_H_
+
+#include <time.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "utils/TimeHelper.h"
+#include "utils/Log.h"
+
+namespace base {
+
+class time {
+public:
+  static time now() {
+    return time();
+  }
+
+  // 开机累计毫秒
+  static int64_t uptime() {
+      struct timespec ts;
+      clock_gettime(CLOCK_BOOTTIME, &ts);
+      return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
+  }
+
+  bool after(const time& t) {
+    return true;
+  }
+
+  bool before(const time& t) {
+    return true;
+  }
+
+  struct DateTime {
+    int year;
+    int mon;
+    int day;
+    int hour;
+    int min;
+    int sec;
+    int week;
+  };
+
+  static struct DateTime GetDateTimeNow() {
+    DateTime now;
+    struct tm *t = TimeHelper::getDateTime();
+    now.year = t->tm_year + 1900;
+    now.mon = t->tm_mon + 1;
+    now.day = t->tm_mday;
+    now.hour = t->tm_hour;
+    now.min = t->tm_min;
+    now.sec = t->tm_sec;
+    now.week = t->tm_wday;
+    return now;
+  }
+
+  static struct DateTime GetBuildDateTime() {
+    std::string monthes[] = {
+        "Jan",
+        "Feb",
+        "Mar",
+        "Apr",
+        "May",
+        "Jun",
+        "Jul",
+        "Aug",
+        "Sep",
+        "Oct",
+        "Nov",
+        "Dec",
+    };
+
+    std::string dateStr = __DATE__;
+    int year = atoi(dateStr.substr(dateStr.length() - 4).c_str());
+    int month = 0;
+    for (int i = 0; i < 12; i++) {
+        if (dateStr.find(monthes[i]) != std::string::npos) {
+            month = i + 1;
+            break;
+        }
+    }
+    std::string dayStr = dateStr.substr(4, 2);
+    int day = atoi(dayStr.c_str());
+    std::string timeStr = __TIME__;
+    std::string hourStr = timeStr.substr(0, 2);
+    int hour = atoi(hourStr.c_str());
+    std::string minStr = timeStr.substr(3, 2);
+    int min = atoi(minStr.c_str());
+    std::string secondStr = timeStr.substr(6, 2);
+    int second = atoi(secondStr.c_str());
+
+    DateTime dt;
+    dt.year = year;
+    dt.mon = month;
+    dt.day = day;
+    dt.hour = hour;
+    dt.min = min;
+    dt.sec = second;
+    return dt;
+  }
+
+  static void SetSystemDateTime(time_t timestamp) {
+    TimeHelper::setDateTime(gmtime(&timestamp));
+  }
+
+  static void SetSystemDateTime(DateTime dt) {
+    struct tm t = *TimeHelper::getDateTime();
+    t.tm_year = dt.year - 1900;
+    t.tm_mon = (dt.mon - 1) % 12; //[0,11]
+    t.tm_mday = dt.day % 32; //[1,31]
+    t.tm_hour = dt.hour % 24; //[0,23]
+    t.tm_min = dt.min % 60; //[0,59]
+    t.tm_sec = dt.sec % 60; //[0,59]
+    TimeHelper::setDateTime(&t);
+  }
+
+private:
+
+};
+
+} /* namespace base */
+
+#endif /* _FY_TIME_H_ */

+ 219 - 0
jni/base/timer.hpp

@@ -0,0 +1,219 @@
+#ifndef _FY_TIMER_H_
+#define _FY_TIMER_H_
+
+#include <time.h>
+#include <map>
+#include <memory.h>
+#include <string.h>
+#include <asm-generic/siginfo.h>
+#include "utils/Log.h"
+
+#include "mutex.hpp"
+
+namespace base {
+
+/**
+ * 计时timer
+ */
+class timer {
+public:
+  timer():add_up_time_(0), start_time_(this->uptime()) {
+  }
+  void reset() {
+    start_time_ = this->uptime();
+    add_up_time_ = 0;
+  }
+  int64_t elapsed() const {
+    if (start_time_ < 0) {
+      return add_up_time_;
+    }
+    return this->uptime() - start_time_ + add_up_time_;
+  }
+  void pause() {
+    if (start_time_ >= 0) {
+      add_up_time_ += (this->uptime() - start_time_);
+    }
+    start_time_ = -1;
+  }
+  void resume() {
+    if (start_time_ < 0) {
+      start_time_ = this->uptime();
+    }
+  }
+  bool paused() const {
+    return start_time_ < 0;
+  }
+
+private:
+  static int64_t uptime() {
+      struct timespec ts;
+      clock_gettime(CLOCK_BOOTTIME, &ts);
+      return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
+  }
+  int64_t add_up_time_;
+  int64_t start_time_;
+};
+
+/**
+ * 日志输出时间间隔
+ */
+class progress_timer : private base::timer {
+public:
+  explicit progress_timer(const char* label):base::timer(),label_(label) {
+  }
+  ~progress_timer(){
+    int64_t progress = elapsed();
+    int64_t second = progress/1000;
+    if (second > 0) {
+      LOGD("%s took \033[1;32m%llds.%lldms\033[0m", label_.c_str(), progress/1000, progress%1000);
+    } else {
+      LOGD("%s took \033[1;32m%lldms\033[0m", label_.c_str(),progress%1000);
+    }
+  }
+private:
+  std::string label_;
+};
+
+/**
+ * 可能需要链接  -lrt
+ */
+class posix_timer {
+public:
+  typedef void (*posix_timer_callback)(int timer_id, void * user_data);
+
+private:
+  struct description;
+
+public:
+  virtual ~posix_timer() {
+    std::map<int, description>::iterator des = all_timer_.begin();
+    for (; des != all_timer_.end(); des++) {
+      destroy(des->first);
+    }
+  }
+
+private:
+  /**
+   * return timer id
+   */
+  static int _create(bool oneshot, int period_millis, int delay_millis, posix_timer_callback on_timer, void* user_data) {
+    fy::lock_guard<fy::mutex> lock(instance()->mutex_);
+    instance()->sival_int_++;
+    int ret;
+    timer_t timer;
+    struct sigevent evp;
+    struct timespec spec;
+    struct itimerspec time_value;
+
+    memset((void*)&evp, 0, sizeof(sigevent));
+    evp.sigev_value.sival_int = instance()->sival_int_;
+    /* 子线程运行 */
+    evp.sigev_notify = SIGEV_THREAD;
+    evp.sigev_notify_function = posix_timer::timer_thread_callback_wrapper;
+
+    ret = timer_create(CLOCK_MONOTONIC, &evp, &timer);
+    if (-1 == ret) {
+      //LOGE("timer_create Failed");
+      return -1;
+    }
+
+    time_value.it_interval.tv_sec = period_millis / 1000;      /*n秒触发一次*/
+    time_value.it_interval.tv_nsec = period_millis % 1000 * 1000 * 1000;
+    clock_gettime(CLOCK_MONOTONIC, &spec);
+    time_value.it_value.tv_sec = spec.tv_sec + delay_millis / 1000;      /*n秒后启动*/
+    time_value.it_value.tv_nsec = spec.tv_nsec + delay_millis % 1000 * 1000 * 1000;
+
+    struct description des = {
+        oneshot,
+        period_millis,
+        timer,
+        instance()->sival_int_,
+        user_data,
+        on_timer
+    };
+    instance()->all_timer_[instance()->sival_int_] = des;
+
+    //启动
+    ret = timer_settime(timer, CLOCK_MONOTONIC, &time_value, NULL);
+    if(-1 == ret) {
+      //LOGE("timer_settime Failed");
+      timer_delete(timer);
+      instance()->all_timer_.erase(instance()->all_timer_.find(instance()->sival_int_));
+      return -2;
+    }
+    //LOGD("start timer");
+    return instance()->sival_int_;
+  }
+
+public:
+  static void destroy(int timer_id) {
+    fy::lock_guard<fy::mutex> lock(instance()->mutex_);
+    std::map<int, description>::iterator it = instance()->all_timer_.find(timer_id);
+    if (it == instance()->all_timer_.end()) {
+      return;
+    }
+    timer_delete(it->second.timer);
+    instance()->all_timer_.erase(it);
+  }
+
+  static int oneshot(time_t delay_millis, posix_timer_callback on_timer, void* user_data) {
+    return instance()->_create(true, 0, delay_millis, on_timer, user_data);
+  }
+
+  /**
+   * 每次回调都会创建一个新线程,并且,回调的执行时间不影响定时器下一次的触发时间;
+   * 这意味着,如果回调中耗时长于period_millis,会同时存在多个回调。
+   */
+  static int create(int period_millis, int delay_millis, posix_timer_callback on_timer, void* user_data) {
+    return instance()->_create(false, period_millis, delay_millis, on_timer, user_data);
+  }
+
+private:
+  posix_timer() {
+    sival_int_ = 0;
+  }
+
+  static posix_timer* instance() {
+    static posix_timer singleton;
+    return &singleton;
+  }
+
+  static void timer_thread_callback_wrapper(union sigval v) {
+    instance()->timer_thread_callback(v);
+  }
+
+  void timer_thread_callback(union sigval v) {
+    description des;
+    {  // scope lock
+      fy::lock_guard<fy::mutex> lock(mutex_);
+      std::map<int, description>::iterator it = all_timer_.find(v.sival_int);
+      if (it == all_timer_.end()) {
+        return;
+      }
+      des = it->second;
+      if (des.is_oneshot) {
+        timer_delete(it->second.timer);
+        instance()->all_timer_.erase(it);
+      }
+    }
+    des.callback(des.sival_int, des.user_data);
+  }
+
+  struct description {
+    bool is_oneshot;
+    time_t interval;
+    timer_t timer;
+    int sival_int;
+    void* user_data;
+    posix_timer_callback callback;
+  };
+private:
+  int sival_int_;
+  fy::mutex mutex_;
+  std::map<int, description> all_timer_;
+
+};
+
+} /* namespace fy */
+
+#endif /* JNI_FY_TIMER_H_ */

+ 374 - 0
jni/core/CPullWindow/CPullWindow.cpp

@@ -0,0 +1,374 @@
+/*
+ * CPullWindow.cpp
+ *
+ *  Created on: 2021年3月30日
+ *      Author: Administrator
+ */
+#include "CPullWindow.h"
+
+#include "entry/EasyUIContext.h"
+
+#define TURN_PAGE_MIN_SPEED		0.0001
+#define WFILE "CPullWindow.cpp"
+
+CPullWindow::CPullWindow() :
+		isDownPull(false),
+		isRegistered(false),
+		isCanMove(false),
+		mHasDown(false),
+		mIsRolling(false),
+		mCurRollSpeed(CPullWindow_ROLL_SPEED),
+		mRollSpeed(CPullWindow_ROLL_SPEED),
+		mBase(NULL),
+		mStartDownTime(0){
+
+	isFuncMove = false;
+
+	isTextView1GraymaskShow = false;
+	mBaseColor = NULL;
+}
+
+void CPullWindow::resetPage(){
+	mStartDownTime = 0;
+	mRollSpeed = CPullWindow_ROLL_SPEED;
+
+	mCurRollSpeed = CPullWindow_ROLL_SPEED;
+	isTextView1GraymaskShow = false;
+	mIsRolling = false;
+	mHasDown  = false;
+	mBase = NULL;
+	isRegistered = false;
+	isCanMove = false;
+	isFuncMove = false;
+	mBaseColor = NULL;
+}
+
+LayoutPosition CPullWindow::getPosition(){
+	if(mBase){
+		return mBase->getPosition();
+	}else{
+		return LayoutPosition();
+	}
+}
+
+/// 下拉状态栏,设置透明度
+void CPullWindow::setBottomWindowColor(ZKBase* pBaseColor){
+	if(pBaseColor){
+
+		mBaseColor = pBaseColor;
+	}else if(!mBaseColor){
+
+		return;
+	}
+
+#define TEXT_WIDTH 480
+
+
+	float rate_pos =   \
+			(float)((abs(getPosition().mTop + TEXT_WIDTH))%(TEXT_WIDTH + 1))/(float)(TEXT_WIDTH);
+
+	unsigned int colorBack = (unsigned int)((double)(rate_pos)  * (double)(0xFF000000)) & 0xFF000000;
+
+	if(WBETWEEN_PullWindow((float)((abs(getPosition().mTop + TEXT_WIDTH))%(TEXT_WIDTH + 1)),0,340)){
+		mBaseColor->setBackgroundColor(colorBack);
+	}
+
+
+
+#if 0
+	WLOGD_lf("彩色值",WDOUBLE(0xFF000000))
+
+	LOGD("比率:%f = %f/%f\n",
+			rate_pos,
+			WFLOAT((WABS(UIMANAGER->mCPullWindow.getDy() + TEXT_WIDTH))%(TEXT_WIDTH + 1)),
+			WFLOAT(TEXT_WIDTH)
+			);
+
+	LOGD("结果:%u(%x) = (%lf * %lf) & 0xFF000000\n",
+			colorBack,
+			colorBack,
+			WDOUBLE(rate_pos),
+			WDOUBLE(0xFF000000));
+
+
+	LOGD("结果:%u(%x) = Dy(%d) (%d)\n",
+			colorBack,
+			colorBack,
+			UIMANAGER->mCPullWindow.getDy(),
+			(WABS(UIMANAGER->mCPullWindow.getDy() + TEXT_WIDTH))
+			);
+#endif
+}
+
+
+void CPullWindow::onCPullWindow_init(ZKBase *pBase){
+
+	if(mBase){
+		setBottomWindowColor();
+	}
+
+	if(pBase){
+
+		mBase = pBase;
+	}else if(!mBase){
+		LOGD("\n\n\n######:%s(%d),impossible\n",WFILE,__LINE__);
+
+		LOGD("****:%s(%d):%s(%s)\n",WFILE,__LINE__,"setPage() error","pBase == NULL");
+
+		return;
+	}
+	LayoutPosition pos = mBase->getPosition();
+	pos.mTop = -pos.mHeight;
+	mBase->setPosition(pos);
+	isTextView1GraymaskShow = false;
+
+}
+
+// 移动函数
+void CPullWindow::movePage(int dy){
+	if(!mBase){
+
+		LOGD("\n\n\n######:%s(%d),impossible\n",WFILE,__LINE__);
+
+		LOGD("****:%s(%d):%s(%s)\n",WFILE,__LINE__,"movePage() error","mBase == NULL");
+		return;
+	}
+	LayoutPosition lp = mBase->getPosition();
+	//LOGD("i=%d,lp.mTop = %d,dy = %d   ,return\n",i,lp.mTop,dy);
+	if (lp.mTop == dy) {
+		return;
+	}
+	// 移动当前的一页
+	lp.mTop = dy;
+	//LOGD("####:dy(%d)(%d,%d,%d,%d)\n",dy,lp.mLeft,lp.mTop,lp.mWidth,lp.mHeight);
+	//上滑时,不允许下拉过多
+	if(!isDownPull && lp.mTop <=0)
+		mBase->setPosition(lp);
+	else if(isDownPull)
+		mBase->setPosition(lp);
+}
+
+// 判断,是否去滑动
+bool CPullWindow::needToRoll() const{
+	if (!mBase) {
+		return false;
+	}
+	return isFuncMove || (mBase->getPosition().mTop != 0 && mBase->getPosition().mTop != -mBase->getPosition().mHeight);
+}
+
+void CPullWindow::setBaseUpMove(){
+	if (!mBase || isRunning()) {
+		if(!mBase){
+
+			LOGD("\n\n\n######:%s(%d),impossible\n",WFILE,__LINE__);
+
+			LOGD("****:%s(%d):%s(%s)\n",WFILE,__LINE__,"setBaseDownMove() error","mBase == NULL");
+		}
+		return;
+	}
+	isFuncMove = true;
+
+
+	mCurRollSpeed = -mRollSpeed;
+
+	run();
+}
+
+void CPullWindow::setBaseDownMove(){
+	if (!mBase || isRunning()) {
+		if(!mBase){
+
+			LOGD("\n\n\n######:%s(%d),impossible\n",WFILE,__LINE__);
+
+			LOGD("****:%s(%d):%s(%s)\n",WFILE,__LINE__,"setBaseDownMove() error","mBase == NULL");
+		}
+		return;
+	}
+
+	isFuncMove = true;
+	mCurRollSpeed = mRollSpeed;
+
+	run();
+}
+
+// 通过滑动判断左移还是右移动
+bool CPullWindow::onTouchEvent(const MotionEvent &ev) {
+	if (!mBase || mIsRolling) {
+		return false;
+	}
+
+	switch (ev.mActionStatus) {
+		case MotionEvent::E_ACTION_DOWN:
+			if ((mBase->getPosition().mTop == -mBase->getPosition().mHeight
+					&& WBETWEEN_PullWindow(ev.mY,CPullWindow_Pull_Top,CPullWindow_Pull_High))
+					|| !mBase->getPosition().mTop) {
+				mDownPoint.x = ev.mX;
+				mDownPoint.y = ev.mY;
+				mHasDown = true;
+				isCanMove = false;
+				mStartDownTime = clock();
+				if((mBase->getPosition().mTop == -mBase->getPosition().mHeight
+						&& WBETWEEN_PullWindow(ev.mY,CPullWindow_Pull_Top,CPullWindow_Pull_High))){
+					isDownPull = true;
+//					LOGD_LINE("可能准备下拉")
+				}else if(!mBase->getPosition().mTop){
+//					LOGD_LINE("可能准备上滑")
+					isDownPull = false;
+				}else{
+//					LOGD_LINE("无法滑动状态栏")
+					mHasDown = false;
+				}
+			}else{
+//				LOGD_LINE("无法滑动状态栏")
+				mHasDown = false;
+			}
+			break;
+
+		case MotionEvent::E_ACTION_MOVE: {
+			if (!mHasDown) {
+				return false;
+			}else if(!isCanMove && ((!isDownPull &&  ev.mY - mDownPoint.y < -20) || (isDownPull &&  ev.mY - mDownPoint.y > 20))){
+				isCanMove = true;
+
+				//LOGD("####:差值(%d),滑动(%d),downPoint(%d)\n",abs(ev.mY - mDownPoint.y),ev.mY,mDownPoint.y);
+				mDownPoint.x = ev.mX;
+				mDownPoint.y = ev.mY;
+
+//				UIMANAGER->setStatusBarMove(false);
+
+//				LOGD_s("准备下拉栏")
+
+				return isCanMove;
+			}else if(!isCanMove){
+				//LOGD("差值(%d),滑动(%d),downPoint(%d)\n",abs(ev.mY - mDownPoint.y),ev.mY,mDownPoint.y);
+				return isCanMove;
+			}
+
+			//LOGD("****:PullDownWindow:滑动\n");
+			int dy = ev.mY - mDownPoint.y;
+			//LOGD("dy(%d)\n",dy);
+			if(isDownPull)
+				movePage(-mBase->getPosition().mHeight + dy);
+			else
+				movePage(dy);
+			// 用于计算滑动速度
+			mVelocityTracker.addMovement(ev);
+
+
+			setBottomWindowColor();
+
+			break;
+		}
+
+		case MotionEvent::E_ACTION_UP:
+		case MotionEvent::E_ACTION_CANCEL: {  // 抬手判断 向左滑动还是向右滑动
+			if (!mHasDown || !isCanMove) {
+				mHasDown = false;
+				return false;
+			}
+
+			mUpPoint.x = ev.mX;
+			mUpPoint.y = ev.mY;
+			mHasDown   = false;
+			isCanMove = false;
+			float speed = mVelocityTracker.getYVelocity();  // 获取y移动速度
+			//LOGD("滑速(%f)\n",speed);
+
+			//下滑
+			if (isDownPull && ((mUpPoint.y - mDownPoint.y > mBase->getPosition().mHeight / 3) ||
+					(speed > TURN_PAGE_MIN_SPEED))) {
+				mCurRollSpeed = mRollSpeed;
+				//LOGD("####下滑:滑速(%d)\n",mCurRollSpeed);
+			//上滑
+			} else if (!isDownPull && ((mUpPoint.y - mDownPoint.y < -mBase->getPosition().mHeight / 3) ||
+					(speed < -TURN_PAGE_MIN_SPEED))) {
+				mCurRollSpeed = -mRollSpeed;
+				//LOGD("####上滑:滑速(%d)\n",mCurRollSpeed);
+			//回滚
+			} else {
+				//向下
+				mCurRollSpeed = isDownPull ? -mRollSpeed : mRollSpeed;
+				//LOGD("####回滚:滑速(%d)\n",mCurRollSpeed);
+			}
+
+			mVelocityTracker.reset();
+			if (needToRoll()) {   // 可以运行就启动计时器
+				//LOGD("启动定时器,speed(%f),downY(%d),upY(%d)\n",speed,mDownPoint.y,mUpPoint.y);
+				mIsRolling = true;
+				if(!isRunning()){
+					run();
+				}
+
+				isTextView1GraymaskShow = true;
+
+			}
+
+			break;
+		}
+		case MotionEvent::E_ACTION_NONE:
+		default:
+			break;
+	}
+
+	return false;
+}
+
+bool CPullWindow::threadLoop() {
+
+		if(!mBase){
+
+			LOGD("\n\n\n######:%s(%d),impossible\n",WFILE,__LINE__);
+
+			LOGD("****:%s(%d):%s(%s)\n",WFILE,__LINE__,"threadLoop() error","mBase == NULL");
+
+			mIsRolling = false;
+			isRegistered = false;
+			isTextView1GraymaskShow = false;
+
+			setBottomWindowColor();
+
+			return false;
+		}
+
+		LayoutPosition lp = mBase->getPosition();
+		int dy = lp.mTop + mCurRollSpeed;
+		if (needToRoll()) {
+			if (mCurRollSpeed > 0) {	// 向下滚动
+				if(dy > 0){
+//					LOGD("向下滚动\n");
+					dy = 0;
+					isFuncMove = false;
+				}
+			} else {	// 向上滚动
+				if(dy < -mBase->getPosition().mHeight){// 回滚
+//					LOGD("向上滚动\n");
+					dy = -mBase->getPosition().mHeight;
+					isFuncMove = false;
+
+//					UIMANAGER->setStatusBarMove(true);
+				}
+			}
+			movePage(dy);
+		}
+
+		if (!needToRoll()) {
+			movePage(dy);
+			LayoutPosition lp1 = mBase->getPosition();
+			mBase->setPosition(lp1);
+			mIsRolling = false;
+			isTextView1GraymaskShow = false;
+			setBottomWindowColor();
+			isRegistered = false;
+
+			return false;
+		}
+
+		sleep(10);
+
+		setBottomWindowColor();
+	return true;
+
+
+
+}
+

+ 76 - 0
jni/core/CPullWindow/CPullWindow.h

@@ -0,0 +1,76 @@
+/*
+ * CPullWindow.h
+ *
+ *  Created on: 2021年3月30日
+ *      Author: Administrator
+ */
+
+#ifndef JNI_W_FILE_INCLUDE_W_SCROLLWINDOWWRAPPER_H_
+#define JNI_W_FILE_INCLUDE_W_SCROLLWINDOWWRAPPER_H_
+
+#include "w_DefPullWidnow.h"
+
+
+class CPullWindow:public Thread {
+public:
+	CPullWindow();
+
+	/// 清空
+	void resetPage();
+
+	/// 设置下拉栏初始位置
+	void onCPullWindow_init(ZKBase *pBase = NULL);
+
+	// 通过滑动判断左移还是右移动
+	bool onTouchEvent(const MotionEvent &ev);
+
+	/// 获取下拉栏y轴坐标
+	LayoutPosition getPosition();
+
+	/// 上移。增加移动效果
+	void setBaseUpMove();
+
+	/// 上拉。增加移动效果
+	void setBaseDownMove();
+
+	/** 额外添加的功能 *****************************************/
+
+	/// 下拉状态栏,设置透明度
+	void setBottomWindowColor(ZKBase* pBaseColor = NULL);
+
+protected:
+
+	// 判断可不可以滑动
+	bool needToRoll() const;
+
+	// 移动函数
+	void movePage(int dy);
+
+	/**
+	 * @brief 线程循环调用该接口
+	 * @return true 不退出线程,false 将退出线程
+	 */
+	virtual bool threadLoop();
+private:
+	/// 额外添加功能成员
+	bool isTextView1GraymaskShow;/// 灰色蒙版
+	ZKBase* mBaseColor; /// 设置Base背景色
+
+	/// 固定成员
+	bool isDownPull;//true:是下拉
+	bool isRegistered;
+	bool isCanMove;//true:有滑动事件
+	bool isFuncMove;/// 函数调用移动
+	bool mHasDown;
+	bool mIsRolling;
+	int mCurRollSpeed;
+	unsigned int mRollSpeed;
+	ZKBase* mBase;
+	long int mStartDownTime;
+	PWPOINT mDownPoint;
+	PWPOINT mUpPoint;
+	VelocityTracker mVelocityTracker; // 速度追踪
+};
+
+
+#endif /* JNI_W_FILE_INCLUDE_W_SCROLLWINDOWWRAPPER_H_ */

+ 29 - 0
jni/core/CPullWindow/w_DefPullWidnow.h

@@ -0,0 +1,29 @@
+/*
+ * w_DefPullWidnow.h
+ *
+ *  Created on: 2021年8月10日
+ *      Author: Admin
+ */
+
+#ifndef JNI_CPULLWINDOW_W_DEFPULLWIDNOW_H_
+#define JNI_CPULLWINDOW_W_DEFPULLWIDNOW_H_
+
+#include "control/ZKBase.h"
+#include "system/Thread.h"
+#include "utils/Log.h"
+#include "utils/VelocityTracker.h"
+
+#define CPullWindow_Pull_Top 0 /// 窗口拉取有效区域
+#define CPullWindow_Pull_High 50 /// 窗口拉取有效区域
+
+#define CPullWindow_ROLL_SPEED  30 /// 窗口滚动速度
+
+#define WBETWEEN_PullWindow(i,sMin,sMax) (i >= sMin && i <= sMax)
+
+
+struct PWPOINT{
+	int x;
+	int y;
+};
+
+#endif /* JNI_CPULLWINDOW_W_DEFPULLWIDNOW_H_ */

+ 0 - 0
jni/core/VelocityTracker.h


Some files were not shown because too many files changed in this diff