--- /dev/null
+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
+
--- /dev/null
+################################################################################
+# 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
+
+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
--- /dev/null
+#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);
+};
+
--- /dev/null
+#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;
+};
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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 ¤t, Location end,
+ unsigned int &unicode);
+ bool decodeUnicodeEscapeSequence(Token &token, Location ¤t,
+ 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 ¤tValue();
+ 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
--- /dev/null
+#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 ¤t);
+#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 ¤t);
+#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 ¤t);
+#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
--- /dev/null
+#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
--- /dev/null
+#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();
+};
--- /dev/null
+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
--- /dev/null
+
+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
--- /dev/null
+
+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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+// 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;
+}
--- /dev/null
+// 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 ¤t->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 = ¤t->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;
+}
--- /dev/null
+#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_ = ¤tValue();
+ }
+
+ 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 ¤t,
+ 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 ¤t,
+ 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
--- /dev/null
+#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
--- /dev/null
+// 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 ¤t )
+ : 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 ¤t )
+ : 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 ¤t )
+ : 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;
+}
--- /dev/null
+#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 *¤t) {
+ *--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
--- /dev/null
+Import( 'env buildLibrary' )\r
+\r
+buildLibrary( env, Split( """\r
+ json_reader.cpp \r
+ json_value.cpp \r
+ json_writer.cpp\r
+ """ ),\r
+ 'json' )\r
--- /dev/null
+#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;
+}
+
--- /dev/null
+#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
--- /dev/null
+
+[ 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:~$
--- /dev/null
+{"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
--- /dev/null
+#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;
+}