testkit-stub v2.1 initial version
authorjoey <joey@joey-tang.sh.intel.com>
Tue, 7 May 2013 10:10:54 +0000 (18:10 +0800)
committerjoey <joey@joey-tang.sh.intel.com>
Tue, 7 May 2013 10:10:54 +0000 (18:10 +0800)
32 files changed:
CommandLineBuild/build_data [new file with mode: 0644]
CommandLineBuild/makefile [new file with mode: 0644]
README.md
include/comfun.h [new file with mode: 0644]
include/httpserver.h [new file with mode: 0644]
include/json/autolink.h [new file with mode: 0644]
include/json/config.h [new file with mode: 0644]
include/json/features.h [new file with mode: 0644]
include/json/forwards.h [new file with mode: 0644]
include/json/json.h [new file with mode: 0644]
include/json/reader.h [new file with mode: 0644]
include/json/value.h [new file with mode: 0644]
include/json/writer.h [new file with mode: 0644]
include/testcase.h [new file with mode: 0644]
makefile [new file with mode: 0644]
packaging/testkit-stub.debug.spec [new file with mode: 0644]
packaging/testkit-stub.spec [new file with mode: 0644]
src/comfun.cpp [new file with mode: 0644]
src/httpserver.cpp [new file with mode: 0644]
src/json/json_batchallocator.h [new file with mode: 0644]
src/json/json_internalarray.inl [new file with mode: 0644]
src/json/json_internalmap.inl [new file with mode: 0644]
src/json/json_reader.cpp [new file with mode: 0644]
src/json/json_value.cpp [new file with mode: 0644]
src/json/json_valueiterator.inl [new file with mode: 0644]
src/json/json_writer.cpp [new file with mode: 0644]
src/json/sconscript [new file with mode: 0644]
src/main/main.cpp [new file with mode: 0644]
src/testcase.cpp [new file with mode: 0644]
src/ut/httpserver_log.txt [new file with mode: 0644]
src/ut/test.json [new file with mode: 0644]
src/ut/ut.cpp [new file with mode: 0644]

diff --git a/CommandLineBuild/build_data b/CommandLineBuild/build_data
new file mode 100644 (file)
index 0000000..b09603f
--- /dev/null
@@ -0,0 +1,9 @@
+target:emulator:tizen-emulator-2.0.cpp_llvm31.i386.cpp.app
+target:device:tizen-device-2.0.cpp_llvm31.armel.cpp.app
+target:emulator:includepath:-I/home/danny/tizen-sdk/tools/empty/inc -I/home/danny/tizen-sdk/platforms/tizen2.0/rootstraps/tizen-emulator-2.0.cpp/usr/include -I/home/danny/tizen-sdk/platforms/tizen2.0/rootstraps/tizen-emulator-2.0.cpp/usr/include/libxml2 -I/home/danny/tizen-sdk/library -I/home/danny/tizen-sdk/platforms/tizen2.0/rootstraps/tizen-emulator-2.0.cpp/usr/include/osp 
+target:device:includepath:-I/home/danny/tizen-sdk/tools/empty/inc -I/home/danny/tizen-sdk/platforms/tizen2.0/rootstraps/tizen-device-2.0.cpp/usr/include -I/home/danny/tizen-sdk/platforms/tizen2.0/rootstraps/tizen-device-2.0.cpp/usr/include/libxml2 -I/home/danny/tizen-sdk/library -I/home/danny/tizen-sdk/platforms/tizen2.0/rootstraps/tizen-device-2.0.cpp/usr/include/osp 
+target:emulator:cflags:-target i386-tizen-linux-gnueabi -gcc-toolchain /home/danny/tizen-sdk/tools/smart-build-interface/../i386-linux-gnueabi-gcc-4.5/ -ccc-gcc-name i386-linux-gnueabi-g++ -march=i386 -Wno-gnu  -fPIE --sysroot=/home/danny/tizen-sdk/platforms/tizen2.0/rootstraps/tizen-emulator-2.0.cpp 
+target:device:cflags:-target arm-tizen-linux-gnueabi -gcc-toolchain /home/danny/tizen-sdk/tools/smart-build-interface/../arm-linux-gnueabi-gcc-4.5/ -ccc-gcc-name arm-linux-gnueabi-g++ -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mtune=cortex-a8 -Wno-gnu  -fPIE --sysroot=/home/danny/tizen-sdk/platforms/tizen2.0/rootstraps/tizen-device-2.0.cpp 
+target:emulator:lflags:-target i386-tizen-linux-gnueabi -gcc-toolchain /home/danny/tizen-sdk/tools/smart-build-interface/../i386-linux-gnueabi-gcc-4.5/ -ccc-gcc-name i386-linux-gnueabi-g++ -march=i386 -Xlinker --as-needed -pie -lpthread  --sysroot=/home/danny/tizen-sdk/platforms/tizen2.0/rootstraps/tizen-emulator-2.0.cpp -L/home/danny/tizen-sdk/platforms/tizen2.0/rootstraps/tizen-emulator-2.0.cpp/usr/lib -L/home/danny/tizen-sdk/platforms/tizen2.0/rootstraps/tizen-emulator-2.0.cpp/usr/lib/osp -losp-appfw -losp-uifw -losp-image -losp-json -losp-ime -losp-net -lpthread -losp-content -losp-locations -losp-telephony -losp-uix -losp-media -losp-messaging -losp-web -losp-social -losp-wifi -losp-bluetooth -losp-nfc -losp-face -losp-speech-tts -losp-speech-stt -losp-shell -losp-shell-core -lxml2 
+target:device:lflags:-target arm-tizen-linux-gnueabi -gcc-toolchain /home/danny/tizen-sdk/tools/smart-build-interface/../arm-linux-gnueabi-gcc-4.5/ -ccc-gcc-name arm-linux-gnueabi-g++ -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mtune=cortex-a8 -Xlinker --as-needed -pie -lpthread  --sysroot=/home/danny/tizen-sdk/platforms/tizen2.0/rootstraps/tizen-device-2.0.cpp -L/home/danny/tizen-sdk/platforms/tizen2.0/rootstraps/tizen-device-2.0.cpp/usr/lib -L/home/danny/tizen-sdk/platforms/tizen2.0/rootstraps/tizen-device-2.0.cpp/usr/lib/osp -losp-appfw -losp-uifw -losp-image -losp-json -losp-ime -losp-net -lpthread -losp-content -losp-locations -losp-telephony -losp-uix -losp-media -losp-messaging -losp-web -losp-social -losp-wifi -losp-bluetooth -losp-nfc -losp-face -losp-speech-tts -losp-shell -losp-shell-core -losp-speech-stt -lxml2 
+
diff --git a/CommandLineBuild/makefile b/CommandLineBuild/makefile
new file mode 100644 (file)
index 0000000..218cbf3
--- /dev/null
@@ -0,0 +1,135 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+-include ../makefile.init
+INCLUDES = -I ../include
+
+RM := rm -rf
+
+# All of the sources participating in the build are defined here
+# -include sources.mk
+O_SRCS := 
+PO_SRCS := 
+CPP_SRCS := 
+C_UPPER_SRCS := 
+C_SRCS := 
+S_UPPER_SRCS := 
+OBJ_SRCS := 
+EDC_SRCS := 
+ASM_SRCS := 
+CXX_SRCS := 
+C++_SRCS := 
+CC_SRCS := 
+MO_FILES := 
+OBJS := 
+C++_DEPS := 
+C_DEPS := 
+CC_DEPS := 
+EDJ_FILES := 
+CPP_DEPS := 
+EXECUTABLES := 
+C_UPPER_DEPS := 
+CXX_DEPS := 
+
+# Every subdirectory with source files must be described here
+SUBDIRS := \
+src \
+
+# -include src/subdir.mk
+# Add inputs and outputs from these tool invocations to the build variables 
+CPP_SRCS += \
+../src/main/main.cpp \
+../src/comfun.cpp \
+../src/testcase.cpp \
+../src/httpserver.cpp \
+../src/json/json_reader.cpp \
+../src/json/json_value.cpp \
+../src/json/json_writer.cpp
+
+
+OBJS += \
+./src/main/main.o \
+./src/comfun.o \
+./src/testcase.o \
+./src/httpserver.o \
+./src/json/json_reader.o \
+./src/json/json_value.o \
+./src/json/json_writer.o
+
+
+CPP_DEPS += \
+./src/main/main.d \
+./src/comfun.d \
+./src/testcase.d \
+./src/httpserver.d \
+./src/json/json_reader.d \
+./src/json/json_value.d \
+./src/json/json_writer.d
+
+
+# Each subdirectory must supply rules for building sources it contributes
+src/%.o: ../src/%.cpp
+       @echo 'Building file: $<'
+       @echo 'Invoking: C++ Compiler'
+       $(CC) -I"pch" -D_DEBUG -O0 -g3 -Wall -c -fmessage-length=0 $(INCLUDE_PATH) $(INCLUDES) $(CFLAG) -D_APP_LOG -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o "$@" "$<"
+       @echo 'Finished building: $<'
+       @echo ' '
+
+
+# -include objects.mk
+USER_OBJS :=
+
+LIBS :=
+
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(strip $(C++_DEPS)),)
+-include $(C++_DEPS)
+endif
+ifneq ($(strip $(C_DEPS)),)
+-include $(C_DEPS)
+endif
+ifneq ($(strip $(CC_DEPS)),)
+-include $(CC_DEPS)
+endif
+ifneq ($(strip $(CPP_DEPS)),)
+-include $(CPP_DEPS)
+endif
+ifneq ($(strip $(CXX_DEPS)),)
+-include $(CXX_DEPS)
+endif
+ifneq ($(strip $(C_UPPER_DEPS)),)
+-include $(C_UPPER_DEPS)
+endif
+endif
+
+-include ../makefile.defs
+
+# Add inputs and outputs from these tool invocations to the build variables 
+
+# All Target
+all: httpserver secondary-outputs
+
+init: 
+       mkdir -p src/json
+       mkdir -p src/main
+
+# Tool invocations
+httpserver: init $(OBJS) $(USER_OBJS)
+       @echo 'Building target: $@'
+       @echo 'Invoking: C++ Linker'
+       $(CC) -o"httpserver" $(OBJS) $(USER_OBJS) $(LIBS) $(LFLAG)
+       @echo 'Finished building target: $@'
+       @echo ' '
+
+# Other Targets
+clean:
+       -$(RM) src httpserver
+
+secondary-outputs: $(MO_FILES) $(EDJ_FILES)
+
+.PHONY: all clean dependents
+.SECONDARY:
+
+-include ../makefile.targets
+
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2ffb37f15a51b5b8fdae5c6172ad8d6e39956ea8 100644 (file)
--- a/README.md
+++ b/README.md
@@ -0,0 +1,17 @@
+TCT-stub
+========
+
+Intel Tizen Compatibility Test Stub
+
+to build ARM version locally(without OBS), please make sure 
+
+1, install tizen2.0 SDK with all component selected, 
+
+2, replace all "/home/danny/" in build_data to your own home path, such as "/home/wl/"
+
+3, run native-make -t device in CommandLineBuild folder.
+
+
+to build unit test, just run "make ut" in root folder of the project. then run valgrind to check memory leak.
+
+valgrind --tool=memcheck --leak-check=yes --track-origins=yes -v ./ut
\ No newline at end of file
diff --git a/include/comfun.h b/include/comfun.h
new file mode 100644 (file)
index 0000000..4540ae3
--- /dev/null
@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <string.h>
+#include <string>
+#include <vector>
+using namespace std;
+class ComFun {
+public:
+       ComFun();
+       virtual ~ComFun();
+public:
+       static char CharToInt(char ch);
+       static char StrToBin(char *str);
+       static char* UrlDecode(const char *str);
+       static std::vector<std::string> split(std::string str, std::string pattern);
+};
+
diff --git a/include/httpserver.h b/include/httpserver.h
new file mode 100644 (file)
index 0000000..21f1899
--- /dev/null
@@ -0,0 +1,95 @@
+#include <stdio.h>
+#include <fstream>
+#include <string.h>
+#include "testcase.h"
+
+#include <string>
+using namespace std;
+
+void timer_handler(int signum);
+
+typedef struct HttpRequest {
+       string method;     // request type
+       string path;       // request path
+       string content;    // request content
+       int contentlength; // length of request length
+       int contenttype;   // response content type
+       string prefix;
+       int responsecode;  //response code
+} HR;
+
+class HttpServer {
+public:
+       HttpServer();
+       virtual ~HttpServer();
+public:
+       void StartUp();
+       void processpost(int s, struct HttpRequest *prequest);
+       void sendresponse(int s, int code, struct HttpRequest *prequest,
+                       string content);
+       int sendsegment(int s, string buffer);
+       void parse_json_str(string jsonstr);
+       int getrequest(string requestbuf, struct HttpRequest *prequest);
+       bool get_auto_case(string content, string *type);
+       void checkResult(TestCase* testcase);
+       void killAllWidget();
+       void start_client();
+       bool run_cmd(string cmdString, string expectString, bool showcmdAnyway);
+       void print_info_string(string case_id);
+       void find_purpose(struct HttpRequest *prequest, bool auto_test);
+       void getCurrentTime();
+       void cancel_time_check();
+       void set_timer(int timeout_value);
+       void getAllWidget();
+
+       struct sigaction sa;
+       struct itimerval timer;
+       int gIsRun;
+       int clientsocket;
+
+       int gServerStatus;
+
+       string m_exeType; //auto;manual 
+       TestCase *m_test_cases; //the case array
+
+       //block 
+       int m_totalBlocks;
+       int m_current_block_index;
+       int m_totalcaseCount;
+       int m_total_case_index; //current case index in set
+       int m_block_case_index; //current case index in block
+       int m_block_case_count; //case count in block
+       bool m_block_finished;
+       bool m_set_finished;
+       bool m_server_checked;
+
+       Json::Value m_capability;
+       //TestStatus   
+       int m_timeout_count; // continusously time out count
+
+       int m_killing_widget;
+       
+       std::vector<string> m_widgets; // store all the widgets short name
+
+       string m_running_session;
+
+       string m_last_auto_result;
+
+       int m_failto_launch; // time of fail to launch
+
+       bool m_rerun; // true when re-run a case
+
+       //some variables get from cmd line
+       bool g_show_log;
+       string g_port;
+       string g_hide_status;
+       string g_test_suite;
+       string g_launch_cmd;
+       string g_kill_cmd;
+       string g_exe_sequence;
+       string g_enable_memory_collection;
+       string g_launcher;//lancher name:wrt-launcher/browser
+       bool g_run_wiget;//whether run on the device with wiget
+
+       ofstream outputFile;
+};
diff --git a/include/json/autolink.h b/include/json/autolink.h
new file mode 100644 (file)
index 0000000..37c9258
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef JSON_AUTOLINK_H_INCLUDED
+# define JSON_AUTOLINK_H_INCLUDED
+
+# include "config.h"
+
+# ifdef JSON_IN_CPPTL
+#  include <cpptl/cpptl_autolink.h>
+# endif
+
+# if !defined(JSON_NO_AUTOLINK)  &&  !defined(JSON_DLL_BUILD)  &&  !defined(JSON_IN_CPPTL)
+#  define CPPTL_AUTOLINK_NAME "json"
+#  undef CPPTL_AUTOLINK_DLL
+#  ifdef JSON_DLL
+#   define CPPTL_AUTOLINK_DLL
+#  endif
+#  include "autolink.h"
+# endif
+
+#endif // JSON_AUTOLINK_H_INCLUDED
diff --git a/include/json/config.h b/include/json/config.h
new file mode 100644 (file)
index 0000000..5d334cb
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef JSON_CONFIG_H_INCLUDED
+# define JSON_CONFIG_H_INCLUDED
+
+/// If defined, indicates that json library is embedded in CppTL library.
+//# define JSON_IN_CPPTL 1
+
+/// If defined, indicates that json may leverage CppTL library
+//#  define JSON_USE_CPPTL 1
+/// If defined, indicates that cpptl vector based map should be used instead of std::map
+/// as Value container.
+//#  define JSON_USE_CPPTL_SMALLMAP 1
+/// If defined, indicates that Json specific container should be used
+/// (hash table & simple deque container with customizable allocator).
+/// THIS FEATURE IS STILL EXPERIMENTAL!
+//#  define JSON_VALUE_USE_INTERNAL_MAP 1
+/// Force usage of standard new/malloc based allocator instead of memory pool based allocator.
+/// The memory pools allocator used optimization (initializing Value and ValueInternalLink
+/// as if it was a POD) that may cause some validation tool to report errors.
+/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
+//#  define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
+
+/// If defined, indicates that Json use exception to report invalid type manipulation
+/// instead of C assert macro.
+# define JSON_USE_EXCEPTION 1
+
+# ifdef JSON_IN_CPPTL
+#  include <cpptl/config.h>
+#  ifndef JSON_USE_CPPTL
+#   define JSON_USE_CPPTL 1
+#  endif
+# endif
+
+# ifdef JSON_IN_CPPTL
+#  define JSON_API CPPTL_API
+# elif defined(JSON_DLL_BUILD)
+#  define JSON_API __declspec(dllexport)
+# elif defined(JSON_DLL)
+#  define JSON_API __declspec(dllimport)
+# else
+#  define JSON_API
+# endif
+
+#endif // JSON_CONFIG_H_INCLUDED
diff --git a/include/json/features.h b/include/json/features.h
new file mode 100644 (file)
index 0000000..68e473c
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
+# define CPPTL_JSON_FEATURES_H_INCLUDED
+
+# include "forwards.h"
+
+namespace Json {
+
+/** \brief Configuration passed to reader and writer.
+ * This configuration object can be used to force the Reader or Writer
+ * to behave in a standard conforming way.
+ */
+class JSON_API Features {
+public:
+       /** \brief A configuration that allows all features and assumes all strings are UTF-8.
+        * - C & C++ comments are allowed
+        * - Root object can be any JSON value
+        * - Assumes Value strings are encoded in UTF-8
+        */
+       static Features all();
+
+       /** \brief A configuration that is strictly compatible with the JSON specification.
+        * - Comments are forbidden.
+        * - Root object must be either an array or an object value.
+        * - Assumes Value strings are encoded in UTF-8
+        */
+       static Features strictMode();
+
+       /** \brief Initialize the configuration like JsonConfig::allFeatures;
+        */
+       Features();
+
+       /// \c true if comments are allowed. Default: \c true.
+       bool allowComments_;
+
+       /// \c true if root must be either an array or an object value. Default: \c false.
+       bool strictRoot_;
+};
+
+} // namespace Json
+
+#endif // CPPTL_JSON_FEATURES_H_INCLUDED
diff --git a/include/json/forwards.h b/include/json/forwards.h
new file mode 100644 (file)
index 0000000..4d46633
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef JSON_FORWARDS_H_INCLUDED
+# define JSON_FORWARDS_H_INCLUDED
+
+# include "config.h"
+
+namespace Json {
+
+// writer.h
+class FastWriter;
+class StyledWriter;
+
+// reader.h
+class Reader;
+
+// features.h
+class Features;
+
+// value.h
+typedef int Int;
+typedef unsigned int UInt;
+class StaticString;
+class Path;
+class PathArgument;
+class Value;
+class ValueIteratorBase;
+class ValueIterator;
+class ValueConstIterator;
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+class ValueAllocator;
+class ValueMapAllocator;
+class ValueInternalLink;
+class ValueInternalArray;
+class ValueInternalMap;
+#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
+}
+ // namespace Json
+
+#endif // JSON_FORWARDS_H_INCLUDED
diff --git a/include/json/json.h b/include/json/json.h
new file mode 100644 (file)
index 0000000..c71ed65
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef JSON_JSON_H_INCLUDED
+# define JSON_JSON_H_INCLUDED
+
+# include "autolink.h"
+# include "value.h"
+# include "reader.h"
+# include "writer.h"
+# include "features.h"
+
+#endif // JSON_JSON_H_INCLUDED
diff --git a/include/json/reader.h b/include/json/reader.h
new file mode 100644 (file)
index 0000000..6020c42
--- /dev/null
@@ -0,0 +1,177 @@
+#ifndef CPPTL_JSON_READER_H_INCLUDED
+# define CPPTL_JSON_READER_H_INCLUDED
+
+# include "features.h"
+# include "value.h"
+# include <deque>
+# include <stack>
+# include <string>
+# include <iostream>
+
+namespace Json {
+
+/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value.
+ *
+ */
+class JSON_API Reader {
+public:
+       typedef char Char;
+       typedef const Char *Location;
+
+       /** \brief Constructs a Reader allowing all features
+        * for parsing.
+        */
+       Reader();
+
+       /** \brief Constructs a Reader allowing the specified feature set
+        * for parsing.
+        */
+       Reader(const Features &features);
+
+       /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
+        * \param document UTF-8 encoded string containing the document to read.
+        * \param root [out] Contains the root value of the document if it was
+        *             successfully parsed.
+        * \param collectComments \c true to collect comment and allow writing them back during
+        *                        serialization, \c false to discard comments.
+        *                        This parameter is ignored if Features::allowComments_
+        *                        is \c false.
+        * \return \c true if the document was successfully parsed, \c false if an error occurred.
+        */
+       bool parse(const std::string &document, Value &root, bool collectComments =
+                       true);
+
+       /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
+        * \param document UTF-8 encoded string containing the document to read.
+        * \param root [out] Contains the root value of the document if it was
+        *             successfully parsed.
+        * \param collectComments \c true to collect comment and allow writing them back during
+        *                        serialization, \c false to discard comments.
+        *                        This parameter is ignored if Features::allowComments_
+        *                        is \c false.
+        * \return \c true if the document was successfully parsed, \c false if an error occurred.
+        */
+       bool parse(const char *beginDoc, const char *endDoc, Value &root,
+                       bool collectComments = true);
+
+       /// \brief Parse from input stream.
+       /// \see Json::operator>>(std::istream&, Json::Value&).
+       bool parse(std::istream &is, Value &root, bool collectComments = true);
+
+       /** \brief Returns a user friendly string that list errors in the parsed document.
+        * \return Formatted error message with the list of errors with their location in 
+        *         the parsed document. An empty string is returned if no error occurred
+        *         during parsing.
+        */
+       std::string getFormatedErrorMessages() const;
+
+private:
+       enum TokenType {
+               tokenEndOfStream = 0,
+               tokenObjectBegin,
+               tokenObjectEnd,
+               tokenArrayBegin,
+               tokenArrayEnd,
+               tokenString,
+               tokenNumber,
+               tokenTrue,
+               tokenFalse,
+               tokenNull,
+               tokenArraySeparator,
+               tokenMemberSeparator,
+               tokenComment,
+               tokenError
+       };
+
+       class Token {
+       public:
+               TokenType type_;
+               Location start_;
+               Location end_;
+       };
+
+       class ErrorInfo {
+       public:
+               Token token_;
+               std::string message_;
+               Location extra_;
+       };
+
+       typedef std::deque<ErrorInfo> Errors;
+
+       bool expectToken(TokenType type, Token &token, const char *message);
+       bool readToken(Token &token);
+       void skipSpaces();
+       bool match(Location pattern, int patternLength);
+       bool readComment();
+       bool readCStyleComment();
+       bool readCppStyleComment();
+       bool readString();
+       void readNumber();
+       bool readValue();
+       bool readObject(Token &token);
+       bool readArray(Token &token);
+       bool decodeNumber(Token &token);
+       bool decodeString(Token &token);
+       bool decodeString(Token &token, std::string &decoded);
+       bool decodeDouble(Token &token);
+       bool decodeUnicodeCodePoint(Token &token, Location &current, Location end,
+                       unsigned int &unicode);
+       bool decodeUnicodeEscapeSequence(Token &token, Location &current,
+                       Location end, unsigned int &unicode);
+       bool addError(const std::string &message, Token &token, Location extra = 0);
+       bool recoverFromError(TokenType skipUntilToken);
+       bool addErrorAndRecover(const std::string &message, Token &token,
+                       TokenType skipUntilToken);
+       void skipUntilSpace();
+       Value &currentValue();
+       Char getNextChar();
+       void getLocationLineAndColumn(Location location, int &line,
+                       int &column) const;
+       std::string getLocationLineAndColumn(Location location) const;
+       void addComment(Location begin, Location end, CommentPlacement placement);
+       void skipCommentTokens(Token &token);
+
+       typedef std::stack<Value *> Nodes;
+       Nodes nodes_;
+       Errors errors_;
+       std::string document_;
+       Location begin_;
+       Location end_;
+       Location current_;
+       Location lastValueEnd_;
+       Value *lastValue_;
+       std::string commentsBefore_;
+       Features features_;
+       bool collectComments_;
+};
+
+/** \brief Read from 'sin' into 'root'.
+
+ Always keep comments from the input JSON.
+
+ This can be used to read a file into a particular sub-object.
+ For example:
+ \code
+ Json::Value root;
+ cin >> root["dir"]["file"];
+ cout << root;
+ \endcode
+ Result:
+ \verbatim
+ {
+ "dir": {
+ "file": {
+ // The input stream JSON would be nested here.
+ }
+ }
+ }
+ \endverbatim
+ \throw std::exception on parse error.
+ \see Json::operator<<()
+ */
+std::istream& operator>>(std::istream&, Value&);
+
+} // namespace Json
+
+#endif // CPPTL_JSON_READER_H_INCLUDED
diff --git a/include/json/value.h b/include/json/value.h
new file mode 100644 (file)
index 0000000..736cce5
--- /dev/null
@@ -0,0 +1,1013 @@
+#ifndef CPPTL_JSON_H_INCLUDED
+# define CPPTL_JSON_H_INCLUDED
+
+# include "forwards.h"
+# include <string>
+# include <vector>
+
+# ifndef JSON_USE_CPPTL_SMALLMAP
+#  include <map>
+# else
+#  include <cpptl/smallmap.h>
+# endif
+# ifdef JSON_USE_CPPTL
+#  include <cpptl/forwards.h>
+# endif
+
+/** \brief JSON (JavaScript Object Notation).
+ */
+namespace Json {
+
+/** \brief Type of the value held by a Value object.
+ */
+enum ValueType {
+       nullValue = 0, ///< 'null' value
+       intValue,      ///< signed integer value
+       uintValue,     ///< unsigned integer value
+       realValue,     ///< double value
+       stringValue,   ///< UTF-8 string value
+       booleanValue,  ///< bool value
+       arrayValue,    ///< array value (ordered list)
+       objectValue    ///< object value (collection of name/value pairs).
+};
+
+enum CommentPlacement {
+       commentBefore = 0,        ///< a comment placed on the line before a value
+       commentAfterOnSameLine,   ///< a comment just after a value on the same line
+       commentAfter, ///< a comment on the line after a value (only make sense for root value)
+       numberOfCommentPlacement
+};
+
+//# ifdef JSON_USE_CPPTL
+//   typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;
+//   typedef CppTL::AnyEnumerator<const Value &> EnumValues;
+//# endif
+
+/** \brief Lightweight wrapper to tag static string.
+ *
+ * Value constructor and objectValue member assignement takes advantage of the
+ * StaticString and avoid the cost of string duplication when storing the
+ * string or the member name.
+ *
+ * Example of usage:
+ * \code
+ * Json::Value aValue( StaticString("some text") );
+ * Json::Value object;
+ * static const StaticString code("code");
+ * object[code] = 1234;
+ * \endcode
+ */
+class JSON_API StaticString {
+public:
+       explicit StaticString(const char *czstring) :
+                       str_(czstring) {
+       }
+
+       operator const char *() const {
+               return str_;
+       }
+
+       const char *c_str() const {
+               return str_;
+       }
+
+private:
+       const char *str_;
+};
+
+/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
+ *
+ * This class is a discriminated union wrapper that can represents a:
+ * - signed integer [range: Value::minInt - Value::maxInt]
+ * - unsigned integer (range: 0 - Value::maxUInt)
+ * - double
+ * - UTF-8 string
+ * - boolean
+ * - 'null'
+ * - an ordered list of Value
+ * - collection of name/value pairs (javascript object)
+ *
+ * The type of the held value is represented by a #ValueType and 
+ * can be obtained using type().
+ *
+ * values of an #objectValue or #arrayValue can be accessed using operator[]() methods. 
+ * Non const methods will automatically create the a #nullValue element 
+ * if it does not exist. 
+ * The sequence of an #arrayValue will be automatically resize and initialized 
+ * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
+ *
+ * The get() methods can be used to obtanis default value in the case the required element
+ * does not exist.
+ *
+ * It is possible to iterate over the list of a #objectValue values using 
+ * the getMemberNames() method.
+ */
+class JSON_API Value {
+       friend class ValueIteratorBase;
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+       friend class ValueInternalLink;
+       friend class ValueInternalMap;
+# endif
+public:
+       typedef std::vector<std::string> Members;
+       typedef ValueIterator iterator;
+       typedef ValueConstIterator const_iterator;
+       typedef Json::UInt UInt;
+       typedef Json::Int Int;
+       typedef UInt ArrayIndex;
+
+       static const Value null;
+       static const Int minInt;
+       static const Int maxInt;
+       static const UInt maxUInt;
+
+private:
+#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+# ifndef JSON_VALUE_USE_INTERNAL_MAP
+       class CZString {
+       public:
+               enum DuplicationPolicy {
+                       noDuplication = 0, duplicate, duplicateOnCopy
+               };
+               CZString(int index);
+               CZString(const char *cstr, DuplicationPolicy allocate);
+               CZString(const CZString &other);
+               ~CZString();
+               CZString &operator =(const CZString &other);
+               bool operator<(const CZString &other) const;
+               bool operator==(const CZString &other) const;
+               int index() const;
+               const char *c_str() const;
+               bool isStaticString() const;
+       private:
+               void swap(CZString &other);
+               const char *cstr_;
+               int index_;
+       };
+
+public:
+#  ifndef JSON_USE_CPPTL_SMALLMAP
+       typedef std::map<CZString, Value> ObjectValues;
+#  else
+       typedef CppTL::SmallMap<CZString, Value> ObjectValues;
+#  endif // ifndef JSON_USE_CPPTL_SMALLMAP
+# endif // ifndef JSON_VALUE_USE_INTERNAL_MAP
+#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+public:
+       /** \brief Create a default Value of the given type.
+
+        This is a very useful constructor.
+        To create an empty array, pass arrayValue.
+        To create an empty object, pass objectValue.
+        Another Value can then be set to this one by assignment.
+        This is useful since clear() and resize() will not alter types.
+
+        Examples:
+        \code
+        Json::Value null_value; // null
+        Json::Value arr_value(Json::arrayValue); // []
+        Json::Value obj_value(Json::objectValue); // {}
+        \endcode
+        */
+       Value(ValueType type = nullValue);
+       Value(Int value);
+       Value(UInt value);
+       Value(double value);
+       Value(const char *value);
+       Value(const char *beginValue, const char *endValue);
+       /** \brief Constructs a value from a static string.
+
+        * Like other value string constructor but do not duplicate the string for
+        * internal storage. The given string must remain alive after the call to this
+        * constructor.
+        * Example of usage:
+        * \code
+        * Json::Value aValue( StaticString("some text") );
+        * \endcode
+        */
+       Value(const StaticString &value);
+       Value(const std::string &value);
+# ifdef JSON_USE_CPPTL
+       Value( const CppTL::ConstString &value );
+# endif
+       Value(bool value);
+       Value(const Value &other);
+       ~Value();
+
+       Value &operator=(const Value &other);
+       /// Swap values.
+       /// \note Currently, comments are intentionally not swapped, for
+       /// both logic and efficiency.
+       void swap(Value &other);
+
+       ValueType type() const;
+
+       bool operator <(const Value &other) const;
+       bool operator <=(const Value &other) const;
+       bool operator >=(const Value &other) const;
+       bool operator >(const Value &other) const;
+
+       bool operator ==(const Value &other) const;
+       bool operator !=(const Value &other) const;
+
+       int compare(const Value &other);
+
+       const char *asCString() const;
+       std::string asString() const;
+# ifdef JSON_USE_CPPTL
+       CppTL::ConstString asConstString() const;
+# endif
+       Int asInt() const;
+       UInt asUInt() const;
+       double asDouble() const;
+       bool asBool() const;
+
+       bool isNull() const;
+       bool isBool() const;
+       bool isInt() const;
+       bool isUInt() const;
+       bool isIntegral() const;
+       bool isDouble() const;
+       bool isNumeric() const;
+       bool isString() const;
+       bool isArray() const;
+       bool isObject() const;
+
+       bool isConvertibleTo(ValueType other) const;
+
+       /// Number of values in array or object
+       UInt size() const;
+
+       /// \brief Return true if empty array, empty object, or null;
+       /// otherwise, false.
+       bool empty() const;
+
+       /// Return isNull()
+       bool operator!() const;
+
+       /// Remove all object members and array elements.
+       /// \pre type() is arrayValue, objectValue, or nullValue
+       /// \post type() is unchanged
+       void clear();
+
+       /// Resize the array to size elements. 
+       /// New elements are initialized to null.
+       /// May only be called on nullValue or arrayValue.
+       /// \pre type() is arrayValue or nullValue
+       /// \post type() is arrayValue
+       void resize(UInt size);
+
+       /// Access an array element (zero based index ).
+       /// If the array contains less than index element, then null value are inserted
+       /// in the array so that its size is index+1.
+       /// (You may need to say 'value[0u]' to get your compiler to distinguish
+       ///  this from the operator[] which takes a string.)
+       Value &operator[](UInt index);
+       /// Access an array element (zero based index )
+       /// (You may need to say 'value[0u]' to get your compiler to distinguish
+       ///  this from the operator[] which takes a string.)
+       const Value &operator[](UInt index) const;
+       /// If the array contains at least index+1 elements, returns the element value, 
+       /// otherwise returns defaultValue.
+       Value get(UInt index, const Value &defaultValue) const;
+       /// Return true if index < size().
+       bool isValidIndex(UInt index) const;
+       /// \brief Append value to array at the end.
+       ///
+       /// Equivalent to jsonvalue[jsonvalue.size()] = value;
+       Value &append(const Value &value);
+
+       /// Access an object value by name, create a null member if it does not exist.
+       Value &operator[](const char *key);
+       /// Access an object value by name, returns null if there is no member with that name.
+       const Value &operator[](const char *key) const;
+       /// Access an object value by name, create a null member if it does not exist.
+       Value &operator[](const std::string &key);
+       /// Access an object value by name, returns null if there is no member with that name.
+       const Value &operator[](const std::string &key) const;
+       /** \brief Access an object value by name, create a null member if it does not exist.
+
+        * If the object as no entry for that name, then the member name used to store
+        * the new entry is not duplicated.
+        * Example of use:
+        * \code
+        * Json::Value object;
+        * static const StaticString code("code");
+        * object[code] = 1234;
+        * \endcode
+        */
+       Value &operator[](const StaticString &key);
+# ifdef JSON_USE_CPPTL
+       /// Access an object value by name, create a null member if it does not exist.
+       Value &operator[]( const CppTL::ConstString &key );
+       /// Access an object value by name, returns null if there is no member with that name.
+       const Value &operator[]( const CppTL::ConstString &key ) const;
+# endif
+       /// Return the member named key if it exist, defaultValue otherwise.
+       Value get(const char *key, const Value &defaultValue) const;
+       /// Return the member named key if it exist, defaultValue otherwise.
+       Value get(const std::string &key, const Value &defaultValue) const;
+# ifdef JSON_USE_CPPTL
+       /// Return the member named key if it exist, defaultValue otherwise.
+       Value get( const CppTL::ConstString &key,
+                       const Value &defaultValue ) const;
+# endif
+       /// \brief Remove and return the named member.  
+       ///
+       /// Do nothing if it did not exist.
+       /// \return the removed Value, or null.
+       /// \pre type() is objectValue or nullValue
+       /// \post type() is unchanged
+       Value removeMember(const char* key);
+       /// Same as removeMember(const char*)
+       Value removeMember(const std::string &key);
+
+       /// Return true if the object has a member named key.
+       bool isMember(const char *key) const;
+       /// Return true if the object has a member named key.
+       bool isMember(const std::string &key) const;
+# ifdef JSON_USE_CPPTL
+       /// Return true if the object has a member named key.
+       bool isMember( const CppTL::ConstString &key ) const;
+# endif
+
+       /// \brief Return a list of the member names.
+       ///
+       /// If null, return an empty list.
+       /// \pre type() is objectValue or nullValue
+       /// \post if type() was nullValue, it remains nullValue
+       Members getMemberNames() const;
+
+//# ifdef JSON_USE_CPPTL
+//      EnumMemberNames enumMemberNames() const;
+//      EnumValues enumValues() const;
+//# endif
+
+       /// Comments must be //... or /* ... */
+       void setComment(const char *comment, CommentPlacement placement);
+       /// Comments must be //... or /* ... */
+       void setComment(const std::string &comment, CommentPlacement placement);
+       bool hasComment(CommentPlacement placement) const;
+       /// Include delimiters and embedded newlines.
+       std::string getComment(CommentPlacement placement) const;
+
+       std::string toStyledString() const;
+
+       const_iterator begin() const;
+       const_iterator end() const;
+
+       iterator begin();
+       iterator end();
+
+private:
+       Value &resolveReference(const char *key, bool isStatic);
+
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+       inline bool isItemAvailable() const
+       {
+               return itemIsUsed_ == 0;
+       }
+
+       inline void setItemUsed( bool isUsed = true )
+       {
+               itemIsUsed_ = isUsed ? 1 : 0;
+       }
+
+       inline bool isMemberNameStatic() const
+       {
+               return memberNameIsStatic_ == 0;
+       }
+
+       inline void setMemberNameIsStatic( bool isStatic )
+       {
+               memberNameIsStatic_ = isStatic ? 1 : 0;
+       }
+# endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP
+private:
+       struct CommentInfo {
+               CommentInfo();
+               ~CommentInfo();
+
+               void setComment(const char *text);
+
+               char *comment_;
+       };
+
+       //struct MemberNamesTransform
+       //{
+       //   typedef const char *result_type;
+       //   const char *operator()( const CZString &name ) const
+       //   {
+       //      return name.c_str();
+       //   }
+       //};
+
+       union ValueHolder {
+               Int int_;
+               UInt uint_;
+               double real_;
+               bool bool_;
+               char *string_;
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+               ValueInternalArray *array_;
+               ValueInternalMap *map_;
+#else
+               ObjectValues *map_;
+# endif
+       } value_;
+       ValueType type_ :8;
+       int allocated_ :1;     // Notes: if declared as bool, bitfield is useless.
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+       unsigned int itemIsUsed_ : 1;     // used by the ValueInternalMap container.
+       int memberNameIsStatic_ : 1;// used by the ValueInternalMap container.
+# endif
+       CommentInfo *comments_;
+};
+
+/** \brief Experimental and untested: represents an element of the "path" to access a node.
+ */
+class PathArgument {
+public:
+       friend class Path;
+
+       PathArgument();
+       PathArgument(UInt index);
+       PathArgument(const char *key);
+       PathArgument(const std::string &key);
+
+private:
+       enum Kind {
+               kindNone = 0, kindIndex, kindKey
+       };
+       std::string key_;
+       UInt index_;
+       Kind kind_;
+};
+
+/** \brief Experimental and untested: represents a "path" to access a node.
+ *
+ * Syntax:
+ * - "." => root node
+ * - ".[n]" => elements at index 'n' of root node (an array value)
+ * - ".name" => member named 'name' of root node (an object value)
+ * - ".name1.name2.name3"
+ * - ".[0][1][2].name1[3]"
+ * - ".%" => member name is provided as parameter
+ * - ".[%]" => index is provied as parameter
+ */
+class Path {
+public:
+       Path(const std::string &path, const PathArgument &a1 = PathArgument(),
+                       const PathArgument &a2 = PathArgument(), const PathArgument &a3 =
+                                       PathArgument(), const PathArgument &a4 = PathArgument(),
+                       const PathArgument &a5 = PathArgument());
+
+                       const Value &resolve(const Value &root) const;
+       Value resolve(const Value &root, const Value &defaultValue) const;
+       /// Creates the "path" to access the specified node and returns a reference on the node.
+       Value &make(Value &root) const;
+
+private:
+       typedef std::vector<const PathArgument *> InArgs;
+       typedef std::vector<PathArgument> Args;
+
+       void makePath(const std::string &path, const InArgs &in);
+       void addPathInArg(const std::string &path, const InArgs &in,
+                       InArgs::const_iterator &itInArg, PathArgument::Kind kind);
+       void invalidPath(const std::string &path, int location);
+
+       Args args_;
+};
+
+/** \brief Experimental do not use: Allocator to customize member name and string value memory management done by Value.
+ *
+ * - makeMemberName() and releaseMemberName() are called to respectively duplicate and
+ *   free an Json::objectValue member name.
+ * - duplicateStringValue() and releaseStringValue() are called similarly to
+ *   duplicate and free a Json::stringValue value.
+ */
+class ValueAllocator {
+public:
+       enum {
+               unknown = (unsigned) -1
+       };
+
+       virtual ~ValueAllocator();
+
+       virtual char *makeMemberName(const char *memberName) = 0;
+       virtual void releaseMemberName(char *memberName) = 0;
+       virtual char *duplicateStringValue(const char *value, unsigned int length =
+                       unknown) = 0;
+       virtual void releaseStringValue(char *value) = 0;
+};
+
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+/** \brief Allocator to customize Value internal map.
+ * Below is an example of a simple implementation (default implementation actually
+ * use memory pool for speed).
+ * \code
+ class DefaultValueMapAllocator : public ValueMapAllocator
+ {
+ public: // overridden from ValueMapAllocator
+ virtual ValueInternalMap *newMap()
+ {
+ return new ValueInternalMap();
+ }
+
+ virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
+ {
+ return new ValueInternalMap( other );
+ }
+
+ virtual void destructMap( ValueInternalMap *map )
+ {
+ delete map;
+ }
+
+ virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
+ {
+ return new ValueInternalLink[size];
+ }
+
+ virtual void releaseMapBuckets( ValueInternalLink *links )
+ {
+ delete [] links;
+ }
+
+ virtual ValueInternalLink *allocateMapLink()
+ {
+ return new ValueInternalLink();
+ }
+
+ virtual void releaseMapLink( ValueInternalLink *link )
+ {
+ delete link;
+ }
+ };
+ * \endcode
+ */
+class JSON_API ValueMapAllocator
+{
+public:
+       virtual ~ValueMapAllocator();
+       virtual ValueInternalMap *newMap() = 0;
+       virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0;
+       virtual void destructMap( ValueInternalMap *map ) = 0;
+       virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0;
+       virtual void releaseMapBuckets( ValueInternalLink *links ) = 0;
+       virtual ValueInternalLink *allocateMapLink() = 0;
+       virtual void releaseMapLink( ValueInternalLink *link ) = 0;
+};
+
+/** \brief ValueInternalMap hash-map bucket chain link (for internal use only).
+ * \internal previous_ & next_ allows for bidirectional traversal.
+ */
+class JSON_API ValueInternalLink
+{
+public:
+       enum {itemPerLink = 6}; // sizeof(ValueInternalLink) = 128 on 32 bits architecture.
+       enum InternalFlags {
+               flagAvailable = 0,
+               flagUsed = 1
+       };
+
+       ValueInternalLink();
+
+       ~ValueInternalLink();
+
+       Value items_[itemPerLink];
+       char *keys_[itemPerLink];
+       ValueInternalLink *previous_;
+       ValueInternalLink *next_;
+};
+
+/** \brief A linked page based hash-table implementation used internally by Value.
+ * \internal ValueInternalMap is a tradional bucket based hash-table, with a linked
+ * list in each bucket to handle collision. There is an addional twist in that
+ * each node of the collision linked list is a page containing a fixed amount of
+ * value. This provides a better compromise between memory usage and speed.
+ * 
+ * Each bucket is made up of a chained list of ValueInternalLink. The last
+ * link of a given bucket can be found in the 'previous_' field of the following bucket.
+ * The last link of the last bucket is stored in tailLink_ as it has no following bucket.
+ * Only the last link of a bucket may contains 'available' item. The last link always
+ * contains at least one element unless is it the bucket one very first link.
+ */
+class JSON_API ValueInternalMap
+{
+       friend class ValueIteratorBase;
+       friend class Value;
+public:
+       typedef unsigned int HashKey;
+       typedef unsigned int BucketIndex;
+
+# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+       struct IteratorState
+       {
+               IteratorState()
+               : map_(0)
+               , link_(0)
+               , itemIndex_(0)
+               , bucketIndex_(0)
+               {
+               }
+               ValueInternalMap *map_;
+               ValueInternalLink *link_;
+               BucketIndex itemIndex_;
+               BucketIndex bucketIndex_;
+       };
+# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+       ValueInternalMap();
+       ValueInternalMap( const ValueInternalMap &other );
+       ValueInternalMap &operator =( const ValueInternalMap &other );
+       ~ValueInternalMap();
+
+       void swap( ValueInternalMap &other );
+
+       BucketIndex size() const;
+
+       void clear();
+
+       bool reserveDelta( BucketIndex growth );
+
+       bool reserve( BucketIndex newItemCount );
+
+       const Value *find( const char *key ) const;
+
+       Value *find( const char *key );
+
+       Value &resolveReference( const char *key,
+                       bool isStatic );
+
+       void remove( const char *key );
+
+       void doActualRemove( ValueInternalLink *link,
+                       BucketIndex index,
+                       BucketIndex bucketIndex );
+
+       ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex );
+
+       Value &setNewItem( const char *key,
+                       bool isStatic,
+                       ValueInternalLink *link,
+                       BucketIndex index );
+
+       Value &unsafeAdd( const char *key,
+                       bool isStatic,
+                       HashKey hashedKey );
+
+       HashKey hash( const char *key ) const;
+
+       int compare( const ValueInternalMap &other ) const;
+
+private:
+       void makeBeginIterator( IteratorState &it ) const;
+       void makeEndIterator( IteratorState &it ) const;
+       static bool equals( const IteratorState &x, const IteratorState &other );
+       static void increment( IteratorState &iterator );
+       static void incrementBucket( IteratorState &iterator );
+       static void decrement( IteratorState &iterator );
+       static const char *key( const IteratorState &iterator );
+       static const char *key( const IteratorState &iterator, bool &isStatic );
+       static Value &value( const IteratorState &iterator );
+       static int distance( const IteratorState &x, const IteratorState &y );
+
+private:
+       ValueInternalLink *buckets_;
+       ValueInternalLink *tailLink_;
+       BucketIndex bucketsSize_;
+       BucketIndex itemCount_;
+};
+
+/** \brief A simplified deque implementation used internally by Value.
+ * \internal
+ * It is based on a list of fixed "page", each page contains a fixed number of items.
+ * Instead of using a linked-list, a array of pointer is used for fast item look-up.
+ * Look-up for an element is as follow:
+ * - compute page index: pageIndex = itemIndex / itemsPerPage
+ * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage]
+ *
+ * Insertion is amortized constant time (only the array containing the index of pointers
+ * need to be reallocated when items are appended).
+ */
+class JSON_API ValueInternalArray
+{
+       friend class Value;
+       friend class ValueIteratorBase;
+public:
+       enum {itemsPerPage = 8}; // should be a power of 2 for fast divide and modulo.
+       typedef Value::ArrayIndex ArrayIndex;
+       typedef unsigned int PageIndex;
+
+# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+       struct IteratorState // Must be a POD
+       {
+               IteratorState()
+               : array_(0)
+               , currentPageIndex_(0)
+               , currentItemIndex_(0)
+               {
+               }
+               ValueInternalArray *array_;
+               Value **currentPageIndex_;
+               unsigned int currentItemIndex_;
+       };
+# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+       ValueInternalArray();
+       ValueInternalArray( const ValueInternalArray &other );
+       ValueInternalArray &operator =( const ValueInternalArray &other );
+       ~ValueInternalArray();
+       void swap( ValueInternalArray &other );
+
+       void clear();
+       void resize( ArrayIndex newSize );
+
+       Value &resolveReference( ArrayIndex index );
+
+       Value *find( ArrayIndex index ) const;
+
+       ArrayIndex size() const;
+
+       int compare( const ValueInternalArray &other ) const;
+
+private:
+       static bool equals( const IteratorState &x, const IteratorState &other );
+       static void increment( IteratorState &iterator );
+       static void decrement( IteratorState &iterator );
+       static Value &dereference( const IteratorState &iterator );
+       static Value &unsafeDereference( const IteratorState &iterator );
+       static int distance( const IteratorState &x, const IteratorState &y );
+       static ArrayIndex indexOf( const IteratorState &iterator );
+       void makeBeginIterator( IteratorState &it ) const;
+       void makeEndIterator( IteratorState &it ) const;
+       void makeIterator( IteratorState &it, ArrayIndex index ) const;
+
+       void makeIndexValid( ArrayIndex index );
+
+       Value **pages_;
+       ArrayIndex size_;
+       PageIndex pageCount_;
+};
+
+/** \brief Experimental: do not use. Allocator to customize Value internal array.
+ * Below is an example of a simple implementation (actual implementation use
+ * memory pool).
+ \code
+ class DefaultValueArrayAllocator : public ValueArrayAllocator
+ {
+ public: // overridden from ValueArrayAllocator
+ virtual ~DefaultValueArrayAllocator()
+ {
+ }
+
+ virtual ValueInternalArray *newArray()
+ {
+ return new ValueInternalArray();
+ }
+
+ virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
+ {
+ return new ValueInternalArray( other );
+ }
+
+ virtual void destruct( ValueInternalArray *array )
+ {
+ delete array;
+ }
+
+ virtual void reallocateArrayPageIndex( Value **&indexes, 
+ ValueInternalArray::PageIndex &indexCount,
+ ValueInternalArray::PageIndex minNewIndexCount )
+ {
+ ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
+ if ( minNewIndexCount > newIndexCount )
+ newIndexCount = minNewIndexCount;
+ void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
+ if ( !newIndexes )
+ throw std::bad_alloc();
+ indexCount = newIndexCount;
+ indexes = static_cast<Value **>( newIndexes );
+ }
+ virtual void releaseArrayPageIndex( Value **indexes, 
+ ValueInternalArray::PageIndex indexCount )
+ {
+ if ( indexes )
+ free( indexes );
+ }
+
+ virtual Value *allocateArrayPage()
+ {
+ return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) );
+ }
+
+ virtual void releaseArrayPage( Value *value )
+ {
+ if ( value )
+ free( value );
+ }
+ };
+ \endcode
+ */
+class JSON_API ValueArrayAllocator
+{
+public:
+       virtual ~ValueArrayAllocator();
+       virtual ValueInternalArray *newArray() = 0;
+       virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0;
+       virtual void destructArray( ValueInternalArray *array ) = 0;
+       /** \brief Reallocate array page index.
+        * Reallocates an array of pointer on each page.
+        * \param indexes [input] pointer on the current index. May be \c NULL.
+        *                [output] pointer on the new index of at least 
+        *                         \a minNewIndexCount pages. 
+        * \param indexCount [input] current number of pages in the index.
+        *                   [output] number of page the reallocated index can handle.
+        *                            \b MUST be >= \a minNewIndexCount.
+        * \param minNewIndexCount Minimum number of page the new index must be able to
+        *                         handle.
+        */
+       virtual void reallocateArrayPageIndex( Value **&indexes,
+                       ValueInternalArray::PageIndex &indexCount,
+                       ValueInternalArray::PageIndex minNewIndexCount ) = 0;
+       virtual void releaseArrayPageIndex( Value **indexes,
+                       ValueInternalArray::PageIndex indexCount ) = 0;
+       virtual Value *allocateArrayPage() = 0;
+       virtual void releaseArrayPage( Value *value ) = 0;
+};
+#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
+
+/** \brief base class for Value iterators.
+ *
+ */
+class ValueIteratorBase {
+public:
+       typedef unsigned int size_t;
+       typedef int difference_type;
+       typedef ValueIteratorBase SelfType;
+
+       ValueIteratorBase();
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+       explicit ValueIteratorBase(const Value::ObjectValues::iterator &current);
+#else
+       ValueIteratorBase( const ValueInternalArray::IteratorState &state );
+       ValueIteratorBase( const ValueInternalMap::IteratorState &state );
+#endif
+
+       bool operator ==(const SelfType &other) const {
+               return isEqual(other);
+       }
+
+       bool operator !=(const SelfType &other) const {
+               return !isEqual(other);
+       }
+
+       difference_type operator -(const SelfType &other) const {
+               return computeDistance(other);
+       }
+
+       /// Return either the index or the member name of the referenced value as a Value.
+       Value key() const;
+
+       /// Return the index of the referenced Value. -1 if it is not an arrayValue.
+       UInt index() const;
+
+       /// Return the member name of the referenced Value. "" if it is not an objectValue.
+       const char *memberName() const;
+
+protected:
+       Value &deref() const;
+
+       void increment();
+
+       void decrement();
+
+       difference_type computeDistance(const SelfType &other) const;
+
+       bool isEqual(const SelfType &other) const;
+
+       void copy(const SelfType &other);
+
+private:
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+       Value::ObjectValues::iterator current_;
+       // Indicates that iterator is for a null value.
+       bool isNull_;
+#else
+       union
+       {
+               ValueInternalArray::IteratorState array_;
+               ValueInternalMap::IteratorState map_;
+       }iterator_;
+       bool isArray_;
+#endif
+};
+
+/** \brief const iterator for object and array value.
+ *
+ */
+class ValueConstIterator: public ValueIteratorBase {
+       friend class Value;
+public:
+       typedef unsigned int size_t;
+       typedef int difference_type;
+       typedef const Value &reference;
+       typedef const Value *pointer;
+       typedef ValueConstIterator SelfType;
+
+       ValueConstIterator();
+private:
+       /*! \internal Use by Value to create an iterator.
+        */
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+       explicit ValueConstIterator(const Value::ObjectValues::iterator &current);
+#else
+       ValueConstIterator( const ValueInternalArray::IteratorState &state );
+       ValueConstIterator( const ValueInternalMap::IteratorState &state );
+#endif
+public:
+       SelfType &operator =(const ValueIteratorBase &other);
+
+       SelfType operator++(int) {
+               SelfType temp(*this);
+               ++*this;
+               return temp;
+       }
+
+       SelfType operator--(int) {
+               SelfType temp(*this);
+               --*this;
+               return temp;
+       }
+
+       SelfType &operator--() {
+               decrement();
+               return *this;
+       }
+
+       SelfType &operator++() {
+               increment();
+               return *this;
+       }
+
+       reference operator *() const {
+               return deref();
+       }
+};
+
+/** \brief Iterator for object and array value.
+ */
+class ValueIterator: public ValueIteratorBase {
+       friend class Value;
+public:
+       typedef unsigned int size_t;
+       typedef int difference_type;
+       typedef Value &reference;
+       typedef Value *pointer;
+       typedef ValueIterator SelfType;
+
+       ValueIterator();
+       ValueIterator(const ValueConstIterator &other);
+       ValueIterator(const ValueIterator &other);
+private:
+       /*! \internal Use by Value to create an iterator.
+        */
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+       explicit ValueIterator(const Value::ObjectValues::iterator &current);
+#else
+       ValueIterator( const ValueInternalArray::IteratorState &state );
+       ValueIterator( const ValueInternalMap::IteratorState &state );
+#endif
+public:
+
+       SelfType &operator =(const SelfType &other);
+
+       SelfType operator++(int) {
+               SelfType temp(*this);
+               ++*this;
+               return temp;
+       }
+
+       SelfType operator--(int) {
+               SelfType temp(*this);
+               --*this;
+               return temp;
+       }
+
+       SelfType &operator--() {
+               decrement();
+               return *this;
+       }
+
+       SelfType &operator++() {
+               increment();
+               return *this;
+       }
+
+       reference operator *() const {
+               return deref();
+       }
+};
+
+} // namespace Json
+
+#endif // CPPTL_JSON_H_INCLUDED
diff --git a/include/json/writer.h b/include/json/writer.h
new file mode 100644 (file)
index 0000000..38f18cb
--- /dev/null
@@ -0,0 +1,173 @@
+#ifndef JSON_WRITER_H_INCLUDED
+# define JSON_WRITER_H_INCLUDED
+
+# include "value.h"
+# include <vector>
+# include <string>
+# include <iostream>
+
+namespace Json {
+
+class Value;
+
+/** \brief Abstract class for writers.
+ */
+class JSON_API Writer {
+public:
+       virtual ~Writer();
+
+       virtual std::string write(const Value &root) = 0;
+};
+
+/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format without formatting (not human friendly).
+ *
+ * The JSON document is written in a single line. It is not intended for 'human' consumption,
+ * but may be usefull to support feature such as RPC where bandwith is limited.
+ * \sa Reader, Value
+ */
+class JSON_API FastWriter: public Writer {
+public:
+       FastWriter();
+       virtual ~FastWriter() {
+       }
+
+       void enableYAMLCompatibility();
+
+public:
+       // overridden from Writer
+       virtual std::string write(const Value &root);
+
+private:
+       void writeValue(const Value &value);
+
+       std::string document_;
+       bool yamlCompatiblityEnabled_;
+};
+
+/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way.
+ *
+ * The rules for line break and indent are as follow:
+ * - Object value:
+ *     - if empty then print {} without indent and line break
+ *     - if not empty the print '{', line break & indent, print one value per line
+ *       and then unindent and line break and print '}'.
+ * - Array value:
+ *     - if empty then print [] without indent and line break
+ *     - if the array contains no object value, empty array or some other value types,
+ *       and all the values fit on one lines, then print the array on a single line.
+ *     - otherwise, it the values do not fit on one line, or the array contains
+ *       object or non empty array, then print one value per line.
+ *
+ * If the Value have comments then they are outputed according to their #CommentPlacement.
+ *
+ * \sa Reader, Value, Value::setComment()
+ */
+class JSON_API StyledWriter: public Writer {
+public:
+       StyledWriter();
+       virtual ~StyledWriter() {
+       }
+
+public:
+       // overridden from Writer
+       /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
+        * \param root Value to serialize.
+        * \return String containing the JSON document that represents the root value.
+        */
+       virtual std::string write(const Value &root);
+
+private:
+       void writeValue(const Value &value);
+       void writeArrayValue(const Value &value);
+       bool isMultineArray(const Value &value);
+       void pushValue(const std::string &value);
+       void writeIndent();
+       void writeWithIndent(const std::string &value);
+       void indent();
+       void unindent();
+       void writeCommentBeforeValue(const Value &root);
+       void writeCommentAfterValueOnSameLine(const Value &root);
+       bool hasCommentForValue(const Value &value);
+       static std::string normalizeEOL(const std::string &text);
+
+       typedef std::vector<std::string> ChildValues;
+
+       ChildValues childValues_;
+       std::string document_;
+       std::string indentString_;
+       int rightMargin_;
+       int indentSize_;
+       bool addChildValues_;
+};
+
+/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way,
+ to a stream rather than to a string.
+ *
+ * The rules for line break and indent are as follow:
+ * - Object value:
+ *     - if empty then print {} without indent and line break
+ *     - if not empty the print '{', line break & indent, print one value per line
+ *       and then unindent and line break and print '}'.
+ * - Array value:
+ *     - if empty then print [] without indent and line break
+ *     - if the array contains no object value, empty array or some other value types,
+ *       and all the values fit on one lines, then print the array on a single line.
+ *     - otherwise, it the values do not fit on one line, or the array contains
+ *       object or non empty array, then print one value per line.
+ *
+ * If the Value have comments then they are outputed according to their #CommentPlacement.
+ *
+ * \param indentation Each level will be indented by this amount extra.
+ * \sa Reader, Value, Value::setComment()
+ */
+class JSON_API StyledStreamWriter {
+public:
+       StyledStreamWriter(std::string indentation = "\t");
+       ~StyledStreamWriter() {
+       }
+
+public:
+       /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
+        * \param out Stream to write to. (Can be ostringstream, e.g.)
+        * \param root Value to serialize.
+        * \note There is no point in deriving from Writer, since write() should not return a value.
+        */
+       void write(std::ostream &out, const Value &root);
+
+private:
+       void writeValue(const Value &value);
+       void writeArrayValue(const Value &value);
+       bool isMultineArray(const Value &value);
+       void pushValue(const std::string &value);
+       void writeIndent();
+       void writeWithIndent(const std::string &value);
+       void indent();
+       void unindent();
+       void writeCommentBeforeValue(const Value &root);
+       void writeCommentAfterValueOnSameLine(const Value &root);
+       bool hasCommentForValue(const Value &value);
+       static std::string normalizeEOL(const std::string &text);
+
+       typedef std::vector<std::string> ChildValues;
+
+       ChildValues childValues_;
+       std::ostream* document_;
+       std::string indentString_;
+       int rightMargin_;
+       std::string indentation_;
+       bool addChildValues_;
+};
+
+std::string JSON_API valueToString(Int value);
+std::string JSON_API valueToString(UInt value);
+std::string JSON_API valueToString(double value);
+std::string JSON_API valueToString(bool value);
+std::string JSON_API valueToQuotedString(const char *value);
+
+/// \brief Output using the StyledStreamWriter.
+/// \see Json::operator>>()
+std::ostream& operator<<(std::ostream&, const Value &root);
+
+} // namespace Json
+
+#endif // JSON_WRITER_H_INCLUDED
diff --git a/include/testcase.h b/include/testcase.h
new file mode 100644 (file)
index 0000000..a9b79fd
--- /dev/null
@@ -0,0 +1,38 @@
+#include <stdio.h>
+#include <string.h>
+
+#include <signal.h>
+#include <sys/time.h>
+
+#include <string>
+using namespace std;
+
+#include <json/json.h>
+
+class TestCase {
+public:
+       TestCase();
+       virtual ~TestCase();
+
+public:
+       string result; // "pass" or "fail", "block", "N/A"
+       string start_at;
+       string end_at;
+       string std_out;
+       bool is_executed;
+
+       // below m_case are sent from Com-module for each case.
+       Json::Value m_case;
+       string purpose;
+       string case_id;
+       int timeout_value;
+
+       char m_str_time[32]; // to store the time string
+public:
+       void init(const Json::Value value); // the case_node should be a string in json format
+       Json::Value to_json();
+       Json::Value result_to_json();
+       void set_result(string test_result, string test_msg);
+       void set_start_at();
+       void getCurrentTime();
+};
diff --git a/makefile b/makefile
new file mode 100644 (file)
index 0000000..08d5a3c
--- /dev/null
+++ b/makefile
@@ -0,0 +1,75 @@
+TARGET = httpserver
+UT_TARGET = ut
+OBJ_PATH = objs
+PREFIX_BIN =
+
+CC = g++
+INCLUDES = -I include
+LIBS = 
+CFLAGS =-Wall -Werror
+LINKFLAGS = -lpthread
+
+JSON_SRCDIR = src/json
+SERVER_SRCDIR = src
+MAIN_SRCDIR = src/main
+UT_SRCDIR = src/ut
+
+JSON_SOURCES = $(foreach d,$(JSON_SRCDIR),$(wildcard $(d)/*.cpp) )
+JSON_OBJS = $(patsubst %.cpp, $(OBJ_PATH)/%.o, $(JSON_SOURCES))
+
+SERVER_SOURCES = $(foreach d,$(SERVER_SRCDIR),$(wildcard $(d)/*.cpp) )
+SERVER_OBJS = $(patsubst %.cpp, $(OBJ_PATH)/%.o, $(SERVER_SOURCES))
+
+MAIN_SOURCES = $(foreach d,$(MAIN_SRCDIR),$(wildcard $(d)/*.cpp) )
+MAIN_OBJS = $(patsubst %.cpp, $(OBJ_PATH)/%.o, $(MAIN_SOURCES))
+
+UT_SOURCES = $(foreach d,$(UT_SRCDIR),$(wildcard $(d)/*.cpp) )
+UT_OBJS = $(patsubst %.cpp, $(OBJ_PATH)/%.o, $(UT_SOURCES))
+
+default:init compile
+ut:init ut_compile
+ut: CC += -DDEBUG -g
+debug: CC += -DDEBUG -g
+debug: default
+
+$(C_OBJS):$(OBJ_PATH)/%.o:%.c
+       $(CC) -c $(CFLAGS) $(INCLUDES) $< -o $@
+
+$(JSON_OBJS):$(OBJ_PATH)/%.o:%.cpp
+       $(CC) -c $(CFLAGS) $(INCLUDES) $< -o $@
+
+$(SERVER_OBJS):$(OBJ_PATH)/%.o:%.cpp
+       $(CC) -c $(CFLAGS) $(INCLUDES) $< -o $@
+
+$(MAIN_OBJS):$(OBJ_PATH)/%.o:%.cpp
+       $(CC) -c $(CFLAGS) $(INCLUDES) $< -o $@
+
+$(UT_OBJS):$(OBJ_PATH)/%.o:%.cpp
+       $(CC) -c $(CFLAGS) $(INCLUDES) $< -o $@
+
+init:
+       $(foreach d,$(JSON_SRCDIR), mkdir -p $(OBJ_PATH)/$(d);)
+       $(foreach d,$(SERVER_SRCDIR), mkdir -p $(OBJ_PATH)/$(d);)
+       $(foreach d,$(MAIN_SRCDIR), mkdir -p $(OBJ_PATH)/$(d);)
+       $(foreach d,$(UT_SRCDIR), mkdir -p $(OBJ_PATH)/$(d);)
+
+ut_compile:$(JSON_OBJS) $(SERVER_OBJS) $(UT_OBJS)
+       $(CC)  $^ -o $(UT_TARGET)  $(LINKFLAGS) $(LIBS)
+
+compile:$(JSON_OBJS) $(SERVER_OBJS) $(MAIN_OBJS)
+       $(CC)  $^ -o $(TARGET)  $(LINKFLAGS) $(LIBS)
+
+clean:
+       rm -rf $(OBJ_PATH)
+       rm -f $(TARGET)
+       rm -f $(UT_TARGET)
+
+install: $(TARGET)
+       #cp $(TARGET) $(PREFIX_BIN)
+       install -d $(DESTDIR)/usr/bin/
+       install -m 755 $(TARGET) $(DESTDIR)/usr/bin/
+       
+uninstall:
+       rm -f $(PREFIX_BIN)/$(TARGET)
+
+rebuild: clean compile
diff --git a/packaging/testkit-stub.debug.spec b/packaging/testkit-stub.debug.spec
new file mode 100644 (file)
index 0000000..fa49a6f
--- /dev/null
@@ -0,0 +1,57 @@
+
+Name:       testkit-stub
+Summary:    test
+Version:    1.0
+Release:    1
+Group:      Development/Debug
+License:    GPL v2 only
+URL:        http://www.moblin.org/
+Source0:    %{name}-%{version}.tar.gz
+BuildRoot:  %{_tmppath}/%{name}-%{version}-build
+
+%description
+test
+
+
+%prep
+%setup -q -n %{name}-%{version}
+# >> setup
+# << setup
+
+%build
+# >> build pre
+# << build pre
+
+
+# Call make instruction with smp support
+make debug %{?jobs:-j%jobs}
+
+# >> build post
+# << build post
+%install
+rm -rf %{buildroot}
+# >> install pre
+# << install pre
+%make_install
+
+# >> install post
+# << install post
+
+%clean
+rm -rf %{buildroot}
+
+
+
+
+
+
+%files
+%defattr(-,root,root,-)
+# >> files
+%{_bindir}/httpserver
+# << files
+
+
+%changelog
+* Tue Mar  21 2013 Li Min <min.a.li@intel.com> 0.10
+- create for SLP build
diff --git a/packaging/testkit-stub.spec b/packaging/testkit-stub.spec
new file mode 100644 (file)
index 0000000..6569f72
--- /dev/null
@@ -0,0 +1,57 @@
+
+Name:       testkit-stub
+Summary:    test
+Version:    1.0
+Release:    1
+Group:      Development/Debug
+License:    GPL v2 only
+URL:        http://www.moblin.org/
+Source0:    %{name}-%{version}.tar.gz
+BuildRoot:  %{_tmppath}/%{name}-%{version}-build
+
+%description
+test
+
+
+%prep
+%setup -q -n %{name}-%{version}
+# >> setup
+# << setup
+
+%build
+# >> build pre
+# << build pre
+
+
+# Call make instruction with smp support
+make %{?jobs:-j%jobs}
+
+# >> build post
+# << build post
+%install
+rm -rf %{buildroot}
+# >> install pre
+# << install pre
+%make_install
+
+# >> install post
+# << install post
+
+%clean
+rm -rf %{buildroot}
+
+
+
+
+
+
+%files
+%defattr(-,root,root,-)
+# >> files
+%{_bindir}/httpserver
+# << files
+
+
+%changelog
+* Tue Mar  21 2013 Li Min <min.a.li@intel.com> 0.10
+- create for SLP build
diff --git a/src/comfun.cpp b/src/comfun.cpp
new file mode 100644 (file)
index 0000000..8676629
--- /dev/null
@@ -0,0 +1,78 @@
+#include <stdio.h>
+#include "comfun.h"
+
+ComFun::ComFun() {
+
+}
+ComFun::~ComFun() {
+
+}
+
+char ComFun::CharToInt(char ch) {
+       if (ch >= '0' && ch <= '9')
+               return (char) (ch - '0');
+       if (ch >= 'a' && ch <= 'f')
+               return (char) (ch - 'a' + 10);
+       if (ch >= 'A' && ch <= 'F')
+               return (char) (ch - 'A' + 10);
+       return -1;
+}
+
+char ComFun::StrToBin(char *str) {
+       char tempWord[2];
+       char chn;
+       tempWord[0] = CharToInt(str[0]); //make the B to 11 -- 00001011
+       tempWord[1] = CharToInt(str[1]); //make the 0 to 0 -- 00000000
+       chn = (tempWord[0] << 4) | tempWord[1]; //to change the BO to 10110000
+       return chn;
+}
+//url decode
+char* ComFun::UrlDecode(const char *str) {
+       char tmp[2];
+       int i = 0, len = strlen(str);
+       char *output = new char[len + 1];
+       memset(output, 0, len + 1);
+       int j = 0;
+       while (i < len) {
+               if (*(str + i) == '%') {
+                       tmp[0] = *(str + i + 1);
+                       tmp[1] = *(str + i + 2);
+                       *(output + j) = StrToBin(tmp);
+                       i = i + 3;
+                       j++;
+               } else if (*(str + i) == '+') {
+                       *(output + j) = ' ';
+                       i++;
+                       j++;
+               } else {
+                       *(output + j) = *(str + i);
+                       i++;
+                       j++;
+               }
+       }
+       return output;
+}
+
+//split function for string
+std::vector<std::string> ComFun::split(std::string str, std::string pattern) {
+       std::string::size_type pos;
+       std::vector < std::string > result;
+       str += pattern; //extend string so that operate easyly
+       unsigned int size = str.size();
+       int count = 0;
+       for (unsigned int i = 0; i < size; i++) {
+               if ((pattern == "=")&&(count == 1)){                    
+                       std::string s = str.substr(i, size-1-i);                        
+                       result.push_back(s);
+                       break;
+               }
+               pos = str.find(pattern, i);
+               if (pos < size) {
+                       std::string s = str.substr(i, pos - i);
+                       result.push_back(s);
+                       i = pos + pattern.size() - 1;
+               }
+               count++;
+       }
+       return result;
+}
\ No newline at end of file
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
new file mode 100644 (file)
index 0000000..b9ff5a3
--- /dev/null
@@ -0,0 +1,879 @@
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sstream>
+
+#include <json/json.h>
+#include "comfun.h"
+#include "httpserver.h"
+
+// if use 8080 for SERVER_PORT, it will not work with chrome
+#define SERVER_PORT 8000
+#define MAX_BUF 102400
+
+#define GET   0
+#define HEAD  2
+#define POST  3
+#define BAD_REQUEST -1
+
+#if defined(DEBUG) | defined(_DEBUG)
+    #ifndef DBG_ONLY
+      #define DBG_ONLY(x) do { x } while (0)         
+    #endif
+#else
+    #ifndef DBG_ONLY
+      #define DBG_ONLY(x) 
+    #endif
+#endif
+
+HttpServer::HttpServer() {
+       m_test_cases = NULL;
+       m_exeType = "auto"; // set default to auto
+       m_totalBlocks = 0;
+       m_current_block_index = 1;
+       m_totalcaseCount = 0;
+       m_block_case_index = 0;
+       m_block_case_count = 0;
+       m_total_case_index = 0;
+       m_last_auto_result = "N/A";
+       m_running_session = "";
+       m_server_checked = false;
+       g_show_log = false;
+       g_port = "";
+       g_hide_status = "";
+       g_test_suite = "";
+       g_exe_sequence = "";
+       g_run_wiget = false;
+       g_enable_memory_collection = "";
+       m_block_finished = false;
+       m_set_finished = false;
+       m_timeout_count = 0;
+       m_failto_launch = 0;
+       m_killing_widget = false;
+       m_rerun = false;
+
+       memset(&sa, 0, sizeof(sa));
+       sa.sa_handler = timer_handler;
+       sigaction(SIGALRM, &sa, NULL);
+}
+
+HttpServer::~HttpServer() {
+       if (m_test_cases) {
+               delete[] m_test_cases;
+               m_test_cases = NULL;
+       }
+       DBG_ONLY(outputFile.close(););
+}
+
+// generate response code. send response
+void HttpServer::sendresponse(int s, int code, struct HttpRequest *prequest,
+               string content) {
+       string buffer;
+       stringstream len_stream;
+       len_stream << content.length();
+       prequest->responsecode = code;
+       // generate response head
+       switch (code) {
+       case 200: {
+               buffer =
+                               "HTTP/1.1 200 OK\r\nServer: testkit-stub/1.0\r\nContent-Type: "
+                                               + prequest->prefix
+                                               + "\r\nAccept-Ranges: bytes\r\nContent-Length: "
+                                               + len_stream.str()
+                                               + "\r\nConnection: close\r\nAccess-Control-Allow-Origin: *\r\n\r\n"
+                                               + content;
+               break;
+       }
+       default:
+               break;
+       }
+
+       if (g_show_log) cout << buffer << endl;
+       // send out the http response
+       send(s, buffer.c_str(), buffer.length(), 0);
+}
+
+// parse the http request
+int HttpServer::getrequest(string requestbuf, struct HttpRequest *prequest) {
+       std::vector < std::string > splitstr = ComFun::split(requestbuf, " ");
+       if (splitstr.size() >= 2) {
+               prequest->method = splitstr[0];
+               prequest->path = splitstr[1];
+       }
+
+       if (prequest->path.find('?') == string::npos) {
+               //get the com module send data
+               int content_index = requestbuf.find("\r\n\r\n", 0);
+               if (content_index > -1) {
+                       prequest->content = requestbuf.substr(
+                                       content_index + strlen("\r\n\r\n"));
+               }
+       } else {
+               int session_index = prequest->path.find("?");
+               prequest->content = prequest->path.substr(session_index + 1);
+       }
+       if (prequest->method == "GET") {
+               return GET;
+       } else if (prequest->method == "POST") {
+               return POST;
+       }
+       return -1;
+}
+
+// parse the test case data sent by com-module with init_test cmd
+void HttpServer::parse_json_str(string case_node) {
+       Json::Reader reader;
+       Json::Value value;
+
+       bool parsed = reader.parse(case_node, value);
+       if (!parsed) // try to parse as a file if parse fail
+       { // "test.json" is for verify
+               cout << case_node << endl;
+               std::ifstream test(case_node.c_str(), std::ifstream::binary);
+               parsed = reader.parse(test, value, false);
+       }
+
+       if (parsed) {
+               m_totalBlocks = atoi(value["totalBlk"].asString().c_str());
+               m_current_block_index = atoi(value["currentBlk"].asString().c_str());
+               m_totalcaseCount = atoi(value["casecount"].asString().c_str());
+               m_exeType = value["exetype"].asString();
+
+               const Json::Value arrayObj = value["cases"];
+               m_block_case_count = arrayObj.size();
+
+               if (m_test_cases) {
+                       delete[] m_test_cases;
+                       m_test_cases = NULL;
+               }
+               m_test_cases = new TestCase[m_block_case_count];
+
+               for (int i = 0; i < m_block_case_count; i++) {
+                       m_test_cases[i].init(arrayObj[i]);
+               }
+       }
+}
+
+void HttpServer::cancel_time_check() {
+       timer.it_value.tv_sec = 0;
+       timer.it_value.tv_usec = 0;
+       timer.it_interval.tv_sec = 0;
+       timer.it_interval.tv_usec = 0;
+       setitimer(ITIMER_REAL, &timer, NULL); // set timer with value 0 will stop the timer
+       // refer to http://linux.die.net/man/2/setitimer, each process only have 1 timer of the same type.
+}
+
+// set timeout value to 90 seconds for each case
+void HttpServer::set_timer(int timeout_value) {
+       timer.it_value.tv_sec = timeout_value;
+       timer.it_value.tv_usec = 0;
+       timer.it_interval.tv_sec = 0;
+       timer.it_interval.tv_usec = 0;
+       int ret = setitimer(ITIMER_REAL, &timer, NULL);
+       if (ret < 0)
+               perror("error: set timer!!!");
+}
+
+
+/** send out response according to different http request. 
+a typical workflow of auto case would be
+/check_server_status                                           (by com-module)
+/init_test                                                                     (by com-module)
+/check_server                                                          (by widget)
+/init_session_id?session_id=2033                       (by widget)
+/auto_test_task?session_id=2033                                (by widget)
+/check_execution_progress?session_id=2033      (by widget)
+/ask_next_step?session_id=2033                         (by widget)
+/commit_result                                                                 (by widget)
+/auto_test_task?session_id=2033                                (by widget)
+/manual_cases                                                          (by widget)
+/check_server_status                                           (by com-module)
+/get_test_result                                                       (by com-module)
+/shut_down_server                                                      (by com-module)
+
+
+a typical workflow of manual case would be
+/check_server_status                                           (by com-module)
+/init_test                                                                     (by com-module)
+/check_server                                                          (by widget)
+/init_session_id?session_id=2033                       (by widget)
+/auto_test_task?session_id=2033                                (by widget)
+/manual_cases                                                          (by widget)
+/check_server_status                                           (by com-module)
+/commit_manual_result                                          (by widget)
+...
+/check_server_status                                           (by com-module)
+/commit_manual_result                                          (by widget)
+/generate_xml                                                          (by widget)
+/get_test_result                                                       (by com-module)
+/shut_down_server                                                      (by com-module)
+
+**/
+void HttpServer::processpost(int s, struct HttpRequest *prequest) {
+       prequest->prefix = "application/json";
+       string json_str = "";
+       string json_parse_str = "";
+
+       if (prequest->path.find("/init_test") != string::npos) {// invoke by com-module to send test data
+               m_block_finished = false;
+               m_set_finished = false;
+               m_timeout_count = 0;
+               m_server_checked = false;
+               cout << "[ init the test suite ]" << endl;
+               DBG_ONLY(outputFile << "[ init the test suite ]" << endl;);
+               parse_json_str(prequest->content);
+
+               start_client();
+               //set_timer(30); // set timer here incase widget hang.
+
+               m_block_case_index = 0;
+               if (m_current_block_index == 1)
+                       m_total_case_index = 0;
+
+               json_str = "{\"OK\":1}";
+       } else if (prequest->path == "/check_server") {// invoke by index.html to find server running or not
+               cout << "[ checking server, and found the server is running ]" << endl;
+               DBG_ONLY(outputFile << "[ checking server, and found the server is running ]" << endl;);
+               m_server_checked = true;
+               json_str = "{\"OK\":1}";
+       } else if (prequest->path == "/check_server_status") {// invoke by com-module to get server status
+               Json::Value status;
+               status["block_finished"] = m_block_finished ? 1 : 0;
+               status["finished"] = m_set_finished ? 1 : 0;
+        if (m_failto_launch > 10) {
+            status["error_code"] = 2;
+            status["finished"] = 1; // finish current set if can't launch widget
+        }
+               json_str = status.toStyledString();
+
+               if (!m_server_checked) {
+                       cout << "waiting for widget check_server" << endl;
+                       DBG_ONLY(outputFile << "wait for widget check_server" << endl;);
+               }
+               if (m_totalBlocks > 0)
+               {
+                       cout << "block: " << m_current_block_index << "/" << m_totalBlocks << ", total case: " << m_total_case_index << "/" << m_totalcaseCount << ", block case: " << m_block_case_index << "/" << m_block_case_count << ", m_timeout_count:" << m_timeout_count << endl;
+               DBG_ONLY(outputFile << "block: " << m_current_block_index << "/" << m_totalBlocks << ", total case: " << m_total_case_index << "/" << m_totalcaseCount << ", block case: " << m_block_case_index << "/" << m_block_case_count << ", m_timeout_count:" << m_timeout_count << endl;);
+               if (m_exeType != "auto") {
+                       cout << "manual cases. please check device." << endl << endl;
+                       DBG_ONLY(outputFile << "manual cases. please click on device." << endl << endl;);
+               }
+               }
+        
+       } else if (prequest->path == "/shut_down_server") {
+               if (g_run_wiget == true)
+                       killAllWidget(); // kill all widget when shutdown server
+               json_str = "{\"OK\":1}";
+               gIsRun = 0;
+       } else if (prequest->path.find("/init_session_id") != string::npos) {// invoke by index.html to record a session id
+               json_str = "{\"OK\":1}";
+               int index = prequest->path.find('=');
+               if (index != -1) {
+                       m_running_session = prequest->path.substr(index + 1);
+                       cout << "[ sessionID: " << m_running_session << " is gotten from the client ]" << endl;
+                       DBG_ONLY(outputFile << "[ sessionID: " << m_running_session << " is gotten from the client ]" << endl;);
+               } else {
+                       cout << "[ invalid session id ]" << endl;
+                       DBG_ONLY(outputFile << "[ invalid session id ]" << endl;);
+               }
+       } else if (prequest->path.find("/ask_next_step") != string::npos) {// invoke by index.html to check whether there are more cases
+               if (m_block_finished || m_set_finished)
+                       json_str = "{\"step\":\"stop\"}";
+               else
+                       json_str = "{\"step\":\"continue\"}";
+
+               m_timeout_count = 0; // reset the timeout count
+       } else if (prequest->path.find("/auto_test_task") != string::npos) {// invoke by index.html to get current auto case
+               if (m_test_cases == NULL) {
+                       json_str = "{\"Error\":\"no case\"}";
+               } else if (m_exeType != "auto") {
+                       json_str = "{\"none\":0}";
+               } else {
+                       string error_type = "";
+                       bool find_tc = get_auto_case(prequest->content, &error_type);
+                       if (find_tc == false) {
+                               json_str = "{\"" + error_type + "\":0}";
+                       } else {
+                               json_str =
+                                               m_test_cases[m_block_case_index].to_json().toStyledString();
+                       }
+               }
+       } else if (prequest->path.find("/manual_cases") != string::npos) {// invoke by index.html to get all manual cases
+               cancel_time_check(); // should not timeout in manual mode
+               if (!m_test_cases) {
+                       json_str = "{\"Error\":\"no case\"}";
+               } else if (m_exeType == "auto") {
+                       json_str = "{\"none\":0}";
+               } else {
+                       Json::Value arrayObj;
+                       for (int i = 0; i < m_block_case_count; i++)
+                               arrayObj.append(m_test_cases[i].to_json());
+
+                       json_str = arrayObj.toStyledString();
+               }
+       } else if (prequest->path.find("/case_time_out") != string::npos) {// invoke by timer to notify case timeout
+               if (!m_test_cases) {
+                       json_str = "{\"Error\":\"no case\"}";
+               } else if (m_block_case_index < m_block_case_count) {
+                       checkResult(&m_test_cases[m_block_case_index]);
+                       json_str = "{\"OK\":\"timeout\"}";
+               } else {
+                       json_str = "{\"Error\":\"case out of index\"}";
+               }
+       } else if (prequest->path.find("/commit_manual_result") != string::npos) {// invoke by index.html to provide result of a manual case.
+               if ((prequest->content.length() == 0) || (!m_test_cases)) {
+                       json_str = "{\"Error\":\"no manual result\"}";
+               } else {
+                       find_purpose(prequest, false); // will set index in find_purpose
+                       json_str = "{\"OK\":1}";
+               }
+       } else if (prequest->path.find("/check_execution_progress") != string::npos) {//invoke by index.html to get test result of last auto case
+               char *total_count = new char[16];
+               sprintf(total_count, "%d", m_totalcaseCount);
+               char *current_index = new char[16];
+               sprintf(current_index, "%d", m_total_case_index + 1);
+
+               string count_str(total_count);
+               string index_str(current_index);
+               json_str = "{\"total\":" + count_str + ",\"current\":" + index_str
+                               + ",\"last_test_result\":\"" + m_last_auto_result + "\"}";
+
+               delete[] total_count;
+               delete[] current_index;
+       }
+       //generate_xml:from index_html, a maually block finished when click done in widget
+       else if (prequest->path == "/generate_xml") {
+               cancel_time_check();
+               m_block_finished = true;
+               if (m_current_block_index == m_totalBlocks)
+                       m_set_finished = true;
+
+               json_str = "{\"OK\":1}";
+       }
+       //from com module,when m_set_finished is true
+       else if (prequest->path == "/get_test_result") {
+               cancel_time_check();
+               if (!m_test_cases) {
+                       json_str = "{\"Error\":\"no case\"}";
+               } else {
+                       Json::Value root;
+                       Json::Value arrayObj;
+                       for (int i = 0; i < m_block_case_count; i++)
+                               arrayObj.append(m_test_cases[i].result_to_json());
+
+                       char count[8];
+                       memset(count, 0, 8);
+                       sprintf(count, "%d", m_block_case_count);
+                       root["count"] = count;
+                       root["cases"] = arrayObj;
+
+                       json_str = root.toStyledString();
+               }
+       }
+    // index.html invoke this with purpose and result of an auto case, auto case commit result. 
+    // we need find correct test case by purpose, and record test result to it.
+    else if (prequest->path == "/commit_result") {
+               if ((prequest->content.length() == 0) || (!m_test_cases)) {
+                       json_str = "{\"Error\":\"no result\"}";
+                       m_last_auto_result = "BLOCK";
+                       m_rerun = true;
+               } else {
+                       char* tmp = ComFun::UrlDecode(prequest->content.c_str());
+                       string content = tmp;
+                       delete[] tmp; // free memory from comfun
+                       string sessionid = "";
+                       std::vector < std::string > splitstr = ComFun::split(content, "&");
+                       for (unsigned int i = 0; i < splitstr.size(); i++) {
+                               vector < string > resultkey = ComFun::split(splitstr[i], "=");
+                               if (resultkey[0] == "session_id"){
+                                       sessionid = resultkey[1];
+                                       break;
+                               }
+                       }
+                       if (m_running_session == sessionid) {
+                               m_rerun = false;
+                               if (m_block_case_index < m_block_case_count) {
+                       m_block_case_index++;
+                       m_total_case_index++;
+                   }
+
+                   find_purpose(prequest, true);
+
+                   json_str = "{\"OK\":1}";
+            }
+        }
+    } else if (prequest->path == "/set_capability") {// by com-module to send capability data
+        Json::Reader reader;
+
+        reader.parse(prequest->content, m_capability);
+
+        json_str = "{\"OK\":1}";
+    } else if (prequest->path.find("/capability") != string::npos) {// by test suite. only one query parameter each time
+        char* tmp = ComFun::UrlDecode(prequest->content.c_str());
+        string content = tmp;
+        delete[] tmp; // free memory from comfun
+
+        json_str = "{\"support\":0}";
+        string name = "", value = "";
+        std::vector < std::string > splitstr = ComFun::split(content, "&");
+        for (unsigned int i = 0; i < splitstr.size(); i++) {
+            vector < string > resultkey = ComFun::split(splitstr[i], "=");
+            if (resultkey[0] == "name") {
+               name = resultkey[1];
+               for (unsigned int i = 0; i < name.size(); i++)
+                       name[i] = tolower(name[i]);
+            }
+            if (resultkey[0] == "value") value = resultkey[1];
+        }
+        if (m_capability[name].isBool()) {// for bool value, omit the value part
+            json_str = "{\"support\":1}";
+        }
+        else if (m_capability[name].isInt()) {
+            if (m_capability[name].asInt() == atoi(value.c_str()))
+                json_str = "{\"support\":1}";
+        }
+        else if (m_capability[name].isString()) {
+            if (m_capability[name].asString() == value)
+                json_str = "{\"support\":1}";
+        }
+       } else {
+        cout << "=================unknown request: " << prequest->path << endl;
+       }
+    
+    DBG_ONLY(
+               outputFile << "prequest->path is:" << prequest->path << endl;
+               outputFile << "prequest->content is:" << prequest->content << endl;
+               outputFile << "server response is:" << json_str << endl;
+    );
+    if (g_show_log == true)
+    {
+               cout << "prequest->path is:" << prequest->path << endl;
+               cout << "prequest->content is:" << prequest->content << endl;
+               cout << "server response is:" << json_str << endl;
+    }
+
+       if (json_str != "")
+               sendresponse(s, 200, prequest, json_str);
+}
+
+// find correct case according the purpose sent by widget
+void HttpServer::find_purpose(struct HttpRequest *prequest, bool auto_test) {
+       string purpose = "";
+       string result = "";
+       string msg = "";
+       string content = "";
+
+       char* tmp = ComFun::UrlDecode(prequest->content.c_str());
+       content = tmp;
+       delete[] tmp; // free memory from comfun
+
+       std::vector < std::string > splitstr = ComFun::split(content, "&");
+       for (unsigned int i = 0; i < splitstr.size(); i++) {
+               vector < string > resultkey = ComFun::split(splitstr[i], "=");
+               if (resultkey[0] == "purpose")
+                       purpose = resultkey[1];
+               else if (resultkey[0] == "result")
+                       result = resultkey[1];
+               else if (resultkey[0] == "msg")
+                       msg = resultkey[1];
+       }
+
+       bool found = false;
+       for (int i = 0; i < m_block_case_count; i++) {
+               if (m_test_cases[i].purpose == purpose) {
+                       m_test_cases[i].set_result(result, msg);
+                       found = true;
+                       if (!auto_test) // should auto test use this logic?
+                               m_block_case_index = i; // set index by purpose found
+                       break;
+               }
+       }
+       if (!found) {
+               cout << "[ Error: can't find any test case by key: " << purpose << " ]" << endl;
+               DBG_ONLY(outputFile << "[ Error: can't find any test case by key: " << purpose << " ]"  << endl;);
+       }
+
+       if (auto_test)
+               m_last_auto_result = result;
+}
+
+// create new thread for each http request
+void* processthread(void *para) {
+       string recvstr = "";
+       char *buffer = new char[MAX_BUF]; // suppose 1 case need 1k, 100 cases will be sent each time, we need 100k memory?
+       memset(buffer, 0, MAX_BUF);
+       long iDataNum = 0;
+       int recvnum = 0;
+       HttpServer *server = (HttpServer *) para;
+       struct HttpRequest httprequest;
+       httprequest.content = "";
+       httprequest.path = "";
+
+       int content_length = 0;
+       int real_content_length = 0;
+       while (1) {
+               iDataNum = recv(server->clientsocket, buffer + recvnum,
+                               MAX_BUF - recvnum - 1, 0);
+               if (iDataNum <= 0) {
+                       delete[] buffer;
+                       close(server->clientsocket);
+                       pthread_exit (NULL);
+                       return 0;
+               }
+               recvnum += iDataNum;
+
+               // to calculate content length and real content read
+               if (content_length == 0) {
+                       char* Content_Length = strstr(buffer, "Content-Length: ");
+                       if (Content_Length != NULL) {
+                               char tmplen[32];
+                               sscanf(Content_Length, "%[^:]:%d", tmplen, &content_length);
+                               if (content_length > 0) {
+                                       char* tmp = strstr(buffer, "\r\n\r\n");
+                                       if (tmp == NULL) {
+                                               tmp = strstr(buffer, "\n\n");
+                                               if (tmp != NULL)
+                                                       real_content_length = iDataNum - (tmp-buffer) -2;
+                                               else {
+                                                       cout << "[ can't find \\r\\n\\r\\n or \\n\\n ]" << endl;
+                                                       break;
+                                               }
+                                       }
+                                       else real_content_length = iDataNum - (tmp-buffer) - 4;
+                               }
+                       }
+                       else real_content_length += iDataNum;
+               }
+               else real_content_length += iDataNum;
+
+               if (real_content_length >= content_length) break;
+       }
+       buffer[recvnum] = '\0';
+       recvstr = buffer;
+       delete[] buffer;
+
+       // parse request and process it
+       switch (server->getrequest(recvstr, &httprequest)) {
+       case GET:
+       case POST:
+               server->processpost(server->clientsocket, &httprequest);
+               break;
+       default:
+               break;
+       }
+       close(server->clientsocket);
+       pthread_exit (NULL);
+       return 0;
+}
+
+// send out timeout request to server if timeout. timer handler must be a global function, so can't invoke server's member function directly. 
+void timer_handler(int signum) {
+       // when timeout, we send a http request to server, so server can check result. seems no other convinent way to do it.
+       const char *strings =
+                       "GET /case_time_out HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: Close\r\n\r\n";
+       int sockfd = socket(AF_INET, SOCK_STREAM, 0);
+       struct sockaddr_in address;
+       address.sin_family = AF_INET;
+       address.sin_addr.s_addr = inet_addr("127.0.0.1");
+       address.sin_port = htons(SERVER_PORT);
+       int len = sizeof(address);
+       int result = connect(sockfd, (struct sockaddr *) &address, len);
+       if (result == -1) {
+               cout << "fail to send timeout request to server!" << endl;
+       } else {
+               write(sockfd, strings, strlen(strings));
+               close(sockfd);
+       }
+}
+
+void HttpServer::print_info_string(string case_id) {
+       if (m_rerun) {
+               cout << "\n[case] execute case again: ";
+               DBG_ONLY(outputFile << "\n[case] execute case again: ";);
+       }
+       else {
+               cout << "\n[case] execute case: ";
+               DBG_ONLY(outputFile << "\n[case] execute case: ";);
+       }
+       cout << case_id << endl;
+       cout << "last_test_result: " << m_last_auto_result << endl;
+       DBG_ONLY(outputFile << case_id << endl;);
+       DBG_ONLY(outputFile << "last_test_result: " << m_last_auto_result << endl;);
+}
+
+// prepare to run current auto case by set the start time, etc.
+bool HttpServer::get_auto_case(string content, string *type) {
+       if (!m_killing_widget) {
+               if (content != "") {
+                       string value = content.substr(content.find("=") + 1);
+                       if (value.length() > 0) {
+                               if (m_running_session == value) {
+                                       if (m_block_case_index < m_block_case_count) {
+                                               set_timer(m_test_cases[m_block_case_index].timeout_value);
+                                               m_test_cases[m_block_case_index].set_start_at();
+                                               print_info_string(m_test_cases[m_block_case_index].case_id);
+                                               return true;
+                                       } else {
+                                               cout << endl << "[ no auto case is available any more ]" << endl;
+                                               DBG_ONLY(outputFile << endl << "[ no auto case is available any more ]" << endl;);
+                                               *type = "none";
+                                               m_block_finished = true;
+                                               if (m_current_block_index == m_totalBlocks)
+                                                       m_set_finished = true; // the set is finished if current block is the last block
+                                       }
+                               } else {
+                                       cout << "[ Error: invalid session ID ]" << endl;
+                                       DBG_ONLY(outputFile << "[ Error: invalid session ID ]" << endl;);
+                                       *type = "invalid";
+                               }
+                       }
+               }
+       } else {
+               cout << "\n[ restart client process is activated, exit current client ]" << endl;
+               DBG_ONLY(outputFile << "\n[ restart client process is activated, exit current client ]" << endl;);
+               *type = "stop";
+       }
+       return false;
+}
+
+//start the socket server, listen to client
+void HttpServer::StartUp() {
+    DBG_ONLY(
+       outputFile.open("httpserver_log.txt",ios::out);
+       outputFile<<"httpserver.g_port is:"+g_port<<endl;
+       outputFile<<"httpserver.g_hide_status is:"+g_hide_status<<endl;
+       outputFile<<"httpserver.g_test_suite is:"+g_test_suite<<endl;
+       outputFile<<"httpserver.g_exe_sequence is:"+g_exe_sequence<<endl;
+       outputFile<<"httpserver.g_enable_memory_collection is:"+g_enable_memory_collection<<endl;
+    );
+    if (g_show_log == true)
+    {
+               cout<<"httpserver.g_show_log is:"<<g_show_log<<endl;
+               cout<<"httpserver.g_port is:"+g_port<<endl;
+               cout<<"httpserver.g_hide_status is:"+g_hide_status<<endl;
+               cout<<"httpserver.g_test_suite is:"+g_test_suite<<endl;
+               cout<<"httpserver.g_exe_sequence is:"+g_exe_sequence<<endl;
+               cout<<"httpserver.g_enable_memory_collection is:"+g_enable_memory_collection<<endl;
+    }
+    if (g_run_wiget == true){ 
+               getAllWidget();
+               killAllWidget();
+    }
+    else //wait for the index window.close, otherwise will occur bind aleady error
+               sleep(5);
+    int serversocket;
+       gServerStatus = 1;
+       struct sockaddr_in server_addr;
+       struct sockaddr_in clientAddr;
+       int addr_len = sizeof(clientAddr);
+
+       if ((serversocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+               perror( "error: create server socket!!!");
+               return;
+       }
+
+       bzero(&server_addr, sizeof(server_addr));
+       server_addr.sin_family = AF_INET;
+       server_addr.sin_port = htons(SERVER_PORT);
+       server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+       int tmp = 1;
+       setsockopt(serversocket, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(int));
+       if (bind(serversocket, (struct sockaddr *) &server_addr,
+                       sizeof(server_addr)) < 0) {
+               perror("error: bind address !!!!");
+               return;
+       }
+
+       if (listen(serversocket, 5) < 0) {
+               perror("error: listen !!!!");
+               return;
+       }
+       gIsRun = 1;
+       cout << "[Server is running.....]" << endl;
+       DBG_ONLY(outputFile << "[Server is running.....]" << endl;);
+
+       while (gIsRun) {
+               clientsocket = accept(serversocket, (struct sockaddr *) &clientAddr,
+                               (socklen_t*) &addr_len);
+               if (clientsocket < 0) {
+                       perror("error: accept client socket !!!");
+                       continue;
+               }
+               if (gServerStatus == 0) {
+                       close(clientsocket);
+               } else if (gServerStatus == 1) {
+                       pthread_t threadid;
+                       pthread_create(&threadid, NULL, processthread, (void *) this);
+                       //must have,otherwise the thread can not exit
+                       if (threadid != 0) { // can't exit thread without below code?
+                               pthread_join(threadid, NULL);
+                       }
+               }
+       }
+       close(serversocket);
+}
+
+// set result to current if timeout
+void HttpServer::checkResult(TestCase* testcase) {
+       if (!testcase->is_executed) {
+               cout << "[ Warning: time is out, test case \"" << testcase->purpose     << "\" is timeout, set the result to \"BLOCK\", and restart the client ]" << endl;
+               DBG_ONLY(outputFile << "[ Warning: time is out, test case \"" << testcase->purpose      << "\" is timeout, set the result to \"BLOCK\", and restart the client ]" << endl;);
+
+               testcase->set_result("BLOCK", "Time is out");
+               m_last_auto_result = "BLOCK";
+
+               if (g_run_wiget == true){
+                       cout << "[ start new client in 5sec ]" << endl;
+                       DBG_ONLY(outputFile << "[ start new client in 5sec ]" << endl;);
+                       sleep(5);
+                       start_client(); // start widget again in case it dead. browser not need to restart
+               }
+               m_timeout_count++;
+               if (m_block_case_index < m_block_case_count) {
+                       m_block_case_index++;
+                       m_total_case_index++;
+               }
+       } else {
+               cout << "[ test case \"" << testcase->purpose << "\" is executed in time, and the result is testcase->result ]" << endl;
+               DBG_ONLY(outputFile << "[ test case \"" << testcase->purpose << "\" is executed in time, and the result is testcase->result ]" << endl;);
+       }
+
+}
+
+void HttpServer::getAllWidget() {
+       char buf[128];
+       memset(buf, 0, 128);
+       FILE *pp;
+       string cmd = g_launcher+" -l | awk '{print $NF}' | sed -n '3,$p'";
+       if ((pp = popen(cmd.c_str(), "r")) == NULL) {
+               cout << "popen() error!" << endl;
+               DBG_ONLY(outputFile << "popen() error!" << endl;);
+               return;
+       }
+
+       while (fgets(buf, sizeof buf, pp)) {
+               buf[strlen(buf) - 1] = 0; // remove the character return at the end.
+               m_widgets.push_back(buf);
+               memset(buf, 0, 128);
+       }
+       pclose(pp);
+}
+
+// try to kill all widget listed by wrt-launch -l
+void HttpServer::killAllWidget() {
+       m_killing_widget = true;
+       string cmd = "killall " + g_launcher + " 2>/dev/null";
+       system(cmd.c_str());
+
+       char buf[128];
+       memset(buf, 0, 128);
+       FILE *pp;
+       if ((pp = popen("ps ax | awk '{print $NF}' | sed -n '2,$p'", "r")) == NULL) {
+               cout << "popen() error!" << endl;
+               DBG_ONLY(outputFile << "popen() error!" << endl;);
+               return;
+       }
+
+       std::vector<string> processes;
+       while (fgets(buf, sizeof buf, pp)) {
+               if(g_show_log == true)
+                       cout<<buf<<endl;
+               buf[strlen(buf) - 1] = 0; // remove the character return at the end.
+               processes.push_back(buf);
+               memset(buf, 0, 128);
+       }
+       if(g_show_log == true)
+               cout<<"end while"<<endl;
+       pclose(pp);
+
+
+       for (unsigned int i = 0; i < m_widgets.size(); i++) 
+               for (unsigned int j = 0; j < processes.size(); j++)
+                       if (string::npos != processes[j].find(m_widgets[i])) {
+                               string cmd = g_launcher +" -k " + m_widgets[i]; // use wrt-launcher to kill widget
+                               DBG_ONLY(outputFile<<cmd<<endl;);
+                               if(g_show_log == true)
+                                       cout<<cmd<<endl;
+                               run_cmd(cmd, "result: killed", true);
+                               break;
+                       }
+       if(g_show_log == true)
+               cout<<"end for"<<endl;
+       m_killing_widget = false;
+}
+
+// try to start widget
+void HttpServer::start_client() {
+       if (m_set_finished) return;// not restart widget if set finished
+       if(g_run_wiget == true){
+           run_cmd(g_kill_cmd, "result: killed", true);// kill before launch incase sometime relaunch fail, widget hang
+               sleep(5);
+               while (!run_cmd(g_launch_cmd, "result: launched", true)) {
+                       m_failto_launch++;
+                       DBG_ONLY(outputFile << m_failto_launch << endl;);
+                       if(g_show_log == true)
+                               cout << m_failto_launch << endl;
+                       if (m_failto_launch > 10) {
+                   m_set_finished = true;
+                   m_block_finished = true;
+                   m_total_case_index = m_totalcaseCount;
+                               break;
+                       }
+               run_cmd(g_kill_cmd, "result: killed", true);
+                       sleep(10); // try until start widget success
+               }
+               m_failto_launch = 0;
+       }
+       else{
+               sleep(5); // sleep 5 seconds to avoid launch browser too frequently, otherwise may launch fail.
+               string launch_cmd = ""; 
+               launch_cmd = g_launcher +"&";
+               int status = system(launch_cmd.c_str());
+               if(status != 0)
+               {
+                   cout<<"[cmd: "<<launch_cmd<<" error]"<<endl; 
+                   return;
+               }
+       }
+}
+
+// run shell cmd. return true if the output equal to expectString. show cmd and output if showcmdAnyway.
+bool HttpServer::run_cmd(string cmdString, string expectString,
+               bool showcmdAnyway) {
+       bool ret = false;
+
+       char buf[128];
+       memset(buf, 0, 128);
+       FILE *pp;
+       if ((pp = popen(cmdString.c_str(), "r")) == NULL) {
+               cout << "popen() error!" << endl;
+               DBG_ONLY(outputFile << "popen() error!" << endl;);
+               return ret;
+       }
+
+       while (fgets(buf, sizeof buf, pp)) {
+               if (strstr(buf, expectString.c_str()))
+                       ret = true;
+               if (ret || showcmdAnyway) { // show cmd and result if ret or showcmdAnyWay
+                       cout << cmdString << endl;
+                       cout << buf << endl;
+                       DBG_ONLY(outputFile << cmdString << endl;);
+                       DBG_ONLY(outputFile << buf << endl;);
+               }
+               memset(buf, 0, 128);            
+       }
+       pclose(pp);     
+       return ret;
+}
\ No newline at end of file
diff --git a/src/json/json_batchallocator.h b/src/json/json_batchallocator.h
new file mode 100644 (file)
index 0000000..26b1ccb
--- /dev/null
@@ -0,0 +1,114 @@
+#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
+# define JSONCPP_BATCHALLOCATOR_H_INCLUDED
+
+# include <stdlib.h>
+# include <assert.h>
+
+# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+namespace Json {
+
+/* Fast memory allocator.
+ *
+ * This memory allocator allocates memory for a batch of object (specified by
+ * the page size, the number of object in each page).
+ *
+ * It does not allow the destruction of a single object. All the allocated objects
+ * can be destroyed at once. The memory can be either released or reused for future
+ * allocation.
+ * 
+ * The in-place new operator must be used to construct the object using the pointer
+ * returned by allocate.
+ */
+template<typename AllocatedType, const unsigned int objectPerAllocation>
+class BatchAllocator {
+public:
+       typedef AllocatedType Type;
+
+       BatchAllocator(unsigned int objectsPerPage = 255) :
+                       freeHead_(0), objectsPerPage_(objectsPerPage) {
+//      printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() );
+               assert(
+                               sizeof(AllocatedType) * objectPerAllocation
+                                               >= sizeof(AllocatedType *)); // We must be able to store a slist in the object free space.
+               assert(objectsPerPage >= 16);
+               batches_ = allocateBatch(0);   // allocated a dummy page
+               currentBatch_ = batches_;
+       }
+
+       ~BatchAllocator() {
+               for (BatchInfo *batch = batches_; batch;) {
+                       BatchInfo *nextBatch = batch->next_;
+                       free(batch);
+                       batch = nextBatch;
+               }
+       }
+
+       /// allocate space for an array of objectPerAllocation object.
+       /// @warning it is the responsability of the caller to call objects constructors.
+       AllocatedType *allocate() {
+               if (freeHead_) // returns node from free list.
+               {
+                       AllocatedType *object = freeHead_;
+                       freeHead_ = *(AllocatedType **) object;
+                       return object;
+               }
+               if (currentBatch_->used_ == currentBatch_->end_) {
+                       currentBatch_ = currentBatch_->next_;
+                       while (currentBatch_ && currentBatch_->used_ == currentBatch_->end_)
+                               currentBatch_ = currentBatch_->next_;
+
+                       if (!currentBatch_) // no free batch found, allocate a new one
+                       {
+                               currentBatch_ = allocateBatch(objectsPerPage_);
+                               currentBatch_->next_ = batches_; // insert at the head of the list
+                               batches_ = currentBatch_;
+                       }
+               }
+               AllocatedType *allocated = currentBatch_->used_;
+               currentBatch_->used_ += objectPerAllocation;
+               return allocated;
+       }
+
+       /// Release the object.
+       /// @warning it is the responsability of the caller to actually destruct the object.
+       void release(AllocatedType *object) {
+               assert(object != 0);
+               *(AllocatedType **) object = freeHead_;
+               freeHead_ = object;
+       }
+
+private:
+       struct BatchInfo {
+               BatchInfo *next_;
+               AllocatedType *used_;
+               AllocatedType *end_;
+               AllocatedType buffer_[objectPerAllocation];
+       };
+
+       // disabled copy constructor and assignement operator.
+       BatchAllocator(const BatchAllocator &);
+       void operator =(const BatchAllocator &);
+
+       static BatchInfo *allocateBatch(unsigned int objectsPerPage) {
+               const unsigned int mallocSize = sizeof(BatchInfo)
+                               - sizeof(AllocatedType) * objectPerAllocation
+                               + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
+               BatchInfo *batch = static_cast<BatchInfo*>(malloc(mallocSize));
+               batch->next_ = 0;
+               batch->used_ = batch->buffer_;
+               batch->end_ = batch->buffer_ + objectsPerPage;
+               return batch;
+       }
+
+       BatchInfo *batches_;
+       BatchInfo *currentBatch_;
+       /// Head of a single linked list within the allocated space of freeed object
+       AllocatedType *freeHead_;
+       unsigned int objectsPerPage_;
+};
+
+} // namespace Json
+
+# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
+#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
diff --git a/src/json/json_internalarray.inl b/src/json/json_internalarray.inl
new file mode 100644 (file)
index 0000000..9b985d2
--- /dev/null
@@ -0,0 +1,448 @@
+// included by json_value.cpp
+// everything is within Json namespace
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueInternalArray
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueArrayAllocator::~ValueArrayAllocator()
+{
+}
+
+// //////////////////////////////////////////////////////////////////
+// class DefaultValueArrayAllocator
+// //////////////////////////////////////////////////////////////////
+#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+class DefaultValueArrayAllocator : public ValueArrayAllocator
+{
+public: // overridden from ValueArrayAllocator
+   virtual ~DefaultValueArrayAllocator()
+   {
+   }
+
+   virtual ValueInternalArray *newArray()
+   {
+      return new ValueInternalArray();
+   }
+
+   virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
+   {
+      return new ValueInternalArray( other );
+   }
+
+   virtual void destructArray( ValueInternalArray *array )
+   {
+      delete array;
+   }
+
+   virtual void reallocateArrayPageIndex( Value **&indexes, 
+                                          ValueInternalArray::PageIndex &indexCount,
+                                          ValueInternalArray::PageIndex minNewIndexCount )
+   {
+      ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
+      if ( minNewIndexCount > newIndexCount )
+         newIndexCount = minNewIndexCount;
+      void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
+      if ( !newIndexes )
+         throw std::bad_alloc();
+      indexCount = newIndexCount;
+      indexes = static_cast<Value **>( newIndexes );
+   }
+   virtual void releaseArrayPageIndex( Value **indexes, 
+                                       ValueInternalArray::PageIndex indexCount )
+   {
+      if ( indexes )
+         free( indexes );
+   }
+
+   virtual Value *allocateArrayPage()
+   {
+      return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) );
+   }
+
+   virtual void releaseArrayPage( Value *value )
+   {
+      if ( value )
+         free( value );
+   }
+};
+
+#else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+/// @todo make this thread-safe (lock when accessign batch allocator)
+class DefaultValueArrayAllocator : public ValueArrayAllocator
+{
+public: // overridden from ValueArrayAllocator
+   virtual ~DefaultValueArrayAllocator()
+   {
+   }
+
+   virtual ValueInternalArray *newArray()
+   {
+      ValueInternalArray *array = arraysAllocator_.allocate();
+      new (array) ValueInternalArray(); // placement new
+      return array;
+   }
+
+   virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
+   {
+      ValueInternalArray *array = arraysAllocator_.allocate();
+      new (array) ValueInternalArray( other ); // placement new
+      return array;
+   }
+
+   virtual void destructArray( ValueInternalArray *array )
+   {
+      if ( array )
+      {
+         array->~ValueInternalArray();
+         arraysAllocator_.release( array );
+      }
+   }
+
+   virtual void reallocateArrayPageIndex( Value **&indexes, 
+                                          ValueInternalArray::PageIndex &indexCount,
+                                          ValueInternalArray::PageIndex minNewIndexCount )
+   {
+      ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
+      if ( minNewIndexCount > newIndexCount )
+         newIndexCount = minNewIndexCount;
+      void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
+      if ( !newIndexes )
+         throw std::bad_alloc();
+      indexCount = newIndexCount;
+      indexes = static_cast<Value **>( newIndexes );
+   }
+   virtual void releaseArrayPageIndex( Value **indexes, 
+                                       ValueInternalArray::PageIndex indexCount )
+   {
+      if ( indexes )
+         free( indexes );
+   }
+
+   virtual Value *allocateArrayPage()
+   {
+      return static_cast<Value *>( pagesAllocator_.allocate() );
+   }
+
+   virtual void releaseArrayPage( Value *value )
+   {
+      if ( value )
+         pagesAllocator_.release( value );
+   }
+private:
+   BatchAllocator<ValueInternalArray,1> arraysAllocator_;
+   BatchAllocator<Value,ValueInternalArray::itemsPerPage> pagesAllocator_;
+};
+#endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+
+static ValueArrayAllocator *&arrayAllocator()
+{
+   static DefaultValueArrayAllocator defaultAllocator;
+   static ValueArrayAllocator *arrayAllocator = &defaultAllocator;
+   return arrayAllocator;
+}
+
+static struct DummyArrayAllocatorInitializer {
+   DummyArrayAllocatorInitializer() 
+   {
+      arrayAllocator();      // ensure arrayAllocator() statics are initialized before main().
+   }
+} dummyArrayAllocatorInitializer;
+
+// //////////////////////////////////////////////////////////////////
+// class ValueInternalArray
+// //////////////////////////////////////////////////////////////////
+bool 
+ValueInternalArray::equals( const IteratorState &x, 
+                            const IteratorState &other )
+{
+   return x.array_ == other.array_  
+          &&  x.currentItemIndex_ == other.currentItemIndex_  
+          &&  x.currentPageIndex_ == other.currentPageIndex_;
+}
+
+
+void 
+ValueInternalArray::increment( IteratorState &it )
+{
+   JSON_ASSERT_MESSAGE( it.array_  &&
+      (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
+      != it.array_->size_,
+      "ValueInternalArray::increment(): moving iterator beyond end" );
+   ++(it.currentItemIndex_);
+   if ( it.currentItemIndex_ == itemsPerPage )
+   {
+      it.currentItemIndex_ = 0;
+      ++(it.currentPageIndex_);
+   }
+}
+
+
+void 
+ValueInternalArray::decrement( IteratorState &it )
+{
+   JSON_ASSERT_MESSAGE( it.array_  &&  it.currentPageIndex_ == it.array_->pages_ 
+                        &&  it.currentItemIndex_ == 0,
+      "ValueInternalArray::decrement(): moving iterator beyond end" );
+   if ( it.currentItemIndex_ == 0 )
+   {
+      it.currentItemIndex_ = itemsPerPage-1;
+      --(it.currentPageIndex_);
+   }
+   else
+   {
+      --(it.currentItemIndex_);
+   }
+}
+
+
+Value &
+ValueInternalArray::unsafeDereference( const IteratorState &it )
+{
+   return (*(it.currentPageIndex_))[it.currentItemIndex_];
+}
+
+
+Value &
+ValueInternalArray::dereference( const IteratorState &it )
+{
+   JSON_ASSERT_MESSAGE( it.array_  &&
+      (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
+      < it.array_->size_,
+      "ValueInternalArray::dereference(): dereferencing invalid iterator" );
+   return unsafeDereference( it );
+}
+
+void 
+ValueInternalArray::makeBeginIterator( IteratorState &it ) const
+{
+   it.array_ = const_cast<ValueInternalArray *>( this );
+   it.currentItemIndex_ = 0;
+   it.currentPageIndex_ = pages_;
+}
+
+
+void 
+ValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const
+{
+   it.array_ = const_cast<ValueInternalArray *>( this );
+   it.currentItemIndex_ = index % itemsPerPage;
+   it.currentPageIndex_ = pages_ + index / itemsPerPage;
+}
+
+
+void 
+ValueInternalArray::makeEndIterator( IteratorState &it ) const
+{
+   makeIterator( it, size_ );
+}
+
+
+ValueInternalArray::ValueInternalArray()
+   : pages_( 0 )
+   , size_( 0 )
+   , pageCount_( 0 )
+{
+}
+
+
+ValueInternalArray::ValueInternalArray( const ValueInternalArray &other )
+   : pages_( 0 )
+   , pageCount_( 0 )
+   , size_( other.size_ )
+{
+   PageIndex minNewPages = other.size_ / itemsPerPage;
+   arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
+   JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, 
+                        "ValueInternalArray::reserve(): bad reallocation" );
+   IteratorState itOther;
+   other.makeBeginIterator( itOther );
+   Value *value;
+   for ( ArrayIndex index = 0; index < size_; ++index, increment(itOther) )
+   {
+      if ( index % itemsPerPage == 0 )
+      {
+         PageIndex pageIndex = index / itemsPerPage;
+         value = arrayAllocator()->allocateArrayPage();
+         pages_[pageIndex] = value;
+      }
+      new (value) Value( dereference( itOther ) );
+   }
+}
+
+
+ValueInternalArray &
+ValueInternalArray::operator =( const ValueInternalArray &other )
+{
+   ValueInternalArray temp( other );
+   swap( temp );
+   return *this;
+}
+
+
+ValueInternalArray::~ValueInternalArray()
+{
+   // destroy all constructed items
+   IteratorState it;
+   IteratorState itEnd;
+   makeBeginIterator( it);
+   makeEndIterator( itEnd );
+   for ( ; !equals(it,itEnd); increment(it) )
+   {
+      Value *value = &dereference(it);
+      value->~Value();
+   }
+   // release all pages
+   PageIndex lastPageIndex = size_ / itemsPerPage;
+   for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex )
+      arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
+   // release pages index
+   arrayAllocator()->releaseArrayPageIndex( pages_, pageCount_ );
+}
+
+
+void 
+ValueInternalArray::swap( ValueInternalArray &other )
+{
+   Value **tempPages = pages_;
+   pages_ = other.pages_;
+   other.pages_ = tempPages;
+   ArrayIndex tempSize = size_;
+   size_ = other.size_;
+   other.size_ = tempSize;
+   PageIndex tempPageCount = pageCount_;
+   pageCount_ = other.pageCount_;
+   other.pageCount_ = tempPageCount;
+}
+
+void 
+ValueInternalArray::clear()
+{
+   ValueInternalArray dummy;
+   swap( dummy );
+}
+
+
+void 
+ValueInternalArray::resize( ArrayIndex newSize )
+{
+   if ( newSize == 0 )
+      clear();
+   else if ( newSize < size_ )
+   {
+      IteratorState it;
+      IteratorState itEnd;
+      makeIterator( it, newSize );
+      makeIterator( itEnd, size_ );
+      for ( ; !equals(it,itEnd); increment(it) )
+      {
+         Value *value = &dereference(it);
+         value->~Value();
+      }
+      PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage;
+      PageIndex lastPageIndex = size_ / itemsPerPage;
+      for ( ; pageIndex < lastPageIndex; ++pageIndex )
+         arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
+      size_ = newSize;
+   }
+   else if ( newSize > size_ )
+      resolveReference( newSize );
+}
+
+
+void 
+ValueInternalArray::makeIndexValid( ArrayIndex index )
+{
+   // Need to enlarge page index ?
+   if ( index >= pageCount_ * itemsPerPage )
+   {
+      PageIndex minNewPages = (index + 1) / itemsPerPage;
+      arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
+      JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" );
+   }
+
+   // Need to allocate new pages ?
+   ArrayIndex nextPageIndex = 
+      (size_ % itemsPerPage) != 0 ? size_ - (size_%itemsPerPage) + itemsPerPage
+                                  : size_;
+   if ( nextPageIndex <= index )
+   {
+      PageIndex pageIndex = nextPageIndex / itemsPerPage;
+      PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1;
+      for ( ; pageToAllocate-- > 0; ++pageIndex )
+         pages_[pageIndex] = arrayAllocator()->allocateArrayPage();
+   }
+
+   // Initialize all new entries
+   IteratorState it;
+   IteratorState itEnd;
+   makeIterator( it, size_ );
+   size_ = index + 1;
+   makeIterator( itEnd, size_ );
+   for ( ; !equals(it,itEnd); increment(it) )
+   {
+      Value *value = &dereference(it);
+      new (value) Value(); // Construct a default value using placement new
+   }
+}
+
+Value &
+ValueInternalArray::resolveReference( ArrayIndex index )
+{
+   if ( index >= size_ )
+      makeIndexValid( index );
+   return pages_[index/itemsPerPage][index%itemsPerPage];
+}
+
+Value *
+ValueInternalArray::find( ArrayIndex index ) const
+{
+   if ( index >= size_ )
+      return 0;
+   return &(pages_[index/itemsPerPage][index%itemsPerPage]);
+}
+
+ValueInternalArray::ArrayIndex 
+ValueInternalArray::size() const
+{
+   return size_;
+}
+
+int 
+ValueInternalArray::distance( const IteratorState &x, const IteratorState &y )
+{
+   return indexOf(y) - indexOf(x);
+}
+
+
+ValueInternalArray::ArrayIndex 
+ValueInternalArray::indexOf( const IteratorState &iterator )
+{
+   if ( !iterator.array_ )
+      return ArrayIndex(-1);
+   return ArrayIndex(
+      (iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage 
+      + iterator.currentItemIndex_ );
+}
+
+
+int 
+ValueInternalArray::compare( const ValueInternalArray &other ) const
+{
+   int sizeDiff( size_ - other.size_ );
+   if ( sizeDiff != 0 )
+      return sizeDiff;
+   
+   for ( ArrayIndex index =0; index < size_; ++index )
+   {
+      int diff = pages_[index/itemsPerPage][index%itemsPerPage].compare( 
+         other.pages_[index/itemsPerPage][index%itemsPerPage] );
+      if ( diff != 0 )
+         return diff;
+   }
+   return 0;
+}
diff --git a/src/json/json_internalmap.inl b/src/json/json_internalmap.inl
new file mode 100644 (file)
index 0000000..1977148
--- /dev/null
@@ -0,0 +1,607 @@
+// included by json_value.cpp
+// everything is within Json namespace
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueInternalMap
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+/** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) );
+   * This optimization is used by the fast allocator.
+   */
+ValueInternalLink::ValueInternalLink()
+   : previous_( 0 )
+   , next_( 0 )
+{
+}
+
+ValueInternalLink::~ValueInternalLink()
+{ 
+   for ( int index =0; index < itemPerLink; ++index )
+   {
+      if ( !items_[index].isItemAvailable() )
+      {
+         if ( !items_[index].isMemberNameStatic() )
+            free( keys_[index] );
+      }
+      else
+         break;
+   }
+}
+
+
+
+ValueMapAllocator::~ValueMapAllocator()
+{
+}
+
+#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+class DefaultValueMapAllocator : public ValueMapAllocator
+{
+public: // overridden from ValueMapAllocator
+   virtual ValueInternalMap *newMap()
+   {
+      return new ValueInternalMap();
+   }
+
+   virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
+   {
+      return new ValueInternalMap( other );
+   }
+
+   virtual void destructMap( ValueInternalMap *map )
+   {
+      delete map;
+   }
+
+   virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
+   {
+      return new ValueInternalLink[size];
+   }
+
+   virtual void releaseMapBuckets( ValueInternalLink *links )
+   {
+      delete [] links;
+   }
+
+   virtual ValueInternalLink *allocateMapLink()
+   {
+      return new ValueInternalLink();
+   }
+
+   virtual void releaseMapLink( ValueInternalLink *link )
+   {
+      delete link;
+   }
+};
+#else
+/// @todo make this thread-safe (lock when accessign batch allocator)
+class DefaultValueMapAllocator : public ValueMapAllocator
+{
+public: // overridden from ValueMapAllocator
+   virtual ValueInternalMap *newMap()
+   {
+      ValueInternalMap *map = mapsAllocator_.allocate();
+      new (map) ValueInternalMap(); // placement new
+      return map;
+   }
+
+   virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
+   {
+      ValueInternalMap *map = mapsAllocator_.allocate();
+      new (map) ValueInternalMap( other ); // placement new
+      return map;
+   }
+
+   virtual void destructMap( ValueInternalMap *map )
+   {
+      if ( map )
+      {
+         map->~ValueInternalMap();
+         mapsAllocator_.release( map );
+      }
+   }
+
+   virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
+   {
+      return new ValueInternalLink[size];
+   }
+
+   virtual void releaseMapBuckets( ValueInternalLink *links )
+   {
+      delete [] links;
+   }
+
+   virtual ValueInternalLink *allocateMapLink()
+   {
+      ValueInternalLink *link = linksAllocator_.allocate();
+      memset( link, 0, sizeof(ValueInternalLink) );
+      return link;
+   }
+
+   virtual void releaseMapLink( ValueInternalLink *link )
+   {
+      link->~ValueInternalLink();
+      linksAllocator_.release( link );
+   }
+private:
+   BatchAllocator<ValueInternalMap,1> mapsAllocator_;
+   BatchAllocator<ValueInternalLink,1> linksAllocator_;
+};
+#endif
+
+static ValueMapAllocator *&mapAllocator()
+{
+   static DefaultValueMapAllocator defaultAllocator;
+   static ValueMapAllocator *mapAllocator = &defaultAllocator;
+   return mapAllocator;
+}
+
+static struct DummyMapAllocatorInitializer {
+   DummyMapAllocatorInitializer() 
+   {
+      mapAllocator();      // ensure mapAllocator() statics are initialized before main().
+   }
+} dummyMapAllocatorInitializer;
+
+
+
+// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32.
+
+/*
+use linked list hash map. 
+buckets array is a container.
+linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124)
+value have extra state: valid, available, deleted
+*/
+
+
+ValueInternalMap::ValueInternalMap()
+   : buckets_( 0 )
+   , tailLink_( 0 )
+   , bucketsSize_( 0 )
+   , itemCount_( 0 )
+{
+}
+
+
+ValueInternalMap::ValueInternalMap( const ValueInternalMap &other )
+   : buckets_( 0 )
+   , tailLink_( 0 )
+   , bucketsSize_( 0 )
+   , itemCount_( 0 )
+{
+   reserve( other.itemCount_ );
+   IteratorState it;
+   IteratorState itEnd;
+   other.makeBeginIterator( it );
+   other.makeEndIterator( itEnd );
+   for ( ; !equals(it,itEnd); increment(it) )
+   {
+      bool isStatic;
+      const char *memberName = key( it, isStatic );
+      const Value &aValue = value( it );
+      resolveReference(memberName, isStatic) = aValue;
+   }
+}
+
+
+ValueInternalMap &
+ValueInternalMap::operator =( const ValueInternalMap &other )
+{
+   ValueInternalMap dummy( other );
+   swap( dummy );
+   return *this;
+}
+
+
+ValueInternalMap::~ValueInternalMap()
+{
+   if ( buckets_ )
+   {
+      for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex )
+      {
+         ValueInternalLink *link = buckets_[bucketIndex].next_;
+         while ( link )
+         {
+            ValueInternalLink *linkToRelease = link;
+            link = link->next_;
+            mapAllocator()->releaseMapLink( linkToRelease );
+         }
+      }
+      mapAllocator()->releaseMapBuckets( buckets_ );
+   }
+}
+
+
+void 
+ValueInternalMap::swap( ValueInternalMap &other )
+{
+   ValueInternalLink *tempBuckets = buckets_;
+   buckets_ = other.buckets_;
+   other.buckets_ = tempBuckets;
+   ValueInternalLink *tempTailLink = tailLink_;
+   tailLink_ = other.tailLink_;
+   other.tailLink_ = tempTailLink;
+   BucketIndex tempBucketsSize = bucketsSize_;
+   bucketsSize_ = other.bucketsSize_;
+   other.bucketsSize_ = tempBucketsSize;
+   BucketIndex tempItemCount = itemCount_;
+   itemCount_ = other.itemCount_;
+   other.itemCount_ = tempItemCount;
+}
+
+
+void 
+ValueInternalMap::clear()
+{
+   ValueInternalMap dummy;
+   swap( dummy );
+}
+
+
+ValueInternalMap::BucketIndex 
+ValueInternalMap::size() const
+{
+   return itemCount_;
+}
+
+bool 
+ValueInternalMap::reserveDelta( BucketIndex growth )
+{
+   return reserve( itemCount_ + growth );
+}
+
+bool 
+ValueInternalMap::reserve( BucketIndex newItemCount )
+{
+   if ( !buckets_  &&  newItemCount > 0 )
+   {
+      buckets_ = mapAllocator()->allocateMapBuckets( 1 );
+      bucketsSize_ = 1;
+      tailLink_ = &buckets_[0];
+   }
+//   BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;
+   return true;
+}
+
+
+const Value *
+ValueInternalMap::find( const char *key ) const
+{
+   if ( !bucketsSize_ )
+      return 0;
+   HashKey hashedKey = hash( key );
+   BucketIndex bucketIndex = hashedKey % bucketsSize_;
+   for ( const ValueInternalLink *current = &buckets_[bucketIndex]; 
+         current != 0; 
+         current = current->next_ )
+   {
+      for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index )
+      {
+         if ( current->items_[index].isItemAvailable() )
+            return 0;
+         if ( strcmp( key, current->keys_[index] ) == 0 )
+            return &current->items_[index];
+      }
+   }
+   return 0;
+}
+
+
+Value *
+ValueInternalMap::find( const char *key )
+{
+   const ValueInternalMap *constThis = this;
+   return const_cast<Value *>( constThis->find( key ) );
+}
+
+
+Value &
+ValueInternalMap::resolveReference( const char *key,
+                                    bool isStatic )
+{
+   HashKey hashedKey = hash( key );
+   if ( bucketsSize_ )
+   {
+      BucketIndex bucketIndex = hashedKey % bucketsSize_;
+      ValueInternalLink **previous = 0;
+      BucketIndex index;
+      for ( ValueInternalLink *current = &buckets_[bucketIndex]; 
+            current != 0; 
+            previous = &current->next_, current = current->next_ )
+      {
+         for ( index=0; index < ValueInternalLink::itemPerLink; ++index )
+         {
+            if ( current->items_[index].isItemAvailable() )
+               return setNewItem( key, isStatic, current, index );
+            if ( strcmp( key, current->keys_[index] ) == 0 )
+               return current->items_[index];
+         }
+      }
+   }
+
+   reserveDelta( 1 );
+   return unsafeAdd( key, isStatic, hashedKey );
+}
+
+
+void 
+ValueInternalMap::remove( const char *key )
+{
+   HashKey hashedKey = hash( key );
+   if ( !bucketsSize_ )
+      return;
+   BucketIndex bucketIndex = hashedKey % bucketsSize_;
+   for ( ValueInternalLink *link = &buckets_[bucketIndex]; 
+         link != 0; 
+         link = link->next_ )
+   {
+      BucketIndex index;
+      for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
+      {
+         if ( link->items_[index].isItemAvailable() )
+            return;
+         if ( strcmp( key, link->keys_[index] ) == 0 )
+         {
+            doActualRemove( link, index, bucketIndex );
+            return;
+         }
+      }
+   }
+}
+
+void 
+ValueInternalMap::doActualRemove( ValueInternalLink *link, 
+                                  BucketIndex index,
+                                  BucketIndex bucketIndex )
+{
+   // find last item of the bucket and swap it with the 'removed' one.
+   // set removed items flags to 'available'.
+   // if last page only contains 'available' items, then desallocate it (it's empty)
+   ValueInternalLink *&lastLink = getLastLinkInBucket( index );
+   BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1
+   for ( ;   
+         lastItemIndex < ValueInternalLink::itemPerLink; 
+         ++lastItemIndex ) // may be optimized with dicotomic search
+   {
+      if ( lastLink->items_[lastItemIndex].isItemAvailable() )
+         break;
+   }
+   
+   BucketIndex lastUsedIndex = lastItemIndex - 1;
+   Value *valueToDelete = &link->items_[index];
+   Value *valueToPreserve = &lastLink->items_[lastUsedIndex];
+   if ( valueToDelete != valueToPreserve )
+      valueToDelete->swap( *valueToPreserve );
+   if ( lastUsedIndex == 0 )  // page is now empty
+   {  // remove it from bucket linked list and delete it.
+      ValueInternalLink *linkPreviousToLast = lastLink->previous_;
+      if ( linkPreviousToLast != 0 )   // can not deleted bucket link.
+      {
+         mapAllocator()->releaseMapLink( lastLink );
+         linkPreviousToLast->next_ = 0;
+         lastLink = linkPreviousToLast;
+      }
+   }
+   else
+   {
+      Value dummy;
+      valueToPreserve->swap( dummy ); // restore deleted to default Value.
+      valueToPreserve->setItemUsed( false );
+   }
+   --itemCount_;
+}
+
+
+ValueInternalLink *&
+ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex )
+{
+   if ( bucketIndex == bucketsSize_ - 1 )
+      return tailLink_;
+   ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_;
+   if ( !previous )
+      previous = &buckets_[bucketIndex];
+   return previous;
+}
+
+
+Value &
+ValueInternalMap::setNewItem( const char *key, 
+                              bool isStatic,
+                              ValueInternalLink *link, 
+                              BucketIndex index )
+{
+   char *duplicatedKey = valueAllocator()->makeMemberName( key );
+   ++itemCount_;
+   link->keys_[index] = duplicatedKey;
+   link->items_[index].setItemUsed();
+   link->items_[index].setMemberNameIsStatic( isStatic );
+   return link->items_[index]; // items already default constructed.
+}
+
+
+Value &
+ValueInternalMap::unsafeAdd( const char *key, 
+                             bool isStatic, 
+                             HashKey hashedKey )
+{
+   JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." );
+   BucketIndex bucketIndex = hashedKey % bucketsSize_;
+   ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex );
+   ValueInternalLink *link = previousLink;
+   BucketIndex index;
+   for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
+   {
+      if ( link->items_[index].isItemAvailable() )
+         break;
+   }
+   if ( index == ValueInternalLink::itemPerLink ) // need to add a new page
+   {
+      ValueInternalLink *newLink = mapAllocator()->allocateMapLink();
+      index = 0;
+      link->next_ = newLink;
+      previousLink = newLink;
+      link = newLink;
+   }
+   return setNewItem( key, isStatic, link, index );
+}
+
+
+ValueInternalMap::HashKey 
+ValueInternalMap::hash( const char *key ) const
+{
+   HashKey hash = 0;
+   while ( *key )
+      hash += *key++ * 37;
+   return hash;
+}
+
+
+int 
+ValueInternalMap::compare( const ValueInternalMap &other ) const
+{
+   int sizeDiff( itemCount_ - other.itemCount_ );
+   if ( sizeDiff != 0 )
+      return sizeDiff;
+   // Strict order guaranty is required. Compare all keys FIRST, then compare values.
+   IteratorState it;
+   IteratorState itEnd;
+   makeBeginIterator( it );
+   makeEndIterator( itEnd );
+   for ( ; !equals(it,itEnd); increment(it) )
+   {
+      if ( !other.find( key( it ) ) )
+         return 1;
+   }
+
+   // All keys are equals, let's compare values
+   makeBeginIterator( it );
+   for ( ; !equals(it,itEnd); increment(it) )
+   {
+      const Value *otherValue = other.find( key( it ) );
+      int valueDiff = value(it).compare( *otherValue );
+      if ( valueDiff != 0 )
+         return valueDiff;
+   }
+   return 0;
+}
+
+
+void 
+ValueInternalMap::makeBeginIterator( IteratorState &it ) const
+{
+   it.map_ = const_cast<ValueInternalMap *>( this );
+   it.bucketIndex_ = 0;
+   it.itemIndex_ = 0;
+   it.link_ = buckets_;
+}
+
+
+void 
+ValueInternalMap::makeEndIterator( IteratorState &it ) const
+{
+   it.map_ = const_cast<ValueInternalMap *>( this );
+   it.bucketIndex_ = bucketsSize_;
+   it.itemIndex_ = 0;
+   it.link_ = 0;
+}
+
+
+bool 
+ValueInternalMap::equals( const IteratorState &x, const IteratorState &other )
+{
+   return x.map_ == other.map_  
+          &&  x.bucketIndex_ == other.bucketIndex_  
+          &&  x.link_ == other.link_
+          &&  x.itemIndex_ == other.itemIndex_;
+}
+
+
+void 
+ValueInternalMap::incrementBucket( IteratorState &iterator )
+{
+   ++iterator.bucketIndex_;
+   JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_,
+      "ValueInternalMap::increment(): attempting to iterate beyond end." );
+   if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ )
+      iterator.link_ = 0;
+   else
+      iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]);
+   iterator.itemIndex_ = 0;
+}
+
+
+void 
+ValueInternalMap::increment( IteratorState &iterator )
+{
+   JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." );
+   ++iterator.itemIndex_;
+   if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink )
+   {
+      JSON_ASSERT_MESSAGE( iterator.link_ != 0,
+         "ValueInternalMap::increment(): attempting to iterate beyond end." );
+      iterator.link_ = iterator.link_->next_;
+      if ( iterator.link_ == 0 )
+         incrementBucket( iterator );
+   }
+   else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() )
+   {
+      incrementBucket( iterator );
+   }
+}
+
+
+void 
+ValueInternalMap::decrement( IteratorState &iterator )
+{
+   if ( iterator.itemIndex_ == 0 )
+   {
+      JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." );
+      if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] )
+      {
+         JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." );
+         --(iterator.bucketIndex_);
+      }
+      iterator.link_ = iterator.link_->previous_;
+      iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1;
+   }
+}
+
+
+const char *
+ValueInternalMap::key( const IteratorState &iterator )
+{
+   JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
+   return iterator.link_->keys_[iterator.itemIndex_];
+}
+
+const char *
+ValueInternalMap::key( const IteratorState &iterator, bool &isStatic )
+{
+   JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
+   isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic();
+   return iterator.link_->keys_[iterator.itemIndex_];
+}
+
+
+Value &
+ValueInternalMap::value( const IteratorState &iterator )
+{
+   JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
+   return iterator.link_->items_[iterator.itemIndex_];
+}
+
+
+int 
+ValueInternalMap::distance( const IteratorState &x, const IteratorState &y )
+{
+   int offset = 0;
+   IteratorState it = x;
+   while ( !equals( it, y ) )
+      increment( it );
+   return offset;
+}
diff --git a/src/json/json_reader.cpp b/src/json/json_reader.cpp
new file mode 100644 (file)
index 0000000..c0a863c
--- /dev/null
@@ -0,0 +1,731 @@
+#include <json/reader.h>
+#include <json/value.h>
+#include <utility>
+#include <cstdio>
+#include <cassert>
+#include <cstring>
+#include <iostream>
+#include <stdexcept>
+
+#if _MSC_VER >= 1400 // VC++ 8.0
+#pragma warning( disable : 4996 )   // disable warning about strdup being deprecated.
+#endif
+
+namespace Json {
+
+// Implementation of class Features
+// ////////////////////////////////
+
+Features::Features() :
+               allowComments_(true), strictRoot_(false) {
+}
+
+Features Features::all() {
+       return Features();
+}
+
+Features Features::strictMode() {
+       Features features;
+       features.allowComments_ = false;
+       features.strictRoot_ = true;
+       return features;
+}
+
+// Implementation of class Reader
+// ////////////////////////////////
+
+static inline bool in(Reader::Char c, Reader::Char c1, Reader::Char c2,
+               Reader::Char c3, Reader::Char c4) {
+       return c == c1 || c == c2 || c == c3 || c == c4;
+}
+
+static inline bool in(Reader::Char c, Reader::Char c1, Reader::Char c2,
+               Reader::Char c3, Reader::Char c4, Reader::Char c5) {
+       return c == c1 || c == c2 || c == c3 || c == c4 || c == c5;
+}
+
+static bool containsNewLine(Reader::Location begin, Reader::Location end) {
+       for (; begin < end; ++begin)
+               if (*begin == '\n' || *begin == '\r')
+                       return true;
+       return false;
+}
+
+static std::string codePointToUTF8(unsigned int cp) {
+       std::string result;
+
+       // based on description from http://en.wikipedia.org/wiki/UTF-8
+
+       if (cp <= 0x7f) {
+               result.resize(1);
+               result[0] = static_cast<char>(cp);
+       } else if (cp <= 0x7FF) {
+               result.resize(2);
+               result[1] = static_cast<char>(0x80 | (0x3f & cp));
+               result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
+       } else if (cp <= 0xFFFF) {
+               result.resize(3);
+               result[2] = static_cast<char>(0x80 | (0x3f & cp));
+               result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));
+               result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));
+       } else if (cp <= 0x10FFFF) {
+               result.resize(4);
+               result[3] = static_cast<char>(0x80 | (0x3f & cp));
+               result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
+               result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
+               result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
+       }
+
+       return result;
+}
+
+// Class Reader
+// //////////////////////////////////////////////////////////////////
+
+Reader::Reader() :
+               features_(Features::all()) {
+}
+
+Reader::Reader(const Features &features) :
+               features_(features) {
+}
+
+bool Reader::parse(const std::string &document, Value &root,
+               bool collectComments) {
+       document_ = document;
+       const char *begin = document_.c_str();
+       const char *end = begin + document_.length();
+       return parse(begin, end, root, collectComments);
+}
+
+bool Reader::parse(std::istream& sin, Value &root, bool collectComments) {
+       //std::istream_iterator<char> begin(sin);
+       //std::istream_iterator<char> end;
+       // Those would allow streamed input from a file, if parse() were a
+       // template function.
+
+       // Since std::string is reference-counted, this at least does not
+       // create an extra copy.
+       std::string doc;
+       std::getline(sin, doc, (char) EOF);
+       return parse(doc, root, collectComments);
+}
+
+bool Reader::parse(const char *beginDoc, const char *endDoc, Value &root,
+               bool collectComments) {
+       if (!features_.allowComments_) {
+               collectComments = false;
+       }
+
+       begin_ = beginDoc;
+       end_ = endDoc;
+       collectComments_ = collectComments;
+       current_ = begin_;
+       lastValueEnd_ = 0;
+       lastValue_ = 0;
+       commentsBefore_ = "";
+       errors_.clear();
+       while (!nodes_.empty())
+               nodes_.pop();
+       nodes_.push(&root);
+
+       bool successful = readValue();
+       Token token;
+       skipCommentTokens(token);
+       if (collectComments_ && !commentsBefore_.empty())
+               root.setComment(commentsBefore_, commentAfter);
+       if (features_.strictRoot_) {
+               if (!root.isArray() && !root.isObject()) {
+                       // Set error location to start of doc, ideally should be first token found in doc
+                       token.type_ = tokenError;
+                       token.start_ = beginDoc;
+                       token.end_ = endDoc;
+                       addError(
+                                       "A valid JSON document must be either an array or an object value.",
+                                       token);
+                       return false;
+               }
+       }
+       return successful;
+}
+
+bool Reader::readValue() {
+       Token token;
+       skipCommentTokens(token);
+       bool successful = true;
+
+       if (collectComments_ && !commentsBefore_.empty()) {
+               currentValue().setComment(commentsBefore_, commentBefore);
+               commentsBefore_ = "";
+       }
+
+       switch (token.type_) {
+       case tokenObjectBegin:
+               successful = readObject(token);
+               break;
+       case tokenArrayBegin:
+               successful = readArray(token);
+               break;
+       case tokenNumber:
+               successful = decodeNumber(token);
+               break;
+       case tokenString:
+               successful = decodeString(token);
+               break;
+       case tokenTrue:
+               currentValue() = true;
+               break;
+       case tokenFalse:
+               currentValue() = false;
+               break;
+       case tokenNull:
+               currentValue() = Value();
+               break;
+       default:
+               return addError("Syntax error: value, object or array expected.", token);
+       }
+
+       if (collectComments_) {
+               lastValueEnd_ = current_;
+               lastValue_ = &currentValue();
+       }
+
+       return successful;
+}
+
+void Reader::skipCommentTokens(Token &token) {
+       if (features_.allowComments_) {
+               do {
+                       readToken(token);
+               } while (token.type_ == tokenComment);
+       } else {
+               readToken(token);
+       }
+}
+
+bool Reader::expectToken(TokenType type, Token &token, const char *message) {
+       readToken(token);
+       if (token.type_ != type)
+               return addError(message, token);
+       return true;
+}
+
+bool Reader::readToken(Token &token) {
+       skipSpaces();
+       token.start_ = current_;
+       Char c = getNextChar();
+       bool ok = true;
+       switch (c) {
+       case '{':
+               token.type_ = tokenObjectBegin;
+               break;
+       case '}':
+               token.type_ = tokenObjectEnd;
+               break;
+       case '[':
+               token.type_ = tokenArrayBegin;
+               break;
+       case ']':
+               token.type_ = tokenArrayEnd;
+               break;
+       case '"':
+               token.type_ = tokenString;
+               ok = readString();
+               break;
+       case '/':
+               token.type_ = tokenComment;
+               ok = readComment();
+               break;
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case '-':
+               token.type_ = tokenNumber;
+               readNumber();
+               break;
+       case 't':
+               token.type_ = tokenTrue;
+               ok = match("rue", 3);
+               break;
+       case 'f':
+               token.type_ = tokenFalse;
+               ok = match("alse", 4);
+               break;
+       case 'n':
+               token.type_ = tokenNull;
+               ok = match("ull", 3);
+               break;
+       case ',':
+               token.type_ = tokenArraySeparator;
+               break;
+       case ':':
+               token.type_ = tokenMemberSeparator;
+               break;
+       case 0:
+               token.type_ = tokenEndOfStream;
+               break;
+       default:
+               ok = false;
+               break;
+       }
+       if (!ok)
+               token.type_ = tokenError;
+       token.end_ = current_;
+       return true;
+}
+
+void Reader::skipSpaces() {
+       while (current_ != end_) {
+               Char c = *current_;
+               if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
+                       ++current_;
+               else
+                       break;
+       }
+}
+
+bool Reader::match(Location pattern, int patternLength) {
+       if (end_ - current_ < patternLength)
+               return false;
+       int index = patternLength;
+       while (index--)
+               if (current_[index] != pattern[index])
+                       return false;
+       current_ += patternLength;
+       return true;
+}
+
+bool Reader::readComment() {
+       Location commentBegin = current_ - 1;
+       Char c = getNextChar();
+       bool successful = false;
+       if (c == '*')
+               successful = readCStyleComment();
+       else if (c == '/')
+               successful = readCppStyleComment();
+       if (!successful)
+               return false;
+
+       if (collectComments_) {
+               CommentPlacement placement = commentBefore;
+               if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
+                       if (c != '*' || !containsNewLine(commentBegin, current_))
+                               placement = commentAfterOnSameLine;
+               }
+
+               addComment(commentBegin, current_, placement);
+       }
+       return true;
+}
+
+void Reader::addComment(Location begin, Location end,
+               CommentPlacement placement) {
+       assert(collectComments_);
+       if (placement == commentAfterOnSameLine) {
+               assert(lastValue_ != 0);
+               lastValue_->setComment(std::string(begin, end), placement);
+       } else {
+               if (!commentsBefore_.empty())
+                       commentsBefore_ += "\n";
+               commentsBefore_ += std::string(begin, end);
+       }
+}
+
+bool Reader::readCStyleComment() {
+       while (current_ != end_) {
+               Char c = getNextChar();
+               if (c == '*' && *current_ == '/')
+                       break;
+       }
+       return getNextChar() == '/';
+}
+
+bool Reader::readCppStyleComment() {
+       while (current_ != end_) {
+               Char c = getNextChar();
+               if (c == '\r' || c == '\n')
+                       break;
+       }
+       return true;
+}
+
+void Reader::readNumber() {
+       while (current_ != end_) {
+               if (!(*current_ >= '0' && *current_ <= '9')
+                               && !in(*current_, '.', 'e', 'E', '+', '-'))
+                       break;
+               ++current_;
+       }
+}
+
+bool Reader::readString() {
+       Char c = 0;
+       while (current_ != end_) {
+               c = getNextChar();
+               if (c == '\\')
+                       getNextChar();
+               else if (c == '"')
+                       break;
+       }
+       return c == '"';
+}
+
+bool Reader::readObject(Token &tokenStart) {
+       Token tokenName;
+       std::string name;
+       currentValue() = Value(objectValue);
+       while (readToken(tokenName)) {
+               bool initialTokenOk = true;
+               while (tokenName.type_ == tokenComment && initialTokenOk)
+                       initialTokenOk = readToken(tokenName);
+               if (!initialTokenOk)
+                       break;
+               if (tokenName.type_ == tokenObjectEnd && name.empty())  // empty object
+                       return true;
+               if (tokenName.type_ != tokenString)
+                       break;
+
+               name = "";
+               if (!decodeString(tokenName, name))
+                       return recoverFromError(tokenObjectEnd);
+
+               Token colon;
+               if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
+                       return addErrorAndRecover("Missing ':' after object member name",
+                                       colon, tokenObjectEnd);
+               }
+               Value &value = currentValue()[name];
+               nodes_.push(&value);
+               bool ok = readValue();
+               nodes_.pop();
+               if (!ok) // error already set
+                       return recoverFromError(tokenObjectEnd);
+
+               Token comma;
+               if (!readToken(comma)
+                               || (comma.type_ != tokenObjectEnd
+                                               && comma.type_ != tokenArraySeparator
+                                               && comma.type_ != tokenComment)) {
+                       return addErrorAndRecover(
+                                       "Missing ',' or '}' in object declaration", comma,
+                                       tokenObjectEnd);
+               }
+               bool finalizeTokenOk = true;
+               while (comma.type_ == tokenComment && finalizeTokenOk)
+                       finalizeTokenOk = readToken(comma);
+               if (comma.type_ == tokenObjectEnd)
+                       return true;
+       }
+       return addErrorAndRecover("Missing '}' or object member name", tokenName,
+                       tokenObjectEnd);
+}
+
+bool Reader::readArray(Token &tokenStart) {
+       currentValue() = Value(arrayValue);
+       skipSpaces();
+       if (*current_ == ']') // empty array
+                       {
+               Token endArray;
+               readToken(endArray);
+               return true;
+       }
+       int index = 0;
+       while (true) {
+               Value &value = currentValue()[index++];
+               nodes_.push(&value);
+               bool ok = readValue();
+               nodes_.pop();
+               if (!ok) // error already set
+                       return recoverFromError(tokenArrayEnd);
+
+               Token token;
+               // Accept Comment after last item in the array.
+               ok = readToken(token);
+               while (token.type_ == tokenComment && ok) {
+                       ok = readToken(token);
+               }
+               bool badTokenType = (token.type_ == tokenArraySeparator
+                               && token.type_ == tokenArrayEnd);
+               if (!ok || badTokenType) {
+                       return addErrorAndRecover("Missing ',' or ']' in array declaration",
+                                       token, tokenArrayEnd);
+               }
+               if (token.type_ == tokenArrayEnd)
+                       break;
+       }
+       return true;
+}
+
+bool Reader::decodeNumber(Token &token) {
+       bool isDouble = false;
+       for (Location inspect = token.start_; inspect != token.end_; ++inspect) {
+               isDouble = isDouble || in(*inspect, '.', 'e', 'E', '+')
+                               || (*inspect == '-' && inspect != token.start_);
+       }
+       if (isDouble)
+               return decodeDouble(token);
+       Location current = token.start_;
+       bool isNegative = *current == '-';
+       if (isNegative)
+               ++current;
+       Value::UInt threshold = (
+                       isNegative ? Value::UInt(-Value::minInt) : Value::maxUInt) / 10;
+       Value::UInt value = 0;
+       while (current < token.end_) {
+               Char c = *current++;
+               if (c < '0' || c > '9')
+                       return addError(
+                                       "'" + std::string(token.start_, token.end_)
+                                                       + "' is not a number.", token);
+               if (value >= threshold)
+                       return decodeDouble(token);
+               value = value * 10 + Value::UInt(c - '0');
+       }
+       if (isNegative)
+               currentValue() = -Value::Int(value);
+       else if (value <= Value::UInt(Value::maxInt))
+               currentValue() = Value::Int(value);
+       else
+               currentValue() = value;
+       return true;
+}
+
+bool Reader::decodeDouble(Token &token) {
+       double value = 0;
+       const int bufferSize = 32;
+       int count;
+       int length = int(token.end_ - token.start_);
+       if (length <= bufferSize) {
+               Char buffer[bufferSize];
+               memcpy(buffer, token.start_, length);
+               buffer[length] = 0;
+               count = sscanf(buffer, "%lf", &value);
+       } else {
+               std::string buffer(token.start_, token.end_);
+               count = sscanf(buffer.c_str(), "%lf", &value);
+       }
+
+       if (count != 1)
+               return addError(
+                               "'" + std::string(token.start_, token.end_)
+                                               + "' is not a number.", token);
+       currentValue() = value;
+       return true;
+}
+
+bool Reader::decodeString(Token &token) {
+       std::string decoded;
+       if (!decodeString(token, decoded))
+               return false;
+       currentValue() = decoded;
+       return true;
+}
+
+bool Reader::decodeString(Token &token, std::string &decoded) {
+       decoded.reserve(token.end_ - token.start_ - 2);
+       Location current = token.start_ + 1; // skip '"'
+       Location end = token.end_ - 1;      // do not include '"'
+       while (current != end) {
+               Char c = *current++;
+               if (c == '"')
+                       break;
+               else if (c == '\\') {
+                       if (current == end)
+                               return addError("Empty escape sequence in string", token,
+                                               current);
+                       Char escape = *current++;
+                       switch (escape) {
+                       case '"':
+                               decoded += '"';
+                               break;
+                       case '/':
+                               decoded += '/';
+                               break;
+                       case '\\':
+                               decoded += '\\';
+                               break;
+                       case 'b':
+                               decoded += '\b';
+                               break;
+                       case 'f':
+                               decoded += '\f';
+                               break;
+                       case 'n':
+                               decoded += '\n';
+                               break;
+                       case 'r':
+                               decoded += '\r';
+                               break;
+                       case 't':
+                               decoded += '\t';
+                               break;
+                       case 'u': {
+                               unsigned int unicode;
+                               if (!decodeUnicodeCodePoint(token, current, end, unicode))
+                                       return false;
+                               decoded += codePointToUTF8(unicode);
+                       }
+                               break;
+                       default:
+                               return addError("Bad escape sequence in string", token, current);
+                       }
+               } else {
+                       decoded += c;
+               }
+       }
+       return true;
+}
+
+bool Reader::decodeUnicodeCodePoint(Token &token, Location &current,
+               Location end, unsigned int &unicode) {
+
+       if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
+               return false;
+       if (unicode >= 0xD800 && unicode <= 0xDBFF) {
+               // surrogate pairs
+               if (end - current < 6)
+                       return addError(
+                                       "additional six characters expected to parse unicode surrogate pair.",
+                                       token, current);
+               unsigned int surrogatePair;
+               if (*(current++) == '\\' && *(current++) == 'u') {
+                       if (decodeUnicodeEscapeSequence(token, current, end,
+                                       surrogatePair)) {
+                               unicode = 0x10000 + ((unicode & 0x3FF) << 10)
+                                               + (surrogatePair & 0x3FF);
+                       } else
+                               return false;
+               } else
+                       return addError(
+                                       "expecting another \\u token to begin the second half of a unicode surrogate pair",
+                                       token, current);
+       }
+       return true;
+}
+
+bool Reader::decodeUnicodeEscapeSequence(Token &token, Location &current,
+               Location end, unsigned int &unicode) {
+       if (end - current < 4)
+               return addError(
+                               "Bad unicode escape sequence in string: four digits expected.",
+                               token, current);
+       unicode = 0;
+       for (int index = 0; index < 4; ++index) {
+               Char c = *current++;
+               unicode *= 16;
+               if (c >= '0' && c <= '9')
+                       unicode += c - '0';
+               else if (c >= 'a' && c <= 'f')
+                       unicode += c - 'a' + 10;
+               else if (c >= 'A' && c <= 'F')
+                       unicode += c - 'A' + 10;
+               else
+                       return addError(
+                                       "Bad unicode escape sequence in string: hexadecimal digit expected.",
+                                       token, current);
+       }
+       return true;
+}
+
+bool Reader::addError(const std::string &message, Token &token,
+               Location extra) {
+       ErrorInfo info;
+       info.token_ = token;
+       info.message_ = message;
+       info.extra_ = extra;
+       errors_.push_back(info);
+       return false;
+}
+
+bool Reader::recoverFromError(TokenType skipUntilToken) {
+       int errorCount = int(errors_.size());
+       Token skip;
+       while (true) {
+               if (!readToken(skip))
+                       errors_.resize(errorCount); // discard errors caused by recovery
+               if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
+                       break;
+       }
+       errors_.resize(errorCount);
+       return false;
+}
+
+bool Reader::addErrorAndRecover(const std::string &message, Token &token,
+               TokenType skipUntilToken) {
+       addError(message, token);
+       return recoverFromError(skipUntilToken);
+}
+
+Value &
+Reader::currentValue() {
+       return *(nodes_.top());
+}
+
+Reader::Char Reader::getNextChar() {
+       if (current_ == end_)
+               return 0;
+       return *current_++;
+}
+
+void Reader::getLocationLineAndColumn(Location location, int &line,
+               int &column) const {
+       Location current = begin_;
+       Location lastLineStart = current;
+       line = 0;
+       while (current < location && current != end_) {
+               Char c = *current++;
+               if (c == '\r') {
+                       if (*current == '\n')
+                               ++current;
+                       lastLineStart = current;
+                       ++line;
+               } else if (c == '\n') {
+                       lastLineStart = current;
+                       ++line;
+               }
+       }
+       // column & line start at 1
+       column = int(location - lastLineStart) + 1;
+       ++line;
+}
+
+std::string Reader::getLocationLineAndColumn(Location location) const {
+       int line, column;
+       getLocationLineAndColumn(location, line, column);
+       char buffer[18 + 16 + 16 + 1];
+       sprintf(buffer, "Line %d, Column %d", line, column);
+       return buffer;
+}
+
+std::string Reader::getFormatedErrorMessages() const {
+       std::string formattedMessage;
+       for (Errors::const_iterator itError = errors_.begin();
+                       itError != errors_.end(); ++itError) {
+               const ErrorInfo &error = *itError;
+               formattedMessage += "* " + getLocationLineAndColumn(error.token_.start_)
+                               + "\n";
+               formattedMessage += "  " + error.message_ + "\n";
+               if (error.extra_)
+                       formattedMessage += "See " + getLocationLineAndColumn(error.extra_)
+                                       + " for detail.\n";
+       }
+       return formattedMessage;
+}
+
+std::istream& operator>>(std::istream &sin, Value &root) {
+       Json::Reader reader;
+       bool ok = reader.parse(sin, root, true);
+       //JSON_ASSERT( ok );
+       if (!ok)
+               throw std::runtime_error(reader.getFormatedErrorMessages());
+       return sin;
+}
+
+} // namespace Json
diff --git a/src/json/json_value.cpp b/src/json/json_value.cpp
new file mode 100644 (file)
index 0000000..17c8dc4
--- /dev/null
@@ -0,0 +1,1418 @@
+#include <iostream>
+#include <json/value.h>
+#include <json/writer.h>
+#include <utility>
+#include <stdexcept>
+#include <cstring>
+#include <cassert>
+#ifdef JSON_USE_CPPTL
+# include <cpptl/conststring.h>
+#endif
+#include <cstddef>    // size_t
+#ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+# include "json_batchallocator.h"
+#endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+#define JSON_ASSERT_UNREACHABLE assert( false )
+#define JSON_ASSERT( condition ) assert( condition );  // @todo <= change this into an exception throw
+#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) throw std::runtime_error( message );
+
+namespace Json {
+
+const Value Value::null;
+const Int Value::minInt = Int(~(UInt(-1) / 2));
+const Int Value::maxInt = Int(UInt(-1) / 2);
+const UInt Value::maxUInt = UInt(-1);
+
+// A "safe" implementation of strdup. Allow null pointer to be passed. 
+// Also avoid warning on msvc80.
+//
+//inline char *safeStringDup( const char *czstring )
+//{
+//   if ( czstring )
+//   {
+//      const size_t length = (unsigned int)( strlen(czstring) + 1 );
+//      char *newString = static_cast<char *>( malloc( length ) );
+//      memcpy( newString, czstring, length );
+//      return newString;
+//   }
+//   return 0;
+//}
+//
+//inline char *safeStringDup( const std::string &str )
+//{
+//   if ( !str.empty() )
+//   {
+//      const size_t length = str.length();
+//      char *newString = static_cast<char *>( malloc( length + 1 ) );
+//      memcpy( newString, str.c_str(), length );
+//      newString[length] = 0;
+//      return newString;
+//   }
+//   return 0;
+//}
+
+ValueAllocator::~ValueAllocator() {
+}
+
+class DefaultValueAllocator: public ValueAllocator {
+public:
+       virtual ~DefaultValueAllocator() {
+       }
+
+       virtual char *makeMemberName(const char *memberName) {
+               return duplicateStringValue(memberName);
+       }
+
+       virtual void releaseMemberName(char *memberName) {
+               releaseStringValue(memberName);
+       }
+
+       virtual char *duplicateStringValue(const char *value, unsigned int length =
+                       unknown) {
+               //@todo invesgate this old optimization
+               //if ( !value  ||  value[0] == 0 )
+               //   return 0;
+
+               if (length == unknown)
+                       length = (unsigned int) strlen(value);
+               char *newString = static_cast<char *>(malloc(length + 1));
+               memcpy(newString, value, length);
+               newString[length] = 0;
+               return newString;
+       }
+
+       virtual void releaseStringValue(char *value) {
+               if (value)
+                       free(value);
+       }
+};
+
+static ValueAllocator *&valueAllocator() {
+       static DefaultValueAllocator defaultAllocator;
+       static ValueAllocator *valueAllocator = &defaultAllocator;
+       return valueAllocator;
+}
+
+static struct DummyValueAllocatorInitializer {
+       DummyValueAllocatorInitializer() {
+               valueAllocator(); // ensure valueAllocator() statics are initialized before main().
+       }
+} dummyValueAllocatorInitializer;
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// ValueInternals...
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+# include "json_internalarray.inl"
+# include "json_internalmap.inl"
+#endif // JSON_VALUE_USE_INTERNAL_MAP
+# include "json_valueiterator.inl"
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::CommentInfo
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+Value::CommentInfo::CommentInfo() :
+               comment_(0) {
+}
+
+Value::CommentInfo::~CommentInfo() {
+       if (comment_)
+               valueAllocator()->releaseStringValue(comment_);
+}
+
+void Value::CommentInfo::setComment(const char *text) {
+       if (comment_)
+               valueAllocator()->releaseStringValue(comment_);
+       JSON_ASSERT(text);
+       JSON_ASSERT_MESSAGE(text[0] == '\0' || text[0] == '/',
+                       "Comments must start with /");
+       // It seems that /**/ style comments are acceptable as well.
+       comment_ = valueAllocator()->duplicateStringValue(text);
+}
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::CZString
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+# ifndef JSON_VALUE_USE_INTERNAL_MAP
+
+// Notes: index_ indicates if the string was allocated when
+// a string is stored.
+
+Value::CZString::CZString(int index) :
+               cstr_(0), index_(index) {
+}
+
+Value::CZString::CZString(const char *cstr, DuplicationPolicy allocate) :
+               cstr_(
+                               allocate == duplicate ?
+                                               valueAllocator()->makeMemberName(cstr) : cstr), index_(
+                               allocate) {
+}
+
+Value::CZString::CZString(const CZString &other) :
+               cstr_(
+                               other.index_ != noDuplication && other.cstr_ != 0 ?
+                                               valueAllocator()->makeMemberName(other.cstr_) :
+                                               other.cstr_), index_(
+                               other.cstr_ ?
+                                               (other.index_ == noDuplication ?
+                                                               noDuplication : duplicate) :
+                                               other.index_) {
+}
+
+Value::CZString::~CZString() {
+       if (cstr_ && index_ == duplicate)
+               valueAllocator()->releaseMemberName(const_cast<char *>(cstr_));
+}
+
+void Value::CZString::swap(CZString &other) {
+       std::swap(cstr_, other.cstr_);
+       std::swap(index_, other.index_);
+}
+
+Value::CZString &
+Value::CZString::operator =(const CZString &other) {
+       CZString temp(other);
+       swap(temp);
+       return *this;
+}
+
+bool Value::CZString::operator<(const CZString &other) const {
+       if (cstr_)
+               return strcmp(cstr_, other.cstr_) < 0;
+       return index_ < other.index_;
+}
+
+bool Value::CZString::operator==(const CZString &other) const {
+       if (cstr_)
+               return strcmp(cstr_, other.cstr_) == 0;
+       return index_ == other.index_;
+}
+
+int Value::CZString::index() const {
+       return index_;
+}
+
+const char *
+Value::CZString::c_str() const {
+       return cstr_;
+}
+
+bool Value::CZString::isStaticString() const {
+       return index_ == noDuplication;
+}
+
+#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::Value
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+/*! \internal Default constructor initialization must be equivalent to:
+ * memset( this, 0, sizeof(Value) )
+ * This optimization is used in ValueInternalMap fast allocator.
+ */
+Value::Value(ValueType type) :
+               type_(type), allocated_(0), comments_(0)
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+, itemIsUsed_( 0 )
+#endif
+{
+       switch (type) {
+       case nullValue:
+               break;
+       case intValue:
+       case uintValue:
+               value_.int_ = 0;
+               break;
+       case realValue:
+               value_.real_ = 0.0;
+               break;
+       case stringValue:
+               value_.string_ = 0;
+               break;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+       case arrayValue:
+       case objectValue:
+               value_.map_ = new ObjectValues();
+               break;
+#else
+               case arrayValue:
+               value_.array_ = arrayAllocator()->newArray();
+               break;
+               case objectValue:
+               value_.map_ = mapAllocator()->newMap();
+               break;
+#endif
+       case booleanValue:
+               value_.bool_ = false;
+               break;
+       default:
+               JSON_ASSERT_UNREACHABLE;
+       }
+}
+
+Value::Value(Int value) :
+               type_(intValue), comments_(0)
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+, itemIsUsed_( 0 )
+#endif
+{
+       value_.int_ = value;
+}
+
+Value::Value(UInt value) :
+               type_(uintValue), comments_(0)
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+, itemIsUsed_( 0 )
+#endif
+{
+       value_.uint_ = value;
+}
+
+Value::Value(double value) :
+               type_(realValue), comments_(0)
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+, itemIsUsed_( 0 )
+#endif
+{
+       value_.real_ = value;
+}
+
+Value::Value(const char *value) :
+               type_(stringValue), allocated_(true), comments_(0)
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+, itemIsUsed_( 0 )
+#endif
+{
+       value_.string_ = valueAllocator()->duplicateStringValue(value);
+}
+
+Value::Value(const char *beginValue, const char *endValue) :
+               type_(stringValue), allocated_(true), comments_(0)
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+, itemIsUsed_( 0 )
+#endif
+{
+       value_.string_ = valueAllocator()->duplicateStringValue(beginValue,
+                       UInt(endValue - beginValue));
+}
+
+Value::Value(const std::string &value) :
+               type_(stringValue), allocated_(true), comments_(0)
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+, itemIsUsed_( 0 )
+#endif
+{
+       value_.string_ = valueAllocator()->duplicateStringValue(value.c_str(),
+                       (unsigned int) value.length());
+
+}
+
+Value::Value(const StaticString &value) :
+               type_(stringValue), allocated_(false), comments_(0)
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+, itemIsUsed_( 0 )
+#endif
+{
+       value_.string_ = const_cast<char *>(value.c_str());
+}
+
+# ifdef JSON_USE_CPPTL
+Value::Value( const CppTL::ConstString &value )
+: type_( stringValue )
+, allocated_( true )
+, comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+, itemIsUsed_( 0 )
+#endif
+{
+       value_.string_ = valueAllocator()->duplicateStringValue( value, value.length() );
+}
+# endif
+
+Value::Value(bool value) :
+               type_(booleanValue), comments_(0)
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+, itemIsUsed_( 0 )
+#endif
+{
+       value_.bool_ = value;
+}
+
+Value::Value(const Value &other) :
+               type_(other.type_), comments_(0)
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+, itemIsUsed_( 0 )
+#endif
+{
+       switch (type_) {
+       case nullValue:
+       case intValue:
+       case uintValue:
+       case realValue:
+       case booleanValue:
+               value_ = other.value_;
+               break;
+       case stringValue:
+               if (other.value_.string_) {
+                       value_.string_ = valueAllocator()->duplicateStringValue(
+                                       other.value_.string_);
+                       allocated_ = true;
+               } else
+                       value_.string_ = 0;
+               break;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+       case arrayValue:
+       case objectValue:
+               value_.map_ = new ObjectValues(*other.value_.map_);
+               break;
+#else
+               case arrayValue:
+               value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ );
+               break;
+               case objectValue:
+               value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ );
+               break;
+#endif
+       default:
+               JSON_ASSERT_UNREACHABLE;
+       }
+       if (other.comments_) {
+               comments_ = new CommentInfo[numberOfCommentPlacement];
+               for (int comment = 0; comment < numberOfCommentPlacement; ++comment) {
+                       const CommentInfo &otherComment = other.comments_[comment];
+                       if (otherComment.comment_)
+                               comments_[comment].setComment(otherComment.comment_);
+               }
+       }
+}
+
+Value::~Value() {
+       switch (type_) {
+       case nullValue:
+       case intValue:
+       case uintValue:
+       case realValue:
+       case booleanValue:
+               break;
+       case stringValue:
+               if (allocated_)
+                       valueAllocator()->releaseStringValue(value_.string_);
+               break;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+       case arrayValue:
+       case objectValue:
+               delete value_.map_;
+               break;
+#else
+               case arrayValue:
+               arrayAllocator()->destructArray( value_.array_ );
+               break;
+               case objectValue:
+               mapAllocator()->destructMap( value_.map_ );
+               break;
+#endif
+       default:
+               JSON_ASSERT_UNREACHABLE;
+       }
+
+       if (comments_)
+               delete[] comments_;
+}
+
+Value &
+Value::operator=(const Value &other) {
+       Value temp(other);
+       swap(temp);
+       return *this;
+}
+
+void Value::swap(Value &other) {
+       ValueType temp = type_;
+       type_ = other.type_;
+       other.type_ = temp;
+       std::swap(value_, other.value_);
+       int temp2 = allocated_;
+       allocated_ = other.allocated_;
+       other.allocated_ = temp2;
+}
+
+ValueType Value::type() const {
+       return type_;
+}
+
+int Value::compare(const Value &other) {
+       /*
+        int typeDelta = other.type_ - type_;
+        switch ( type_ )
+        {
+        case nullValue:
+
+        return other.type_ == type_;
+        case intValue:
+        if ( other.type_.isNumeric()
+        case uintValue:
+        case realValue:
+        case booleanValue:
+        break;
+        case stringValue,
+        break;
+        case arrayValue:
+        delete value_.array_;
+        break;
+        case objectValue:
+        delete value_.map_;
+        default:
+        JSON_ASSERT_UNREACHABLE;
+        }
+        */
+       return 0;  // unreachable
+}
+
+bool Value::operator <(const Value &other) const {
+       int typeDelta = type_ - other.type_;
+       if (typeDelta)
+               return typeDelta < 0 ? true : false;
+       switch (type_) {
+       case nullValue:
+               return false;
+       case intValue:
+               return value_.int_ < other.value_.int_;
+       case uintValue:
+               return value_.uint_ < other.value_.uint_;
+       case realValue:
+               return value_.real_ < other.value_.real_;
+       case booleanValue:
+               return value_.bool_ < other.value_.bool_;
+       case stringValue:
+               return (value_.string_ == 0 && other.value_.string_)
+                               || (other.value_.string_ && value_.string_
+                                               && strcmp(value_.string_, other.value_.string_) < 0);
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+       case arrayValue:
+       case objectValue: {
+               int delta = int(value_.map_->size() - other.value_.map_->size());
+               if (delta)
+                       return delta < 0;
+               return (*value_.map_) < (*other.value_.map_);
+       }
+#else
+               case arrayValue:
+               return value_.array_->compare( *(other.value_.array_) ) < 0;
+               case objectValue:
+               return value_.map_->compare( *(other.value_.map_) ) < 0;
+#endif
+       default:
+               JSON_ASSERT_UNREACHABLE;
+       }
+       return 0;  // unreachable
+}
+
+bool Value::operator <=(const Value &other) const {
+       return !(other > *this);
+}
+
+bool Value::operator >=(const Value &other) const {
+       return !(*this < other);
+}
+
+bool Value::operator >(const Value &other) const {
+       return other < *this;
+}
+
+bool Value::operator ==(const Value &other) const {
+       //if ( type_ != other.type_ )
+       // GCC 2.95.3 says:
+       // attempt to take address of bit-field structure member `Json::Value::type_'
+       // Beats me, but a temp solves the problem.
+       int temp = other.type_;
+       if (type_ != temp)
+               return false;
+       switch (type_) {
+       case nullValue:
+               return true;
+       case intValue:
+               return value_.int_ == other.value_.int_;
+       case uintValue:
+               return value_.uint_ == other.value_.uint_;
+       case realValue:
+               return value_.real_ == other.value_.real_;
+       case booleanValue:
+               return value_.bool_ == other.value_.bool_;
+       case stringValue:
+               return (value_.string_ == other.value_.string_)
+                               || (other.value_.string_ && value_.string_
+                                               && strcmp(value_.string_, other.value_.string_) == 0);
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+       case arrayValue:
+       case objectValue:
+               return value_.map_->size() == other.value_.map_->size()
+                               && (*value_.map_) == (*other.value_.map_);
+#else
+               case arrayValue:
+               return value_.array_->compare( *(other.value_.array_) ) == 0;
+               case objectValue:
+               return value_.map_->compare( *(other.value_.map_) ) == 0;
+#endif
+       default:
+               JSON_ASSERT_UNREACHABLE;
+       }
+       return 0;  // unreachable
+}
+
+bool Value::operator !=(const Value &other) const {
+       return !(*this == other);
+}
+
+const char *
+Value::asCString() const {
+       JSON_ASSERT(type_ == stringValue);
+       return value_.string_;
+}
+
+std::string Value::asString() const {
+       switch (type_) {
+       case nullValue:
+               return "";
+       case stringValue:
+               return value_.string_ ? value_.string_ : "";
+       case booleanValue:
+               return value_.bool_ ? "true" : "false";
+       case intValue:
+       case uintValue:
+       case realValue:
+       case arrayValue:
+       case objectValue:
+               JSON_ASSERT_MESSAGE(false, "Type is not convertible to string")
+               ;
+       default:
+               JSON_ASSERT_UNREACHABLE;
+       }
+       return ""; // unreachable
+}
+
+# ifdef JSON_USE_CPPTL
+CppTL::ConstString
+Value::asConstString() const
+{
+       return CppTL::ConstString( asString().c_str() );
+}
+# endif
+
+Value::Int Value::asInt() const {
+       switch (type_) {
+       case nullValue:
+               return 0;
+       case intValue:
+               return value_.int_;
+       case uintValue:
+               JSON_ASSERT_MESSAGE(value_.uint_ < (unsigned )maxInt,
+                               "integer out of signed integer range")
+               ;
+               return value_.uint_;
+       case realValue:
+               JSON_ASSERT_MESSAGE(value_.real_ >= minInt && value_.real_ <= maxInt,
+                               "Real out of signed integer range")
+               ;
+               return Int(value_.real_);
+       case booleanValue:
+               return value_.bool_ ? 1 : 0;
+       case stringValue:
+       case arrayValue:
+       case objectValue:
+               JSON_ASSERT_MESSAGE(false, "Type is not convertible to int")
+               ;
+       default:
+               JSON_ASSERT_UNREACHABLE;
+       }
+       return 0; // unreachable;
+}
+
+Value::UInt Value::asUInt() const {
+       switch (type_) {
+       case nullValue:
+               return 0;
+       case intValue:
+               JSON_ASSERT_MESSAGE(value_.int_ >= 0,
+                               "Negative integer can not be converted to unsigned integer")
+               ;
+               return value_.int_;
+       case uintValue:
+               return value_.uint_;
+       case realValue:
+               JSON_ASSERT_MESSAGE(value_.real_ >= 0 && value_.real_ <= maxUInt,
+                               "Real out of unsigned integer range")
+               ;
+               return UInt(value_.real_);
+       case booleanValue:
+               return value_.bool_ ? 1 : 0;
+       case stringValue:
+       case arrayValue:
+       case objectValue:
+               JSON_ASSERT_MESSAGE(false, "Type is not convertible to uint")
+               ;
+       default:
+               JSON_ASSERT_UNREACHABLE;
+       }
+       return 0; // unreachable;
+}
+
+double Value::asDouble() const {
+       switch (type_) {
+       case nullValue:
+               return 0.0;
+       case intValue:
+               return value_.int_;
+       case uintValue:
+               return value_.uint_;
+       case realValue:
+               return value_.real_;
+       case booleanValue:
+               return value_.bool_ ? 1.0 : 0.0;
+       case stringValue:
+       case arrayValue:
+       case objectValue:
+               JSON_ASSERT_MESSAGE(false, "Type is not convertible to double")
+               ;
+       default:
+               JSON_ASSERT_UNREACHABLE;
+       }
+       return 0; // unreachable;
+}
+
+bool Value::asBool() const {
+       switch (type_) {
+       case nullValue:
+               return false;
+       case intValue:
+       case uintValue:
+               return value_.int_ != 0;
+       case realValue:
+               return value_.real_ != 0.0;
+       case booleanValue:
+               return value_.bool_;
+       case stringValue:
+               return value_.string_ && value_.string_[0] != 0;
+       case arrayValue:
+       case objectValue:
+               return value_.map_->size() != 0;
+       default:
+               JSON_ASSERT_UNREACHABLE;
+       }
+       return false; // unreachable;
+}
+
+bool Value::isConvertibleTo(ValueType other) const {
+       switch (type_) {
+       case nullValue:
+               return true;
+       case intValue:
+               return (other == nullValue && value_.int_ == 0) || other == intValue
+                               || (other == uintValue && value_.int_ >= 0)
+                               || other == realValue || other == stringValue
+                               || other == booleanValue;
+       case uintValue:
+               return (other == nullValue && value_.uint_ == 0)
+                               || (other == intValue && value_.uint_ <= (unsigned) maxInt)
+                               || other == uintValue || other == realValue
+                               || other == stringValue || other == booleanValue;
+       case realValue:
+               return (other == nullValue && value_.real_ == 0.0)
+                               || (other == intValue && value_.real_ >= minInt
+                                               && value_.real_ <= maxInt)
+                               || (other == uintValue && value_.real_ >= 0
+                                               && value_.real_ <= maxUInt) || other == realValue
+                               || other == stringValue || other == booleanValue;
+       case booleanValue:
+               return (other == nullValue && value_.bool_ == false)
+                               || other == intValue || other == uintValue || other == realValue
+                               || other == stringValue || other == booleanValue;
+       case stringValue:
+               return other == stringValue
+                               || (other == nullValue
+                                               && (!value_.string_ || value_.string_[0] == 0));
+       case arrayValue:
+               return other == arrayValue
+                               || (other == nullValue && value_.map_->size() == 0);
+       case objectValue:
+               return other == objectValue
+                               || (other == nullValue && value_.map_->size() == 0);
+       default:
+               JSON_ASSERT_UNREACHABLE;
+       }
+       return false; // unreachable;
+}
+
+/// Number of values in array or object
+Value::UInt Value::size() const {
+       switch (type_) {
+       case nullValue:
+       case intValue:
+       case uintValue:
+       case realValue:
+       case booleanValue:
+       case stringValue:
+               return 0;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+       case arrayValue:  // size of the array is highest index + 1
+               if (!value_.map_->empty()) {
+                       ObjectValues::const_iterator itLast = value_.map_->end();
+                       --itLast;
+                       return (*itLast).first.index() + 1;
+               }
+               return 0;
+       case objectValue:
+               return Int(value_.map_->size());
+#else
+               case arrayValue:
+               return Int( value_.array_->size() );
+               case objectValue:
+               return Int( value_.map_->size() );
+#endif
+       default:
+               JSON_ASSERT_UNREACHABLE;
+       }
+       return 0; // unreachable;
+}
+
+bool Value::empty() const {
+       if (isNull() || isArray() || isObject())
+               return size() == 0u;
+       else
+               return false;
+}
+
+bool Value::operator!() const {
+       return isNull();
+}
+
+void Value::clear() {
+       JSON_ASSERT(
+                       type_ == nullValue || type_ == arrayValue || type_ == objectValue);
+
+       switch (type_) {
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+       case arrayValue:
+       case objectValue:
+               value_.map_->clear();
+               break;
+#else
+               case arrayValue:
+               value_.array_->clear();
+               break;
+               case objectValue:
+               value_.map_->clear();
+               break;
+#endif
+       default:
+               break;
+       }
+}
+
+void Value::resize(UInt newSize) {
+       JSON_ASSERT(type_ == nullValue || type_ == arrayValue);
+       if (type_ == nullValue)
+               *this = Value(arrayValue);
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+       UInt oldSize = size();
+       if (newSize == 0)
+               clear();
+       else if (newSize > oldSize)
+               (*this)[newSize - 1];
+       else {
+               for (UInt index = newSize; index < oldSize; ++index)
+                       value_.map_->erase(index);
+               assert(size() == newSize);
+       }
+#else
+       value_.array_->resize( newSize );
+#endif
+}
+
+Value &
+Value::operator[](UInt index) {
+       JSON_ASSERT(type_ == nullValue || type_ == arrayValue);
+       if (type_ == nullValue)
+               *this = Value(arrayValue);
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+       CZString key(index);
+       ObjectValues::iterator it = value_.map_->lower_bound(key);
+       if (it != value_.map_->end() && (*it).first == key)
+               return (*it).second;
+
+       ObjectValues::value_type defaultValue(key, null);
+       it = value_.map_->insert(it, defaultValue);
+       return (*it).second;
+#else
+       return value_.array_->resolveReference( index );
+#endif
+}
+
+const Value &
+Value::operator[](UInt index) const {
+       JSON_ASSERT(type_ == nullValue || type_ == arrayValue);
+       if (type_ == nullValue)
+               return null;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+       CZString key(index);
+       ObjectValues::const_iterator it = value_.map_->find(key);
+       if (it == value_.map_->end())
+               return null;
+       return (*it).second;
+#else
+       Value *value = value_.array_->find( index );
+       return value ? *value : null;
+#endif
+}
+
+Value &
+Value::operator[](const char *key) {
+       return resolveReference(key, false);
+}
+
+Value &
+Value::resolveReference(const char *key, bool isStatic) {
+       JSON_ASSERT(type_ == nullValue || type_ == objectValue);
+       if (type_ == nullValue)
+               *this = Value(objectValue);
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+       CZString actualKey(key,
+                       isStatic ? CZString::noDuplication : CZString::duplicateOnCopy);
+       ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
+       if (it != value_.map_->end() && (*it).first == actualKey)
+               return (*it).second;
+
+       ObjectValues::value_type defaultValue(actualKey, null);
+       it = value_.map_->insert(it, defaultValue);
+       Value &value = (*it).second;
+       return value;
+#else
+       return value_.map_->resolveReference( key, isStatic );
+#endif
+}
+
+Value Value::get(UInt index, const Value &defaultValue) const {
+       const Value *value = &((*this)[index]);
+       return value == &null ? defaultValue : *value;
+}
+
+bool Value::isValidIndex(UInt index) const {
+       return index < size();
+}
+
+const Value &
+Value::operator[](const char *key) const {
+       JSON_ASSERT(type_ == nullValue || type_ == objectValue);
+       if (type_ == nullValue)
+               return null;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+       CZString actualKey(key, CZString::noDuplication);
+       ObjectValues::const_iterator it = value_.map_->find(actualKey);
+       if (it == value_.map_->end())
+               return null;
+       return (*it).second;
+#else
+       const Value *value = value_.map_->find( key );
+       return value ? *value : null;
+#endif
+}
+
+Value &
+Value::operator[](const std::string &key) {
+       return (*this)[key.c_str()];
+}
+
+const Value &
+Value::operator[](const std::string &key) const {
+       return (*this)[key.c_str()];
+}
+
+Value &
+Value::operator[](const StaticString &key) {
+       return resolveReference(key, true);
+}
+
+# ifdef JSON_USE_CPPTL
+Value &
+Value::operator[]( const CppTL::ConstString &key )
+{
+       return (*this)[ key.c_str() ];
+}
+
+const Value &
+Value::operator[]( const CppTL::ConstString &key ) const
+{
+       return (*this)[ key.c_str() ];
+}
+# endif
+
+Value &
+Value::append(const Value &value) {
+       return (*this)[size()] = value;
+}
+
+Value Value::get(const char *key, const Value &defaultValue) const {
+       const Value *value = &((*this)[key]);
+       return value == &null ? defaultValue : *value;
+}
+
+Value Value::get(const std::string &key, const Value &defaultValue) const {
+       return get(key.c_str(), defaultValue);
+}
+
+Value Value::removeMember(const char* key) {
+       JSON_ASSERT(type_ == nullValue || type_ == objectValue);
+       if (type_ == nullValue)
+               return null;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+       CZString actualKey(key, CZString::noDuplication);
+       ObjectValues::iterator it = value_.map_->find(actualKey);
+       if (it == value_.map_->end())
+               return null;
+       Value old(it->second);
+       value_.map_->erase(it);
+       return old;
+#else
+       Value *value = value_.map_->find( key );
+       if (value) {
+               Value old(*value);
+               value_.map_.remove( key );
+               return old;
+       } else {
+               return null;
+       }
+#endif
+}
+
+Value Value::removeMember(const std::string &key) {
+       return removeMember(key.c_str());
+}
+
+# ifdef JSON_USE_CPPTL
+Value
+Value::get( const CppTL::ConstString &key,
+               const Value &defaultValue ) const
+{
+       return get( key.c_str(), defaultValue );
+}
+# endif
+
+bool Value::isMember(const char *key) const {
+       const Value *value = &((*this)[key]);
+       return value != &null;
+}
+
+bool Value::isMember(const std::string &key) const {
+       return isMember(key.c_str());
+}
+
+# ifdef JSON_USE_CPPTL
+bool
+Value::isMember( const CppTL::ConstString &key ) const
+{
+       return isMember( key.c_str() );
+}
+#endif
+
+Value::Members Value::getMemberNames() const {
+       JSON_ASSERT(type_ == nullValue || type_ == objectValue);
+       if (type_ == nullValue)
+               return Value::Members();
+       Members members;
+       members.reserve(value_.map_->size());
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+       ObjectValues::const_iterator it = value_.map_->begin();
+       ObjectValues::const_iterator itEnd = value_.map_->end();
+       for (; it != itEnd; ++it)
+               members.push_back(std::string((*it).first.c_str()));
+#else
+       ValueInternalMap::IteratorState it;
+       ValueInternalMap::IteratorState itEnd;
+       value_.map_->makeBeginIterator( it );
+       value_.map_->makeEndIterator( itEnd );
+       for (; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) )
+       members.push_back( std::string( ValueInternalMap::key( it ) ) );
+#endif
+       return members;
+}
+//
+//# ifdef JSON_USE_CPPTL
+//EnumMemberNames
+//Value::enumMemberNames() const
+//{
+//   if ( type_ == objectValue )
+//   {
+//      return CppTL::Enum::any(  CppTL::Enum::transform(
+//         CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
+//         MemberNamesTransform() ) );
+//   }
+//   return EnumMemberNames();
+//}
+//
+//
+//EnumValues 
+//Value::enumValues() const
+//{
+//   if ( type_ == objectValue  ||  type_ == arrayValue )
+//      return CppTL::Enum::anyValues( *(value_.map_), 
+//                                     CppTL::Type<const Value &>() );
+//   return EnumValues();
+//}
+//
+//# endif
+
+bool Value::isNull() const {
+       return type_ == nullValue;
+}
+
+bool Value::isBool() const {
+       return type_ == booleanValue;
+}
+
+bool Value::isInt() const {
+       return type_ == intValue;
+}
+
+bool Value::isUInt() const {
+       return type_ == uintValue;
+}
+
+bool Value::isIntegral() const {
+       return type_ == intValue || type_ == uintValue || type_ == booleanValue;
+}
+
+bool Value::isDouble() const {
+       return type_ == realValue;
+}
+
+bool Value::isNumeric() const {
+       return isIntegral() || isDouble();
+}
+
+bool Value::isString() const {
+       return type_ == stringValue;
+}
+
+bool Value::isArray() const {
+       return type_ == nullValue || type_ == arrayValue;
+}
+
+bool Value::isObject() const {
+       return type_ == nullValue || type_ == objectValue;
+}
+
+void Value::setComment(const char *comment, CommentPlacement placement) {
+       if (!comments_)
+               comments_ = new CommentInfo[numberOfCommentPlacement];
+       comments_[placement].setComment(comment);
+}
+
+void Value::setComment(const std::string &comment, CommentPlacement placement) {
+       setComment(comment.c_str(), placement);
+}
+
+bool Value::hasComment(CommentPlacement placement) const {
+       return comments_ != 0 && comments_[placement].comment_ != 0;
+}
+
+std::string Value::getComment(CommentPlacement placement) const {
+       if (hasComment(placement))
+               return comments_[placement].comment_;
+       return "";
+}
+
+std::string Value::toStyledString() const {
+       StyledWriter writer;
+       return writer.write(*this);
+}
+
+Value::const_iterator Value::begin() const {
+       switch (type_) {
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+       case arrayValue:
+       if ( value_.array_ )
+       {
+               ValueInternalArray::IteratorState it;
+               value_.array_->makeBeginIterator( it );
+               return const_iterator( it );
+       }
+       break;
+       case objectValue:
+       if ( value_.map_ )
+       {
+               ValueInternalMap::IteratorState it;
+               value_.map_->makeBeginIterator( it );
+               return const_iterator( it );
+       }
+       break;
+#else
+       case arrayValue:
+       case objectValue:
+               if (value_.map_)
+                       return const_iterator(value_.map_->begin());
+               break;
+#endif
+       default:
+               break;
+       }
+       return const_iterator();
+}
+
+Value::const_iterator Value::end() const {
+       switch (type_) {
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+       case arrayValue:
+       if ( value_.array_ )
+       {
+               ValueInternalArray::IteratorState it;
+               value_.array_->makeEndIterator( it );
+               return const_iterator( it );
+       }
+       break;
+       case objectValue:
+       if ( value_.map_ )
+       {
+               ValueInternalMap::IteratorState it;
+               value_.map_->makeEndIterator( it );
+               return const_iterator( it );
+       }
+       break;
+#else
+       case arrayValue:
+       case objectValue:
+               if (value_.map_)
+                       return const_iterator(value_.map_->end());
+               break;
+#endif
+       default:
+               break;
+       }
+       return const_iterator();
+}
+
+Value::iterator Value::begin() {
+       switch (type_) {
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+       case arrayValue:
+       if ( value_.array_ )
+       {
+               ValueInternalArray::IteratorState it;
+               value_.array_->makeBeginIterator( it );
+               return iterator( it );
+       }
+       break;
+       case objectValue:
+       if ( value_.map_ )
+       {
+               ValueInternalMap::IteratorState it;
+               value_.map_->makeBeginIterator( it );
+               return iterator( it );
+       }
+       break;
+#else
+       case arrayValue:
+       case objectValue:
+               if (value_.map_)
+                       return iterator(value_.map_->begin());
+               break;
+#endif
+       default:
+               break;
+       }
+       return iterator();
+}
+
+Value::iterator Value::end() {
+       switch (type_) {
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+       case arrayValue:
+       if ( value_.array_ )
+       {
+               ValueInternalArray::IteratorState it;
+               value_.array_->makeEndIterator( it );
+               return iterator( it );
+       }
+       break;
+       case objectValue:
+       if ( value_.map_ )
+       {
+               ValueInternalMap::IteratorState it;
+               value_.map_->makeEndIterator( it );
+               return iterator( it );
+       }
+       break;
+#else
+       case arrayValue:
+       case objectValue:
+               if (value_.map_)
+                       return iterator(value_.map_->end());
+               break;
+#endif
+       default:
+               break;
+       }
+       return iterator();
+}
+
+// class PathArgument
+// //////////////////////////////////////////////////////////////////
+
+PathArgument::PathArgument() :
+               kind_(kindNone) {
+}
+
+PathArgument::PathArgument(Value::UInt index) :
+               index_(index), kind_(kindIndex) {
+}
+
+PathArgument::PathArgument(const char *key) :
+               key_(key), kind_(kindKey) {
+}
+
+PathArgument::PathArgument(const std::string &key) :
+               key_(key.c_str()), kind_(kindKey) {
+}
+
+// class Path
+// //////////////////////////////////////////////////////////////////
+
+Path::Path(const std::string &path, const PathArgument &a1,
+               const PathArgument &a2, const PathArgument &a3, const PathArgument &a4,
+               const PathArgument &a5) {
+       InArgs in;
+       in.push_back(&a1);
+       in.push_back(&a2);
+       in.push_back(&a3);
+       in.push_back(&a4);
+       in.push_back(&a5);
+       makePath(path, in);
+}
+
+void Path::makePath(const std::string &path, const InArgs &in) {
+       const char *current = path.c_str();
+       const char *end = current + path.length();
+       InArgs::const_iterator itInArg = in.begin();
+       while (current != end) {
+               if (*current == '[') {
+                       ++current;
+                       if (*current == '%')
+                               addPathInArg(path, in, itInArg, PathArgument::kindIndex);
+                       else {
+                               Value::UInt index = 0;
+                               for (; current != end && *current >= '0' && *current <= '9';
+                                               ++current)
+                                       index = index * 10 + Value::UInt(*current - '0');
+                               args_.push_back(index);
+                       }
+                       if (current == end || *current++ != ']')
+                               invalidPath(path, int(current - path.c_str()));
+               } else if (*current == '%') {
+                       addPathInArg(path, in, itInArg, PathArgument::kindKey);
+                       ++current;
+               } else if (*current == '.') {
+                       ++current;
+               } else {
+                       const char *beginName = current;
+                       while (current != end && !strchr("[.", *current))
+                               ++current;
+                       args_.push_back(std::string(beginName, current));
+               }
+       }
+}
+
+void Path::addPathInArg(const std::string &path, const InArgs &in,
+               InArgs::const_iterator &itInArg, PathArgument::Kind kind) {
+       if (itInArg == in.end()) {
+               // Error: missing argument %d
+       } else if ((*itInArg)->kind_ != kind) {
+               // Error: bad argument type
+       } else {
+               args_.push_back(**itInArg);
+       }
+}
+
+void Path::invalidPath(const std::string &path, int location) {
+       // Error: invalid path.
+}
+
+const Value &
+Path::resolve(const Value &root) const {
+       const Value *node = &root;
+       for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
+               const PathArgument &arg = *it;
+               if (arg.kind_ == PathArgument::kindIndex) {
+                       if (!node->isArray() || node->isValidIndex(arg.index_)) {
+                               // Error: unable to resolve path (array value expected at position...
+                       }
+                       node = &((*node)[arg.index_]);
+               } else if (arg.kind_ == PathArgument::kindKey) {
+                       if (!node->isObject()) {
+                               // Error: unable to resolve path (object value expected at position...)
+                       }
+                       node = &((*node)[arg.key_]);
+                       if (node == &Value::null) {
+                               // Error: unable to resolve path (object has no member named '' at position...)
+                       }
+               }
+       }
+       return *node;
+}
+
+Value Path::resolve(const Value &root, const Value &defaultValue) const {
+       const Value *node = &root;
+       for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
+               const PathArgument &arg = *it;
+               if (arg.kind_ == PathArgument::kindIndex) {
+                       if (!node->isArray() || node->isValidIndex(arg.index_))
+                               return defaultValue;
+                       node = &((*node)[arg.index_]);
+               } else if (arg.kind_ == PathArgument::kindKey) {
+                       if (!node->isObject())
+                               return defaultValue;
+                       node = &((*node)[arg.key_]);
+                       if (node == &Value::null)
+                               return defaultValue;
+               }
+       }
+       return *node;
+}
+
+Value &
+Path::make(Value &root) const {
+       Value *node = &root;
+       for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
+               const PathArgument &arg = *it;
+               if (arg.kind_ == PathArgument::kindIndex) {
+                       if (!node->isArray()) {
+                               // Error: node is not an array at position ...
+                       }
+                       node = &((*node)[arg.index_]);
+               } else if (arg.kind_ == PathArgument::kindKey) {
+                       if (!node->isObject()) {
+                               // Error: node is not an object at position...
+                       }
+                       node = &((*node)[arg.key_]);
+               }
+       }
+       return *node;
+}
+
+} // namespace Json
diff --git a/src/json/json_valueiterator.inl b/src/json/json_valueiterator.inl
new file mode 100644 (file)
index 0000000..736e260
--- /dev/null
@@ -0,0 +1,292 @@
+// included by json_value.cpp
+// everything is within Json namespace
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueIteratorBase
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueIteratorBase::ValueIteratorBase()
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   : current_()
+   , isNull_( true )
+{
+}
+#else
+   : isArray_( true )
+   , isNull_( true )
+{
+   iterator_.array_ = ValueInternalArray::IteratorState();
+}
+#endif
+
+
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator &current )
+   : current_( current )
+   , isNull_( false )
+{
+}
+#else
+ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state )
+   : isArray_( true )
+{
+   iterator_.array_ = state;
+}
+
+
+ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state )
+   : isArray_( false )
+{
+   iterator_.map_ = state;
+}
+#endif
+
+Value &
+ValueIteratorBase::deref() const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   return current_->second;
+#else
+   if ( isArray_ )
+      return ValueInternalArray::dereference( iterator_.array_ );
+   return ValueInternalMap::value( iterator_.map_ );
+#endif
+}
+
+
+void 
+ValueIteratorBase::increment()
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   ++current_;
+#else
+   if ( isArray_ )
+      ValueInternalArray::increment( iterator_.array_ );
+   ValueInternalMap::increment( iterator_.map_ );
+#endif
+}
+
+
+void 
+ValueIteratorBase::decrement()
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   --current_;
+#else
+   if ( isArray_ )
+      ValueInternalArray::decrement( iterator_.array_ );
+   ValueInternalMap::decrement( iterator_.map_ );
+#endif
+}
+
+
+ValueIteratorBase::difference_type 
+ValueIteratorBase::computeDistance( const SelfType &other ) const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+# ifdef JSON_USE_CPPTL_SMALLMAP
+   return current_ - other.current_;
+# else
+   // Iterator for null value are initialized using the default
+   // constructor, which initialize current_ to the default
+   // std::map::iterator. As begin() and end() are two instance 
+   // of the default std::map::iterator, they can not be compared.
+   // To allow this, we handle this comparison specifically.
+   if ( isNull_  &&  other.isNull_ )
+   {
+      return 0;
+   }
+
+
+   // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL,
+   // which is the one used by default).
+   // Using a portable hand-made version for non random iterator instead:
+   //   return difference_type( std::distance( current_, other.current_ ) );
+   difference_type myDistance = 0;
+   for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it )
+   {
+      ++myDistance;
+   }
+   return myDistance;
+# endif
+#else
+   if ( isArray_ )
+      return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ );
+   return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ );
+#endif
+}
+
+
+bool 
+ValueIteratorBase::isEqual( const SelfType &other ) const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   if ( isNull_ )
+   {
+      return other.isNull_;
+   }
+   return current_ == other.current_;
+#else
+   if ( isArray_ )
+      return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ );
+   return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ );
+#endif
+}
+
+
+void 
+ValueIteratorBase::copy( const SelfType &other )
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   current_ = other.current_;
+#else
+   if ( isArray_ )
+      iterator_.array_ = other.iterator_.array_;
+   iterator_.map_ = other.iterator_.map_;
+#endif
+}
+
+
+Value 
+ValueIteratorBase::key() const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   const Value::CZString czstring = (*current_).first;
+   if ( czstring.c_str() )
+   {
+      if ( czstring.isStaticString() )
+         return Value( StaticString( czstring.c_str() ) );
+      return Value( czstring.c_str() );
+   }
+   return Value( czstring.index() );
+#else
+   if ( isArray_ )
+      return Value( ValueInternalArray::indexOf( iterator_.array_ ) );
+   bool isStatic;
+   const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic );
+   if ( isStatic )
+      return Value( StaticString( memberName ) );
+   return Value( memberName );
+#endif
+}
+
+
+UInt 
+ValueIteratorBase::index() const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   const Value::CZString czstring = (*current_).first;
+   if ( !czstring.c_str() )
+      return czstring.index();
+   return Value::UInt( -1 );
+#else
+   if ( isArray_ )
+      return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) );
+   return Value::UInt( -1 );
+#endif
+}
+
+
+const char *
+ValueIteratorBase::memberName() const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   const char *name = (*current_).first.c_str();
+   return name ? name : "";
+#else
+   if ( !isArray_ )
+      return ValueInternalMap::key( iterator_.map_ );
+   return "";
+#endif
+}
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueConstIterator
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueConstIterator::ValueConstIterator()
+{
+}
+
+
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator &current )
+   : ValueIteratorBase( current )
+{
+}
+#else
+ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state )
+   : ValueIteratorBase( state )
+{
+}
+
+ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state )
+   : ValueIteratorBase( state )
+{
+}
+#endif
+
+ValueConstIterator &
+ValueConstIterator::operator =( const ValueIteratorBase &other )
+{
+   copy( other );
+   return *this;
+}
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueIterator
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueIterator::ValueIterator()
+{
+}
+
+
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ValueIterator::ValueIterator( const Value::ObjectValues::iterator &current )
+   : ValueIteratorBase( current )
+{
+}
+#else
+ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state )
+   : ValueIteratorBase( state )
+{
+}
+
+ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state )
+   : ValueIteratorBase( state )
+{
+}
+#endif
+
+ValueIterator::ValueIterator( const ValueConstIterator &other )
+   : ValueIteratorBase( other )
+{
+}
+
+ValueIterator::ValueIterator( const ValueIterator &other )
+   : ValueIteratorBase( other )
+{
+}
+
+ValueIterator &
+ValueIterator::operator =( const SelfType &other )
+{
+   copy( other );
+   return *this;
+}
diff --git a/src/json/json_writer.cpp b/src/json/json_writer.cpp
new file mode 100644 (file)
index 0000000..2179e5a
--- /dev/null
@@ -0,0 +1,675 @@
+#include <json/writer.h>
+#include <utility>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+
+#if _MSC_VER >= 1400 // VC++ 8.0
+#pragma warning( disable : 4996 )   // disable warning about strdup being deprecated.
+#endif
+
+namespace Json {
+
+static bool isControlCharacter(char ch) {
+       return ch > 0 && ch <= 0x1F;
+}
+
+static bool containsControlCharacter(const char* str) {
+       while (*str) {
+               if (isControlCharacter(*(str++)))
+                       return true;
+       }
+       return false;
+}
+static void uintToString(unsigned int value, char *&current) {
+       *--current = 0;
+       do {
+               *--current = (value % 10) + '0';
+               value /= 10;
+       } while (value != 0);
+}
+
+std::string valueToString(Int value) {
+       char buffer[32];
+       char *current = buffer + sizeof(buffer);
+       bool isNegative = value < 0;
+       if (isNegative)
+               value = -value;
+       uintToString(UInt(value), current);
+       if (isNegative)
+               *--current = '-';
+       assert(current >= buffer);
+       return current;
+}
+
+std::string valueToString(UInt value) {
+       char buffer[32];
+       char *current = buffer + sizeof(buffer);
+       uintToString(value, current);
+       assert(current >= buffer);
+       return current;
+}
+
+std::string valueToString(double value) {
+       char buffer[32];
+#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. 
+       sprintf_s(buffer, sizeof(buffer), "%#.16g", value);
+#else  
+       sprintf(buffer, "%#.16g", value);
+#endif
+       char* ch = buffer + strlen(buffer) - 1;
+       if (*ch != '0')
+               return buffer; // nothing to truncate, so save time
+       while (ch > buffer && *ch == '0') {
+               --ch;
+       }
+       char* last_nonzero = ch;
+       while (ch >= buffer) {
+               switch (*ch) {
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+                       --ch;
+                       continue;
+               case '.':
+                       // Truncate zeroes to save bytes in output, but keep one.
+                       *(last_nonzero + 2) = '\0';
+                       return buffer;
+               default:
+                       return buffer;
+               }
+       }
+       return buffer;
+}
+
+std::string valueToString(bool value) {
+       return value ? "true" : "false";
+}
+
+std::string valueToQuotedString(const char *value) {
+       // Not sure how to handle unicode...
+       if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL
+                       && !containsControlCharacter(value))
+               return std::string("\"") + value + "\"";
+       // We have to walk value and escape any special characters.
+       // Appending to std::string is not efficient, but this should be rare.
+       // (Note: forward slashes are *not* rare, but I am not escaping them.)
+       unsigned maxsize = strlen(value) * 2 + 3; // allescaped+quotes+NULL
+       std::string result;
+       result.reserve(maxsize); // to avoid lots of mallocs
+       result += "\"";
+       for (const char* c = value; *c != 0; ++c) {
+               switch (*c) {
+               case '\"':
+                       result += "\\\"";
+                       break;
+               case '\\':
+                       result += "\\\\";
+                       break;
+               case '\b':
+                       result += "\\b";
+                       break;
+               case '\f':
+                       result += "\\f";
+                       break;
+               case '\n':
+                       result += "\\n";
+                       break;
+               case '\r':
+                       result += "\\r";
+                       break;
+               case '\t':
+                       result += "\\t";
+                       break;
+                       //case '/':
+                       // Even though \/ is considered a legal escape in JSON, a bare
+                       // slash is also legal, so I see no reason to escape it.
+                       // (I hope I am not misunderstanding something.
+                       // blep notes: actually escaping \/ may be useful in javascript to avoid </ 
+                       // sequence.
+                       // Should add a flag to allow this compatibility mode and prevent this 
+                       // sequence from occurring.
+               default:
+                       if (isControlCharacter(*c)) {
+                               std::ostringstream oss;
+                               oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
+                                               << std::setw(4) << static_cast<int>(*c);
+                               result += oss.str();
+                       } else {
+                               result += *c;
+                       }
+                       break;
+               }
+       }
+       result += "\"";
+       return result;
+}
+
+// Class Writer
+// //////////////////////////////////////////////////////////////////
+Writer::~Writer() {
+}
+
+// Class FastWriter
+// //////////////////////////////////////////////////////////////////
+
+FastWriter::FastWriter() :
+               yamlCompatiblityEnabled_(false) {
+}
+
+void FastWriter::enableYAMLCompatibility() {
+       yamlCompatiblityEnabled_ = true;
+}
+
+std::string FastWriter::write(const Value &root) {
+       document_ = "";
+       writeValue(root);
+       document_ += "\n";
+       return document_;
+}
+
+void FastWriter::writeValue(const Value &value) {
+       switch (value.type()) {
+       case nullValue:
+               document_ += "null";
+               break;
+       case intValue:
+               document_ += valueToString(value.asInt());
+               break;
+       case uintValue:
+               document_ += valueToString(value.asUInt());
+               break;
+       case realValue:
+               document_ += valueToString(value.asDouble());
+               break;
+       case stringValue:
+               document_ += valueToQuotedString(value.asCString());
+               break;
+       case booleanValue:
+               document_ += valueToString(value.asBool());
+               break;
+       case arrayValue: {
+               document_ += "[";
+               int size = value.size();
+               for (int index = 0; index < size; ++index) {
+                       if (index > 0)
+                               document_ += ",";
+                       writeValue(value[index]);
+               }
+               document_ += "]";
+       }
+               break;
+       case objectValue: {
+               Value::Members members(value.getMemberNames());
+               document_ += "{";
+               for (Value::Members::iterator it = members.begin(); it != members.end();
+                               ++it) {
+                       const std::string &name = *it;
+                       if (it != members.begin())
+                               document_ += ",";
+                       document_ += valueToQuotedString(name.c_str());
+                       document_ += yamlCompatiblityEnabled_ ? ": " : ":";
+                       writeValue(value[name]);
+               }
+               document_ += "}";
+       }
+               break;
+       }
+}
+
+// Class StyledWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledWriter::StyledWriter() :
+               rightMargin_(74), indentSize_(3) {
+}
+
+std::string StyledWriter::write(const Value &root) {
+       document_ = "";
+       addChildValues_ = false;
+       indentString_ = "";
+       writeCommentBeforeValue(root);
+       writeValue(root);
+       writeCommentAfterValueOnSameLine(root);
+       document_ += "\n";
+       return document_;
+}
+
+void StyledWriter::writeValue(const Value &value) {
+       switch (value.type()) {
+       case nullValue:
+               pushValue("null");
+               break;
+       case intValue:
+               pushValue(valueToString(value.asInt()));
+               break;
+       case uintValue:
+               pushValue(valueToString(value.asUInt()));
+               break;
+       case realValue:
+               pushValue(valueToString(value.asDouble()));
+               break;
+       case stringValue:
+               pushValue(valueToQuotedString(value.asCString()));
+               break;
+       case booleanValue:
+               pushValue(valueToString(value.asBool()));
+               break;
+       case arrayValue:
+               writeArrayValue(value);
+               break;
+       case objectValue: {
+               Value::Members members(value.getMemberNames());
+               if (members.empty())
+                       pushValue("{}");
+               else {
+                       writeWithIndent("{");
+                       indent();
+                       Value::Members::iterator it = members.begin();
+                       while (true) {
+                               const std::string &name = *it;
+                               const Value &childValue = value[name];
+                               writeCommentBeforeValue(childValue);
+                               writeWithIndent(valueToQuotedString(name.c_str()));
+                               document_ += " : ";
+                               writeValue(childValue);
+                               if (++it == members.end()) {
+                                       writeCommentAfterValueOnSameLine(childValue);
+                                       break;
+                               }
+                               document_ += ",";
+                               writeCommentAfterValueOnSameLine(childValue);
+                       }
+                       unindent();
+                       writeWithIndent("}");
+               }
+       }
+               break;
+       }
+}
+
+void StyledWriter::writeArrayValue(const Value &value) {
+       unsigned size = value.size();
+       if (size == 0)
+               pushValue("[]");
+       else {
+               bool isArrayMultiLine = isMultineArray(value);
+               if (isArrayMultiLine) {
+                       writeWithIndent("[");
+                       indent();
+                       bool hasChildValue = !childValues_.empty();
+                       unsigned index = 0;
+                       while (true) {
+                               const Value &childValue = value[index];
+                               writeCommentBeforeValue(childValue);
+                               if (hasChildValue)
+                                       writeWithIndent(childValues_[index]);
+                               else {
+                                       writeIndent();
+                                       writeValue(childValue);
+                               }
+                               if (++index == size) {
+                                       writeCommentAfterValueOnSameLine(childValue);
+                                       break;
+                               }
+                               document_ += ",";
+                               writeCommentAfterValueOnSameLine(childValue);
+                       }
+                       unindent();
+                       writeWithIndent("]");
+               } else // output on a single line
+               {
+                       assert(childValues_.size() == size);
+                       document_ += "[ ";
+                       for (unsigned index = 0; index < size; ++index) {
+                               if (index > 0)
+                                       document_ += ", ";
+                               document_ += childValues_[index];
+                       }
+                       document_ += " ]";
+               }
+       }
+}
+
+bool StyledWriter::isMultineArray(const Value &value) {
+       int size = value.size();
+       bool isMultiLine = size * 3 >= rightMargin_;
+       childValues_.clear();
+       for (int index = 0; index < size && !isMultiLine; ++index) {
+               const Value &childValue = value[index];
+               isMultiLine = isMultiLine
+                               || ((childValue.isArray() || childValue.isObject())
+                                               && childValue.size() > 0);
+       }
+       if (!isMultiLine) // check if line length > max line length
+       {
+               childValues_.reserve(size);
+               addChildValues_ = true;
+               int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
+               for (int index = 0; index < size && !isMultiLine; ++index) {
+                       writeValue(value[index]);
+                       lineLength += int(childValues_[index].length());
+                       isMultiLine = isMultiLine && hasCommentForValue(value[index]);
+               }
+               addChildValues_ = false;
+               isMultiLine = isMultiLine || lineLength >= rightMargin_;
+       }
+       return isMultiLine;
+}
+
+void StyledWriter::pushValue(const std::string &value) {
+       if (addChildValues_)
+               childValues_.push_back(value);
+       else
+               document_ += value;
+}
+
+void StyledWriter::writeIndent() {
+       if (!document_.empty()) {
+               char last = document_[document_.length() - 1];
+               if (last == ' ')     // already indented
+                       return;
+               if (last != '\n')    // Comments may add new-line
+                       document_ += '\n';
+       }
+       document_ += indentString_;
+}
+
+void StyledWriter::writeWithIndent(const std::string &value) {
+       writeIndent();
+       document_ += value;
+}
+
+void StyledWriter::indent() {
+       indentString_ += std::string(indentSize_, ' ');
+}
+
+void StyledWriter::unindent() {
+       assert(int(indentString_.size()) >= indentSize_);
+       indentString_.resize(indentString_.size() - indentSize_);
+}
+
+void StyledWriter::writeCommentBeforeValue(const Value &root) {
+       if (!root.hasComment(commentBefore))
+               return;
+       document_ += normalizeEOL(root.getComment(commentBefore));
+       document_ += "\n";
+}
+
+void StyledWriter::writeCommentAfterValueOnSameLine(const Value &root) {
+       if (root.hasComment(commentAfterOnSameLine))
+               document_ += " "
+                               + normalizeEOL(root.getComment(commentAfterOnSameLine));
+
+       if (root.hasComment(commentAfter)) {
+               document_ += "\n";
+               document_ += normalizeEOL(root.getComment(commentAfter));
+               document_ += "\n";
+       }
+}
+
+bool StyledWriter::hasCommentForValue(const Value &value) {
+       return value.hasComment(commentBefore)
+                       || value.hasComment(commentAfterOnSameLine)
+                       || value.hasComment(commentAfter);
+}
+
+std::string StyledWriter::normalizeEOL(const std::string &text) {
+       std::string normalized;
+       normalized.reserve(text.length());
+       const char *begin = text.c_str();
+       const char *end = begin + text.length();
+       const char *current = begin;
+       while (current != end) {
+               char c = *current++;
+               if (c == '\r') // mac or dos EOL
+                               {
+                       if (*current == '\n') // convert dos EOL
+                               ++current;
+                       normalized += '\n';
+               } else
+                       // handle unix EOL & other char
+                       normalized += c;
+       }
+       return normalized;
+}
+
+// Class StyledStreamWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledStreamWriter::StyledStreamWriter(std::string indentation) :
+               document_(NULL), rightMargin_(74), indentation_(indentation) {
+}
+
+void StyledStreamWriter::write(std::ostream &out, const Value &root) {
+       document_ = &out;
+       addChildValues_ = false;
+       indentString_ = "";
+       writeCommentBeforeValue(root);
+       writeValue(root);
+       writeCommentAfterValueOnSameLine(root);
+       *document_ << "\n";
+       document_ = NULL; // Forget the stream, for safety.
+}
+
+void StyledStreamWriter::writeValue(const Value &value) {
+       switch (value.type()) {
+       case nullValue:
+               pushValue("null");
+               break;
+       case intValue:
+               pushValue(valueToString(value.asInt()));
+               break;
+       case uintValue:
+               pushValue(valueToString(value.asUInt()));
+               break;
+       case realValue:
+               pushValue(valueToString(value.asDouble()));
+               break;
+       case stringValue:
+               pushValue(valueToQuotedString(value.asCString()));
+               break;
+       case booleanValue:
+               pushValue(valueToString(value.asBool()));
+               break;
+       case arrayValue:
+               writeArrayValue(value);
+               break;
+       case objectValue: {
+               Value::Members members(value.getMemberNames());
+               if (members.empty())
+                       pushValue("{}");
+               else {
+                       writeWithIndent("{");
+                       indent();
+                       Value::Members::iterator it = members.begin();
+                       while (true) {
+                               const std::string &name = *it;
+                               const Value &childValue = value[name];
+                               writeCommentBeforeValue(childValue);
+                               writeWithIndent(valueToQuotedString(name.c_str()));
+                               *document_ << " : ";
+                               writeValue(childValue);
+                               if (++it == members.end()) {
+                                       writeCommentAfterValueOnSameLine(childValue);
+                                       break;
+                               }
+                               *document_ << ",";
+                               writeCommentAfterValueOnSameLine(childValue);
+                       }
+                       unindent();
+                       writeWithIndent("}");
+               }
+       }
+               break;
+       }
+}
+
+void StyledStreamWriter::writeArrayValue(const Value &value) {
+       unsigned size = value.size();
+       if (size == 0)
+               pushValue("[]");
+       else {
+               bool isArrayMultiLine = isMultineArray(value);
+               if (isArrayMultiLine) {
+                       writeWithIndent("[");
+                       indent();
+                       bool hasChildValue = !childValues_.empty();
+                       unsigned index = 0;
+                       while (true) {
+                               const Value &childValue = value[index];
+                               writeCommentBeforeValue(childValue);
+                               if (hasChildValue)
+                                       writeWithIndent(childValues_[index]);
+                               else {
+                                       writeIndent();
+                                       writeValue(childValue);
+                               }
+                               if (++index == size) {
+                                       writeCommentAfterValueOnSameLine(childValue);
+                                       break;
+                               }
+                               *document_ << ",";
+                               writeCommentAfterValueOnSameLine(childValue);
+                       }
+                       unindent();
+                       writeWithIndent("]");
+               } else // output on a single line
+               {
+                       assert(childValues_.size() == size);
+                       *document_ << "[ ";
+                       for (unsigned index = 0; index < size; ++index) {
+                               if (index > 0)
+                                       *document_ << ", ";
+                               *document_ << childValues_[index];
+                       }
+                       *document_ << " ]";
+               }
+       }
+}
+
+bool StyledStreamWriter::isMultineArray(const Value &value) {
+       int size = value.size();
+       bool isMultiLine = size * 3 >= rightMargin_;
+       childValues_.clear();
+       for (int index = 0; index < size && !isMultiLine; ++index) {
+               const Value &childValue = value[index];
+               isMultiLine = isMultiLine
+                               || ((childValue.isArray() || childValue.isObject())
+                                               && childValue.size() > 0);
+       }
+       if (!isMultiLine) // check if line length > max line length
+       {
+               childValues_.reserve(size);
+               addChildValues_ = true;
+               int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
+               for (int index = 0; index < size && !isMultiLine; ++index) {
+                       writeValue(value[index]);
+                       lineLength += int(childValues_[index].length());
+                       isMultiLine = isMultiLine && hasCommentForValue(value[index]);
+               }
+               addChildValues_ = false;
+               isMultiLine = isMultiLine || lineLength >= rightMargin_;
+       }
+       return isMultiLine;
+}
+
+void StyledStreamWriter::pushValue(const std::string &value) {
+       if (addChildValues_)
+               childValues_.push_back(value);
+       else
+               *document_ << value;
+}
+
+void StyledStreamWriter::writeIndent() {
+       /*
+        Some comments in this method would have been nice. ;-)
+
+        if ( !document_.empty() )
+        {
+        char last = document_[document_.length()-1];
+        if ( last == ' ' )     // already indented
+        return;
+        if ( last != '\n' )    // Comments may add new-line
+        *document_ << '\n';
+        }
+        */
+       *document_ << '\n' << indentString_;
+}
+
+void StyledStreamWriter::writeWithIndent(const std::string &value) {
+       writeIndent();
+       *document_ << value;
+}
+
+void StyledStreamWriter::indent() {
+       indentString_ += indentation_;
+}
+
+void StyledStreamWriter::unindent() {
+       assert(indentString_.size() >= indentation_.size());
+       indentString_.resize(indentString_.size() - indentation_.size());
+}
+
+void StyledStreamWriter::writeCommentBeforeValue(const Value &root) {
+       if (!root.hasComment(commentBefore))
+               return;
+       *document_ << normalizeEOL(root.getComment(commentBefore));
+       *document_ << "\n";
+}
+
+void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value &root) {
+       if (root.hasComment(commentAfterOnSameLine))
+               *document_
+                               << " " + normalizeEOL(root.getComment(commentAfterOnSameLine));
+
+       if (root.hasComment(commentAfter)) {
+               *document_ << "\n";
+               *document_ << normalizeEOL(root.getComment(commentAfter));
+               *document_ << "\n";
+       }
+}
+
+bool StyledStreamWriter::hasCommentForValue(const Value &value) {
+       return value.hasComment(commentBefore)
+                       || value.hasComment(commentAfterOnSameLine)
+                       || value.hasComment(commentAfter);
+}
+
+std::string StyledStreamWriter::normalizeEOL(const std::string &text) {
+       std::string normalized;
+       normalized.reserve(text.length());
+       const char *begin = text.c_str();
+       const char *end = begin + text.length();
+       const char *current = begin;
+       while (current != end) {
+               char c = *current++;
+               if (c == '\r') // mac or dos EOL
+                               {
+                       if (*current == '\n') // convert dos EOL
+                               ++current;
+                       normalized += '\n';
+               } else
+                       // handle unix EOL & other char
+                       normalized += c;
+       }
+       return normalized;
+}
+
+std::ostream& operator<<(std::ostream &sout, const Value &root) {
+       Json::StyledStreamWriter writer;
+       writer.write(sout, root);
+       return sout;
+}
+
+} // namespace Json
diff --git a/src/json/sconscript b/src/json/sconscript
new file mode 100644 (file)
index 0000000..f6520d1
--- /dev/null
@@ -0,0 +1,8 @@
+Import( 'env buildLibrary' )\r
+\r
+buildLibrary( env, Split( """\r
+    json_reader.cpp \r
+    json_value.cpp \r
+    json_writer.cpp\r
+     """ ),\r
+    'json' )\r
diff --git a/src/main/main.cpp b/src/main/main.cpp
new file mode 100644 (file)
index 0000000..f8e7bf6
--- /dev/null
@@ -0,0 +1,55 @@
+#include <string>
+#include <json/json.h>
+
+#include "httpserver.h"
+
+int gServerStatus = 0;
+int gIsRun = 0;
+
+//parse the cmd line parameters
+void parse(int count, char *argv[], HttpServer *httpserver) {
+       for (int i = 1; i < count; ++i) {
+               string argvstr = argv[i];
+               if (argvstr == "--debug"){
+                       httpserver->g_show_log = true;
+                       continue;
+               }
+               int sepindex = argvstr.find(":");
+               if (sepindex > -1) {
+                       string key = argvstr.substr(0, sepindex);
+                       string value = argvstr.substr(sepindex + 1);
+                       if (key == "--port") {
+                               httpserver->g_port = value;
+                       } else if (key == "--hidestatus") {
+                               httpserver->g_hide_status = value;
+                       } else if (key == "--testsuite") {
+                               httpserver->g_test_suite = value;
+                       } else if (key == "--exe_sequence") {
+                               httpserver->g_exe_sequence = value;
+                       } else if (key == "--enable_memory_collection") {
+                               httpserver->g_enable_memory_collection = value;
+                       } else if (key == "--external-test") {
+                               //parse the value to lancher and index_file
+                               httpserver->g_launcher = value;
+                               if (value == "wrt-launcher")
+                               {
+                                       httpserver->g_run_wiget = true;
+                                       httpserver->g_launch_cmd = httpserver->g_launcher + " -s " + httpserver->g_test_suite;
+                                       httpserver->g_kill_cmd = httpserver->g_launcher + " -k " + httpserver->g_test_suite;
+                               }
+                               else
+                                       httpserver->g_run_wiget = false;
+                       }
+               }
+       }
+}
+
+int main(int argc, char *argv[]) {
+       HttpServer httpserver;
+       if (argc > 1) {
+               parse(argc, argv, &httpserver);
+       }
+       httpserver.StartUp();
+       return 0;
+}
+
diff --git a/src/testcase.cpp b/src/testcase.cpp
new file mode 100644 (file)
index 0000000..1c942cf
--- /dev/null
@@ -0,0 +1,75 @@
+#include <string>
+#include <json/json.h>
+#include <stdlib.h>
+
+#include "testcase.h"
+
+using namespace std;
+
+TestCase::TestCase() {
+       result = "N/A";
+
+       std_out = "";
+
+       is_executed = false;
+}
+
+TestCase::~TestCase() {
+}
+
+void TestCase::init(const Json::Value value) {
+       m_case = value;
+       purpose = value["purpose"].asString(); // server will use this string directly
+       case_id = value["case_id"].asString();
+       if (value["timeout"].isString())
+               timeout_value = atoi(value["timeout"].asString().c_str());
+       else timeout_value = 90;
+}
+
+Json::Value TestCase::to_json() {
+       return m_case;
+}
+
+Json::Value TestCase::result_to_json() {
+       Json::Value root;
+
+       root["order"] = m_case["order"];
+       root["case_id"] = m_case["case_id"];
+       root["result"] = result;
+
+       if (std_out != "") {
+               root["stdout"] = std_out;
+               root["start_at"] = start_at;
+               root["end_at"] = end_at;
+       }
+
+       return root;
+}
+
+void TestCase::set_result(string test_result, string test_msg) {
+       is_executed = true;
+
+       result = test_result;
+
+       std_out = test_msg;
+
+       getCurrentTime();
+       end_at = m_str_time;
+}
+
+void TestCase::set_start_at() {
+       getCurrentTime();
+       cout << "\nstart time: " << m_str_time << endl;
+       start_at = m_str_time;
+}
+
+void TestCase::getCurrentTime() {
+       memset(m_str_time, 0, 32);
+       time_t timer;
+       struct tm* t_tm;
+       time(&timer);
+       t_tm = localtime(&timer);
+       sprintf(m_str_time, "%4d-%02d-%02d %02d:%02d:%02d", t_tm->tm_year + 1900,
+                       t_tm->tm_mon + 1, t_tm->tm_mday, t_tm->tm_hour, t_tm->tm_min,
+                       t_tm->tm_sec);
+}
\ No newline at end of file
diff --git a/src/ut/httpserver_log.txt b/src/ut/httpserver_log.txt
new file mode 100644 (file)
index 0000000..5fe4a2f
--- /dev/null
@@ -0,0 +1,290 @@
+
+[ testing xml: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.xml ]
+
+[ split xml: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1.xml by <set> ]
+[ this might take some time, please wait ]
+[ total set number is: 10 ]
+[ process set: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_1.xml ]
+[ process set: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_2.xml ]
+[ process set: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_3.xml ]
+[ process set: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_4.xml ]
+[ process set: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_5.xml ]
+[ process set: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_6.xml ]
+[ process set: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_7.xml ]
+[ process set: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_8.xml ]
+[ process set: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_9.xml ]
+[ process set: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_10.xml ]
+[ remove empty set: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_1.xml ]
+[ remove empty set: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_2.xml ]
+[ remove empty set: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_3.xml ]
+[ remove empty set: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_4.xml ]
+[ remove empty set: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_5.xml ]
+[ remove empty set: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_6.xml ]
+[ remove empty set: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_7.xml ]
+[ remove empty set: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_8.xml ]
+[ remove empty set: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_9.xml ]
+
+[ run set: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_10.xml ]
+[ split xml: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_10.xml by <case> ]
+[ this might take some time, please wait ]
+[ prepare_starup_parameters ]
+[ waiting for kill http server ]
+[ forward server http://127.0.0.1:9002 ]
+[ launch the stub app ]
+httpserver->g_test_suite is: api2contt0
+[Server is running.....]
+wrt-launcher: no process found
+[ check server status, get ready! ]
+GET /check_server_status HTTP/1.1
+Host: 127.0.0.1:9002
+Content-Length: 0
+Accept-Encoding: gzip, deflate, compress
+Accept: */*
+User-Agent: python-requests/1.1.0 CPython/2.7.3 Linux/3.5.0-27-generic
+
+
+block: 1/-1215935884, total case: 0/0, block case: 0/0, m_timeout_count:0
+server response is:{
+   "block_finished" : 0,
+   "finished" : 0
+}
+
+POST /init_test HTTP/1.1
+Host: 127.0.0.1:9002
+Content-Length: 587
+content-type: application/json
+Accept-Encoding: gzip, deflate, compress
+Accept: */*
+User-Agent: python-requests/1.1.0 CPython/2.7.3 Linux/3.5.0-27-generic
+
+{"currentBlk": "1", "totalBlk": "1", "casecount": "1", "cases": [{"onload_delay": "3", "case_id": "video_addTextTrack_base", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Check if the vedio.addTextTrack has all arguments that expected a new MutableTextTrack object is to be created and returned"}], "purpose": "Check if the vedio.addTextTrack has all arguments that expected a new MutableTextTrack object is to be created and returned", "entry": "/opt/tct-webapi-w3c-content-tests/Video/video_addTextTrack_base.html", "order": "1"}], "type": "compliance", "exetype": "auto"}
+[ init the test suite ]
+wrt-launcher -k api2contt0
+result: App isn't running
+
+[ test suite: tct-webapi-w3c-content-tests.auto.suite_1_set_10.xml, block: 1/1 , finished: 0 ]
+wrt-launcher -s api2contt0
+result: launched
+
+server response is:{"OK":1}
+GET /check_server_status HTTP/1.1
+Host: 127.0.0.1:9002
+Content-Length: 0
+Accept-Encoding: gzip, deflate, compress
+Accept: */*
+User-Agent: python-requests/1.1.0 CPython/2.7.3 Linux/3.5.0-27-generic
+
+
+block: 1/1, total case: 0/1, block case: 0/1, m_timeout_count:0
+server response is:{
+   "block_finished" : 0,
+   "finished" : 0
+}
+
+[ test suite: tct-webapi-w3c-content-tests.auto.suite_1_set_10.xml, block: 1/1 , finished: 0 ]
+GET /check_server_status HTTP/1.1
+Host: 127.0.0.1:9002
+Content-Length: 0
+Accept-Encoding: gzip, deflate, compress
+Accept: */*
+User-Agent: python-requests/1.1.0 CPython/2.7.3 Linux/3.5.0-27-generic
+
+
+block: 1/1, total case: 0/1, block case: 0/1, m_timeout_count:0
+server response is:{
+   "block_finished" : 0,
+   "finished" : 0
+}
+
+GET /check_server HTTP/1.1
+Host: 127.0.0.1:8000
+Accept-Language: en
+User-Agent: Mozilla/5.0 (Linux; U; Tizen 2.0; en-us) AppleWebKit/537.1 (KHTML, like Gecko) Version/2.0 Mobile
+Accept: */*
+Accept-Charset: iso-8859-1, utf-8, utf16, *;q=0.1
+x-Wap-Proxy-Cookie: none
+Accept-Encoding: gzip, deflate
+Connection: Keep-Alive
+
+
+[ checking server, and found the server is running ]
+server response is:{"OK":1}
+GET /init_session_id?session_id=6330 HTTP/1.1
+Host: 127.0.0.1:8000
+Accept-Language: en
+User-Agent: Mozilla/5.0 (Linux; U; Tizen 2.0; en-us) AppleWebKit/537.1 (KHTML, like Gecko) Version/2.0 Mobile
+Accept: */*
+Accept-Charset: iso-8859-1, utf-8, utf16, *;q=0.1
+x-Wap-Proxy-Cookie: none
+Accept-Encoding: gzip, deflate
+Connection: Keep-Alive
+
+
+[ sessionID: 6330 is gotten from the client ]
+server response is:{"OK":1}
+GET /auto_test_task?session_id=6330 HTTP/1.1
+Host: 127.0.0.1:8000
+Accept-Language: en
+User-Agent: Mozilla/5.0 (Linux; U; Tizen 2.0; en-us) AppleWebKit/537.1 (KHTML, like Gecko) Version/2.0 Mobile
+Accept: text/plain, */*; q=0.01
+Accept-Charset: iso-8859-1, utf-8, utf16, *;q=0.1
+x-Wap-Proxy-Cookie: none
+Accept-Encoding: gzip, deflate
+Connection: Keep-Alive
+
+
+
+start time: 1982-02-06 15:27:38
+
+[case] execute case: video_addTextTrack_base
+last_test_result: N/A
+server response is:{
+   "case_id" : "video_addTextTrack_base",
+   "entry" : "/opt/tct-webapi-w3c-content-tests/Video/video_addTextTrack_base.html",
+   "onload_delay" : "3",
+   "order" : "1",
+   "purpose" : "Check if the vedio.addTextTrack has all arguments that expected a new MutableTextTrack object is to be created and returned",
+   "steps" : [
+      {
+         "expected" : "Pass",
+         "order" : "1",
+         "step_desc" : "Check if the vedio.addTextTrack has all arguments that expected a new MutableTextTrack object is to be created and returned"
+      }
+   ]
+}
+
+GET /check_execution_progress?session_id=6330 HTTP/1.1
+Host: 127.0.0.1:8000
+Accept-Language: en
+User-Agent: Mozilla/5.0 (Linux; U; Tizen 2.0; en-us) AppleWebKit/537.1 (KHTML, like Gecko) Version/2.0 Mobile
+Accept: text/plain, */*; q=0.01
+Accept-Charset: iso-8859-1, utf-8, utf16, *;q=0.1
+x-Wap-Proxy-Cookie: none
+Accept-Encoding: gzip, deflate
+Connection: Keep-Alive
+
+
+server response is:{"total":1,"current":1,"last_test_result":"N/A"}
+GET /ask_next_step?session_id=6330 HTTP/1.1
+Host: 127.0.0.1:8000
+Accept-Language: en
+User-Agent: Mozilla/5.0 (Linux; U; Tizen 2.0; en-us) AppleWebKit/537.1 (KHTML, like Gecko) Version/2.0 Mobile
+Accept: text/plain, */*; q=0.01
+Accept-Charset: iso-8859-1, utf-8, utf16, *;q=0.1
+x-Wap-Proxy-Cookie: none
+Accept-Encoding: gzip, deflate
+Connection: Keep-Alive
+
+
+server response is:{"step":"continue"}
+POST /commit_result HTTP/1.1
+Host: 127.0.0.1:8000
+Origin: file://
+Accept-Language: en
+User-Agent: Mozilla/5.0 (Linux; U; Tizen 2.0; en-us) AppleWebKit/537.1 (KHTML, like Gecko) Version/2.0 Mobile
+Content-Type: application/x-www-form-urlencoded
+Accept: application/json, text/javascript, */*; q=0.01
+Accept-Charset: iso-8859-1, utf-8, utf16, *;q=0.1
+x-Wap-Proxy-Cookie: none
+Accept-Encoding: gzip, deflate
+Connection: Keep-Alive
+Content-Length: 177
+
+purpose=Check+if+the+vedio.addTextTrack+has+all+arguments+that+expected+a+new+MutableTextTrack+object+is+to+be+created+and+returned&result=PASS&msg=%5BMessage%5D&session_id=6330
+server response is:{"OK":1}
+GET /auto_test_task?session_id=6330 HTTP/1.1
+Host: 127.0.0.1:8000
+Accept-Language: en
+User-Agent: Mozilla/5.0 (Linux; U; Tizen 2.0; en-us) AppleWebKit/537.1 (KHTML, like Gecko) Version/2.0 Mobile
+Accept: text/plain, */*; q=0.01
+Accept-Charset: iso-8859-1, utf-8, utf16, *;q=0.1
+x-Wap-Proxy-Cookie: none
+Accept-Encoding: gzip, deflate
+Connection: Keep-Alive
+
+
+
+[ no auto case is available any more ]
+server response is:{"none":0}
+GET /manual_cases HTTP/1.1
+Host: 127.0.0.1:8000
+Accept-Language: en
+User-Agent: Mozilla/5.0 (Linux; U; Tizen 2.0; en-us) AppleWebKit/537.1 (KHTML, like Gecko) Version/2.0 Mobile
+Accept: text/plain, */*; q=0.01
+Accept-Charset: iso-8859-1, utf-8, utf16, *;q=0.1
+x-Wap-Proxy-Cookie: none
+Accept-Encoding: gzip, deflate
+Connection: Keep-Alive
+
+
+server response is:{"none":0}
+[ test suite: tct-webapi-w3c-content-tests.auto.suite_1_set_10.xml, block: 1/1 , finished: 1 ]
+GET /check_server_status HTTP/1.1
+Host: 127.0.0.1:9002
+Content-Length: 0
+Accept-Encoding: gzip, deflate, compress
+Accept: */*
+User-Agent: python-requests/1.1.0 CPython/2.7.3 Linux/3.5.0-27-generic
+
+
+block: 1/1, total case: 1/1, block case: 1/1, m_timeout_count:0
+server response is:{
+   "block_finished" : 1,
+   "finished" : 1
+}
+
+GET /get_test_result HTTP/1.1
+Host: 127.0.0.1:9002
+Content-Length: 0
+Accept-Encoding: gzip, deflate, compress
+Accept: */*
+User-Agent: python-requests/1.1.0 CPython/2.7.3 Linux/3.5.0-27-generic
+
+
+server response is:{
+   "cases" : [
+      {
+         "case_id" : "video_addTextTrack_base",
+         "end_at" : "1982-02-06 15:27:39",
+         "order" : "1",
+         "result" : "PASS",
+         "start_at" : "1982-02-06 15:27:38",
+         "stdout" : "[Message]"
+      }
+   ],
+   "count" : "1"
+}
+
+[ cases result saved to resultfile ]
+
+[ show down server ]
+GET /shut_down_server HTTP/1.1
+Host: 127.0.0.1:9002
+Content-Length: 0
+Accept-Encoding: gzip, deflate, compress
+Accept: */*
+User-Agent: python-requests/1.1.0 CPython/2.7.3 Linux/3.5.0-27-generic
+
+
+wrt-launcher: no process found
+
+[ test complete at time: 2013-04-18_16_06_12 ]
+[ start merging test result xml files,         this might take some time, please wait ]
+[ merge result files into /opt/testkit/lite/2013-04-18-16:05:48.429618/tests.result.xml ]
+|--[ merge webapi result file: /opt/testkit/lite/2013-04-18-16:05:48.429618/tct-webapi-w3c-content-tests.auto.suite_1_set_10.xml ]
+----[ suite: tct-webapi-w3c-content-tests, set: Video, time: 2013-04-18_16_06_12 ]
+[ test summary ]
+  [ total case number: 1 ]
+  [ pass rate: 100.00% ]
+  [ PASS case number: 1 ]
+  [ FAIL case number: 0 ]
+  [ BLOCK case number: 0 ]
+  [ N/A case number: 0 ]
+[ generate result xml: /opt/testkit/lite/2013-04-18-16:05:48.429618/tests.result.xml ]
+[ merge complete, write to the result file,         this might take some time, please wait ]
+wrt-launcher -k api2contt0
+result: killed
+
+server response is:{"OK":1}
+[ all tasks for testkit lite are accomplished, goodbye ]
+danny@danny-Latitude-E6400:~$ 
diff --git a/src/ut/test.json b/src/ut/test.json
new file mode 100644 (file)
index 0000000..b01c641
--- /dev/null
@@ -0,0 +1 @@
+{"currentBlk": "4", "totalBlk": "4", "casecount": "387", "cases": [{"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint16Array_setter.html", "pre_condition": "none", "case_id": "Uint16Array_setter", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify setter of Uint16Array"}], "purpose": "Verify setter of Uint16Array", "order": "301"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint16Array_set_array.html", "pre_condition": "none", "case_id": "Uint16Array_set_array", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify set(array) of Uint16Array"}], "purpose": "Verify set(array) of Uint16Array", "order": "302"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint16Array_set_array_offset.html", "pre_condition": "none", "case_id": "Uint16Array_set_array_offset", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify set(array, offset) of Uint16Array"}], "purpose": "Verify set(array, offset) of Uint16Array", "order": "303"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint16Array_set_exist.html", "pre_condition": "none", "case_id": "Uint16Array_set_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Check if the set of Uint16Array exist"}], "purpose": "Check if the set of Uint16Array exist", "order": "304"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint16Array_set_TypedArray.html", "pre_condition": "none", "case_id": "Uint16Array_set_TypedArray", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify set(typedarray) of Uint16Array"}], "purpose": "Verify set(typedarray) of Uint16Array", "order": "305"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint16Array_set_TypedArray_offset.html", "pre_condition": "none", "case_id": "Uint16Array_set_TypedArray_offset", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify set(typedarray, offset) of Uint16Array"}], "purpose": "Verify set(typedarray, offset) of Uint16Array", "order": "306"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint16Array_subarray_begin.html", "pre_condition": "none", "case_id": "Uint16Array_subarray_begin", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify subarray(begin) of Uint16Array"}], "purpose": "Verify subarray(begin) of Uint16Array", "order": "307"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint16Array_subarray_begin_end.html", "pre_condition": "none", "case_id": "Uint16Array_subarray_begin_end", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify subarray(begin, end) of Uint16Array"}], "purpose": "Verify subarray(begin, end) of Uint16Array", "order": "308"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint16Array_subarray_exist.html", "pre_condition": "none", "case_id": "Uint16Array_subarray_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Check if the subarray of Uint16Array exist"}], "purpose": "Check if the subarray of Uint16Array exist", "order": "309"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_buffer.html", "pre_condition": "none", "case_id": "Uint32Array_buffer", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify buffer of Uint32Array"}], "purpose": "Verify buffer of Uint32Array", "order": "310"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_buffer_exist.html", "pre_condition": "none", "case_id": "Uint32Array_buffer_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Check if the buffer of Uint32Array exist"}], "purpose": "Check if the buffer of Uint32Array exist", "order": "311"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_byteLength.html", "pre_condition": "none", "case_id": "Uint32Array_byteLength", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify byteLength of Uint32Array"}], "purpose": "Verify byteLength of Uint32Array", "order": "312"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_byteLength_exist.html", "pre_condition": "none", "case_id": "Uint32Array_byteLength_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Check if the byteLength of Uint32Array exist"}], "purpose": "Check if the byteLength of Uint32Array exist", "order": "313"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_byteOffset.html", "pre_condition": "none", "case_id": "Uint32Array_byteOffset", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify byteOffset of Uint32Array"}], "purpose": "Verify byteOffset of Uint32Array", "order": "314"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_byteOffset_exist.html", "pre_condition": "none", "case_id": "Uint32Array_byteOffset_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Check if the byteOffset of Uint32Array exist"}], "purpose": "Check if the byteOffset of Uint32Array exist", "order": "315"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_BYTES_PER_ELEMENT_const_4.html", "pre_condition": "none", "case_id": "Uint32Array_BYTES_PER_ELEMENT_const_4", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify BYTES_PER_ELEMENT of Uint32Array is 4"}], "purpose": "Verify BYTES_PER_ELEMENT of Uint32Array is 4", "order": "316"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_BYTES_PER_ELEMENT_exist.html", "pre_condition": "none", "case_id": "Uint32Array_BYTES_PER_ELEMENT_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Check if the BYTES_PER_ELEMENT of Uint32Array exist"}], "purpose": "Check if the BYTES_PER_ELEMENT of Uint32Array exist", "order": "317"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_constructor_array.html", "pre_condition": "none", "case_id": "Uint32Array_constructor_array", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify constructor(array) of Uint32Array"}], "purpose": "Verify constructor(array) of Uint32Array", "order": "318"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_constructor_ArrayBuffer.html", "pre_condition": "none", "case_id": "Uint32Array_constructor_ArrayBuffer", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify constructor(arraybuffer) of Uint32Array"}], "purpose": "Verify constructor(arraybuffer) of Uint32Array", "order": "319"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_constructor_ArrayBuffer_byteOffset.html", "pre_condition": "none", "case_id": "Uint32Array_constructor_ArrayBuffer_byteOffset", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify constructor(arraybuffer, byteOffset) of Uint32Array"}], "purpose": "Verify constructor(arraybuffer, byteOffset) of Uint32Array", "order": "320"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_constructor_ArrayBuffer_byteOffset_length.html", "pre_condition": "none", "case_id": "Uint32Array_constructor_ArrayBuffer_byteOffset_length", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify constructor(arraybuffer, byteOffset, length) of Uint32Array"}], "purpose": "Verify constructor(arraybuffer, byteOffset, length) of Uint32Array", "order": "321"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_constructor_length.html", "pre_condition": "none", "case_id": "Uint32Array_constructor_length", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify constructor(length) of Uint32Array"}], "purpose": "Verify constructor(length) of Uint32Array", "order": "322"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_constructor_TypedArray.html", "pre_condition": "none", "case_id": "Uint32Array_constructor_TypedArray", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify constructor(typedarray) of Uint32Array"}], "purpose": "Verify constructor(typedarray) of Uint32Array", "order": "323"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_getter.html", "pre_condition": "none", "case_id": "Uint32Array_getter", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify getter of Uint32Array"}], "purpose": "Verify getter of Uint32Array", "order": "324"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_length.html", "pre_condition": "none", "case_id": "Uint32Array_length", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify length of Uint32Array"}], "purpose": "Verify length of Uint32Array", "order": "325"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_length_exist.html", "pre_condition": "none", "case_id": "Uint32Array_length_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Check if the length of Uint32Array exist"}], "purpose": "Check if the length of Uint32Array exist", "order": "326"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_setter.html", "pre_condition": "none", "case_id": "Uint32Array_setter", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify setter of Uint32Array"}], "purpose": "Verify setter of Uint32Array", "order": "327"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_set_array.html", "pre_condition": "none", "case_id": "Uint32Array_set_array", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify set(array) of Uint32Array"}], "purpose": "Verify set(array) of Uint32Array", "order": "328"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_set_array_offset.html", "pre_condition": "none", "case_id": "Uint32Array_set_array_offset", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify set(array, offset) of Uint32Array"}], "purpose": "Verify set(array, offset) of Uint32Array", "order": "329"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_set_exist.html", "pre_condition": "none", "case_id": "Uint32Array_set_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Check if the set of Uint32Array exist"}], "purpose": "Check if the set of Uint32Array exist", "order": "330"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_set_TypedArray.html", "pre_condition": "none", "case_id": "Uint32Array_set_TypedArray", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify set(typedarray) of Uint32Array"}], "purpose": "Verify set(typedarray) of Uint32Array", "order": "331"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_set_TypedArray_offset.html", "pre_condition": "none", "case_id": "Uint32Array_set_TypedArray_offset", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify set(typedarray, offset) of Uint32Array"}], "purpose": "Verify set(typedarray, offset) of Uint32Array", "order": "332"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_subarray_begin.html", "pre_condition": "none", "case_id": "Uint32Array_subarray_begin", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify subarray(begin) of Uint32Array"}], "purpose": "Verify subarray(begin) of Uint32Array", "order": "333"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_subarray_begin_end.html", "pre_condition": "none", "case_id": "Uint32Array_subarray_begin_end", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify set(begin, end) of Uint32Array"}], "purpose": "Verify set(begin, end) of Uint32Array", "order": "334"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint32Array_subarray_exist.html", "pre_condition": "none", "case_id": "Uint32Array_subarray_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Check if the subarray of Uint32Array exist"}], "purpose": "Check if the subarray of Uint32Array exist", "order": "335"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_buffer.html", "pre_condition": "none", "case_id": "Uint8Array_buffer", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the buffer of Uint8Array"}], "purpose": "Verify the buffer of Uint8Array", "order": "336"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_buffer_exist.html", "pre_condition": "none", "case_id": "Uint8Array_buffer_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Check if the buffer of Uint8Array exist"}], "purpose": "Check if the buffer of Uint8Array exist", "order": "337"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_byteLength.html", "pre_condition": "none", "case_id": "Uint8Array_byteLength", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the byteLength of Uint8Array"}], "purpose": "Verify the byteLength of Uint8Array", "order": "338"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_byteLength_exist.html", "pre_condition": "none", "case_id": "Uint8Array_byteLength_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Check if the byteLength of Uint8Array exist"}], "purpose": "Check if the byteLength of Uint8Array exist", "order": "339"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_byteOffset.html", "pre_condition": "none", "case_id": "Uint8Array_byteOffset", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the byteOffset of Uint8Array"}], "purpose": "Verify the byteOffset of Uint8Array", "order": "340"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_byteOffset_exist.html", "pre_condition": "none", "case_id": "Uint8Array_byteOffset_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Check if the byteOffset of Uint8Array exist"}], "purpose": "Check if the byteOffset of Uint8Array exist", "order": "341"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_BYTES_PER_ELEMENT_const_1.html", "pre_condition": "none", "case_id": "Uint8Array_BYTES_PER_ELEMENT_const_1", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the BYTES_PER_ELEMENT of Uint8Array is 1"}], "purpose": "Verify the BYTES_PER_ELEMENT of Uint8Array is 1", "order": "342"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_BYTES_PER_ELEMENT_exist.html", "pre_condition": "none", "case_id": "Uint8Array_BYTES_PER_ELEMENT_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Check if the BYTES_PER_ELEMENT of Uint8Array exist"}], "purpose": "Check if the BYTES_PER_ELEMENT of Uint8Array exist", "order": "343"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_constructor_array.html", "pre_condition": "none", "case_id": "Uint8Array_constructor_array", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the constructor(array) of Uint8Array"}], "purpose": "Verify the constructor(array) of Uint8Array", "order": "344"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_constructor_ArrayBuffer.html", "pre_condition": "none", "case_id": "Uint8Array_constructor_ArrayBuffer", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the constructor(arraybuffer) of Uint8Array"}], "purpose": "Verify the constructor(arraybuffer) of Uint8Array", "order": "345"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_constructor_ArrayBuffer_byteOffSet.html", "pre_condition": "none", "case_id": "Uint8Array_constructor_ArrayBuffer_byteOffSet", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the constructor(arraybuffer, byteOffset) of Uint8Array"}], "purpose": "Verify the constructor(arraybuffer, byteOffset) of Uint8Array", "order": "346"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_constructor_ArrayBuffer_byteOffSet_length.html", "pre_condition": "none", "case_id": "Uint8Array_constructor_ArrayBuffer_byteOffSet_length", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the constructor(arraybuffer, byteOffset, length) of Uint8Array"}], "purpose": "Verify the constructor(arraybuffer, byteOffset, length) of Uint8Array", "order": "347"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_constructor_length.html", "pre_condition": "none", "case_id": "Uint8Array_constructor_length", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the constructor(length) of Uint8Array"}], "purpose": "Verify the constructor(length) of Uint8Array", "order": "348"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_constructor_TypedArray.html", "pre_condition": "none", "case_id": "Uint8Array_constructor_TypedArray", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the constructor(typedarray) of Uint8Array"}], "purpose": "Verify the constructor(typedarray) of Uint8Array", "order": "349"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_getter.html", "pre_condition": "none", "case_id": "Uint8Array_getter", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the getter of Uint8Array"}], "purpose": "Verify the getter of Uint8Array", "order": "350"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_length.html", "pre_condition": "none", "case_id": "Uint8Array_length", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the length of Uint8Array"}], "purpose": "Verify the length of Uint8Array", "order": "351"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_length_exist.html", "pre_condition": "none", "case_id": "Uint8Array_length_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Check if the length of Uint8Array exist"}], "purpose": "Check if the length of Uint8Array exist", "order": "352"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_setter.html", "pre_condition": "none", "case_id": "Uint8Array_setter", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the setter of Uint8Array"}], "purpose": "Verify the setter of Uint8Array", "order": "353"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_set_array.html", "pre_condition": "none", "case_id": "Uint8Array_set_array", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the set(array) of Uint8Array"}], "purpose": "Verify the set(array) of Uint8Array", "order": "354"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_set_array_offset.html", "pre_condition": "none", "case_id": "Uint8Array_set_array_offset", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the set(array, offset) of Uint8Array"}], "purpose": "Verify the set(array, offset) of Uint8Array", "order": "355"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_set_exist.html", "pre_condition": "none", "case_id": "Uint8Array_set_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Check if the set of Uint8Array exist"}], "purpose": "Check if the set of Uint8Array exist", "order": "356"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_set_TypedArray.html", "pre_condition": "none", "case_id": "Uint8Array_set_TypedArray", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the set(typedarray) of Uint8Array"}], "purpose": "Verify the set(typedarray) of Uint8Array", "order": "357"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_set_TypedArray_offset.html", "pre_condition": "none", "case_id": "Uint8Array_set_TypedArray_offset", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the set(typedarray, offset) of Uint8Array"}], "purpose": "Verify the set(typedarray, offset) of Uint8Array", "order": "358"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_subarray_begin.html", "pre_condition": "none", "case_id": "Uint8Array_subarray_begin", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the subarray(begin) of Uint8Array"}], "purpose": "Verify the subarray(begin) of Uint8Array", "order": "359"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_subarray_begin_end.html", "pre_condition": "none", "case_id": "Uint8Array_subarray_begin_end", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the subarray(begin, end) of Uint8Array"}], "purpose": "Verify the subarray(begin, end) of Uint8Array", "order": "360"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8Array_subarray_exist.html", "pre_condition": "none", "case_id": "Uint8Array_subarray_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Check if the subarray of Uint8Array exist"}], "purpose": "Check if the subarray of Uint8Array exist", "order": "361"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_buffer.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_buffer", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the buffer of Uint8ClampedArray"}], "purpose": "Verify the buffer of Uint8ClampedArray", "order": "362"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_buffer_exist.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_buffer_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "check if the buffer of Uint8ClampedArray exist"}], "purpose": "check if the buffer of Uint8ClampedArray exist", "order": "363"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_byteLength.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_byteLength", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the byteLength of Uint8ClampedArray"}], "purpose": "Verify the byteLength of Uint8ClampedArray", "order": "364"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_byteLength_exist.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_byteLength_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Check if the byteLength of Uint8ClampedArray exist"}], "purpose": "Check if the byteLength of Uint8ClampedArray exist", "order": "365"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_byteOffset.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_byteOffset", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the byteOffset of Uint8ClampedArray"}], "purpose": "Verify the byteOffset of Uint8ClampedArray", "order": "366"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_byteOffset_exist.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_byteOffset_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "check if the byteOffset of Uint8ClampedArray exist"}], "purpose": "check if the byteOffset of Uint8ClampedArray exist", "order": "367"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_BYTES_PER_ELEMENT_const_1.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_BYTES_PER_ELEMENT_const_1", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify the BYTES_PER-ELEMENT of Uint8ClampedArray is 1"}], "purpose": "Verify the BYTES_PER-ELEMENT of Uint8ClampedArray is 1", "order": "368"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_BYTES_PER_ELEMENT_exist.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_BYTES_PER_ELEMENT_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Check if the BYTES_PER_ELEMENT of Uint8ClampedArray exist"}], "purpose": "Check if the BYTES_PER_ELEMENT of Uint8ClampedArray exist", "order": "369"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_constructor_array.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_constructor_array", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify constructor(array) of Uint8ClampedArray"}], "purpose": "Verify constructor(array) of Uint8ClampedArray", "order": "370"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_constructor_ArrayBuffer.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_constructor_ArrayBuffer", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify constructor(arraybuffer) of Uint8ClampedArray"}], "purpose": "Verify constructor(arraybuffer) of Uint8ClampedArray", "order": "371"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_constructor_ArrayBuffer_byteOffSet.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_constructor_ArrayBuffer_byteOffSet", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify constructor(arraybuffer, byteOffset) of Uint8ClampedArray"}], "purpose": "Verify constructor(arraybuffer, byteOffset) of Uint8ClampedArray", "order": "372"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_constructor_ArrayBuffer_byteOffSet_length.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_constructor_ArrayBuffer_byteOffSet_length", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify constructor(buffer, byteOffset, length) of Uint8ClampedArray"}], "purpose": "Verify constructor(buffer, byteOffset, length) of Uint8ClampedArray", "order": "373"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_constructor_length.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_constructor_length", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify constructor(length) of Uint8ClampedArray"}], "purpose": "Verify constructor(length) of Uint8ClampedArray", "order": "374"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_constructor_TypedArray.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_constructor_TypedArray", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify constructor(typedarray) of Uint8ClampedArray"}], "purpose": "Verify constructor(typedarray) of Uint8ClampedArray", "order": "375"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_getter.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_getter", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify getter of Uint8ClampedArray"}], "purpose": "Verify getter of Uint8ClampedArray", "order": "376"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_length.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_length", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify length of Uint8ClampedArray"}], "purpose": "Verify length of Uint8ClampedArray", "order": "377"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_length_exist.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_length_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Check if the length of Uint8ClampedArray exist"}], "purpose": "Check if the length of Uint8ClampedArray exist", "order": "378"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_setter.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_setter", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify setter of Uint8ClampedArray"}], "purpose": "Verify setter of Uint8ClampedArray", "order": "379"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_set_array.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_set_array", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify set(array) of Uint8ClampedArray"}], "purpose": "Verify set(array) of Uint8ClampedArray", "order": "380"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_set_array_offset.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_set_array_offset", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify set(array, offset) of Uint8ClampedArray"}], "purpose": "Verify set(array, offset) of Uint8ClampedArray", "order": "381"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_set_exist.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_set_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "check if the set of Uint8ClampedArray exist"}], "purpose": "check if the set of Uint8ClampedArray exist", "order": "382"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_set_TypedArray.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_set_TypedArray", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify set(typedarray) of Uint8ClampedArray"}], "purpose": "Verify set(typedarray) of Uint8ClampedArray", "order": "383"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_set_TypedArray_offset.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_set_TypedArray_offset", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify set(typedarray, offset) of Uint8ClampedArray"}], "purpose": "Verify set(typedarray, offset) of Uint8ClampedArray", "order": "384"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_subarray_begin.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_subarray_begin", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify subarray(begin) of Uint8ClampedArray"}], "purpose": "Verify subarray(begin) of Uint8ClampedArray", "order": "385"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_subarray_begin_end.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_subarray_begin_end", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Verify subarray(begin, end) of Uint8ClampedArray"}], "purpose": "Verify subarray(begin, end) of Uint8ClampedArray", "order": "386"}, {"post_condition": "none", "onload_delay": "3", "test_script_entry": "/opt/tct-webapi-nonw3c-tests/TypedArrays/Uint8ClampedArray_subarray_exist.html", "pre_condition": "none", "case_id": "Uint8ClampedArray_subarray_exist", "steps": [{"expected": "Pass", "order": "1", "step_desc": "Check if the subarray of Uint8ClampedArray exist"}], "purpose": "Check if the subarray of Uint8ClampedArray exist", "order": "387"}], "type": "compliance", "exetype": "auto"}
\ No newline at end of file
diff --git a/src/ut/ut.cpp b/src/ut/ut.cpp
new file mode 100644 (file)
index 0000000..e581afe
--- /dev/null
@@ -0,0 +1,83 @@
+#include "httpserver.h"
+
+int main() {
+       HttpServer* httpserver = new HttpServer();
+
+       httpserver->parse_json_str("src/ut/test.json");
+
+       struct HttpRequest httprequest;
+
+       httprequest.path = "/init_test";
+       httpserver->processpost(1, &httprequest);
+
+       httpserver->g_test_suite = "api3nonw3c";
+
+       httprequest.path = "/check_server";
+       httpserver->processpost(1, &httprequest);
+
+       httprequest.path = "/check_server_status";
+       httpserver->processpost(1, &httprequest);
+
+       httprequest.path = "/shut_down_server";
+       httpserver->processpost(1, &httprequest);
+
+       httprequest.path = "/ask_next_step";
+       httpserver->processpost(1, &httprequest);
+
+       httprequest.path = "/init_session_id?session_id=1024";
+       httpserver->processpost(1, &httprequest);
+
+       httprequest.path = "/auto_test_task?session_id=1024";
+       httprequest.content = "session_id=1024";
+       httpserver->processpost(1, &httprequest);
+
+       httprequest.path = "/manual_cases";
+       httpserver->processpost(1, &httprequest);
+
+       httprequest.content = "purpose=ut-cas&result=N/A";
+       httprequest.path = "/commit_manual_result";
+       httpserver->processpost(1, &httprequest);
+
+       httprequest.path = "/check_execution_progress";
+       httpserver->processpost(1, &httprequest);
+
+       httprequest.path = "/generate_xml";
+       httpserver->processpost(1, &httprequest);
+
+       httprequest.content = "purpose=Verify setter of Uint16Array&result=N/A";
+       httprequest.path = "/commit_result";
+       httpserver->processpost(1, &httprequest);
+
+       httprequest.path = "/check_execution_progress";
+       httpserver->processpost(1, &httprequest);
+
+       httprequest.path = "/set_capability";
+       httprequest.content = "{\"name1\":true, \"name2\":45, \"name3\":\"678\"}";
+       httpserver->processpost(1, &httprequest);
+
+       httprequest.path = "/capability";
+       httprequest.content = "name=name1";
+       httpserver->processpost(1, &httprequest);
+
+       httprequest.path = "/capability?name=name2&value=45";
+       httprequest.content = "name=name2&value=45";
+       httpserver->processpost(1, &httprequest);
+
+       httprequest.path = "/capability?name=name3&value=678";
+       httprequest.content = "name=name3&value=678";
+       httpserver->processpost(1, &httprequest);
+
+       httprequest.path = "/capability?name=name4";
+       httprequest.content = "name=name4";
+       httpserver->processpost(1, &httprequest);
+
+       httprequest.path = "/set_capability";
+       httprequest.content = "{\"bluetooth\":true, \"nfc\":true, \"multiTouchCount\":true, \"inputKeyboard\":true, \"wifi\":true, \"wifiDirect\":true, \"openglesVersion1_1\":true, \"openglesVersion2_0\":true, \"fmRadio\":true, \"platformVersion\":true, \"webApiVersion\":true, \"nativeApiVersion\":true, \"platformName\":true, \"cameraFront\":true, \"cameraFrontFlash\":true, \"cameraBack\":true, \"cameraBackFlash\":true, \"location\":true, \"locationGps\":true, \"locationWps\":true, \"microphone\":true, \"usbHost\":true, \"usbAccessory\":true, \"screenOutputRca\":true, \"screenOutputHdmi\":true, \"platformCoreCpuArch\":true, \"platformCoreFpuArch\":true, \"sipVoip\":true, \"duid\":true, \"speechRecognition\":true, \"accelerometer\":true, \"barometer\":true, \"gyroscope\":true, \"magnetometer\":true, \"proximity\":true}";
+       httpserver->processpost(1, &httprequest);
+
+       httpserver->StartUp();
+
+       delete httpserver;
+
+       return 0;
+}